UnFiltered Trade Flag - how to

I have tried very diligently to find the answer to my question across the forums and tried:
ExRem(),
Filp(),
if( Nz( StaticVarGet("InitializationDone") ) == 0 )
{
StaticVarSet("InitializationDone", 1);
InUnfilteredTrade = False;}

But to date I have not been able to get Ref(InUnfilteredTrade, -1) to == the value from the previous bar. I have not been susessful with Flip() nor ExRem() becuase the second array is not defined only after array1 is true and is not valid if array1 gets a second buy signal because BarsSince() and Hold() stop being accurate on the second signal. Hold() didn't work because the current condition for closing are EITHER # of bars pass OR TimeNum() == ExitTime

I'm using a form of optimization that completely eliminates trades based on custom column values. But the whole trade, for the whole duration it would have had needs to be a No Entry Window otherwise I just get a delayed entry.

Here's the code in it's current version:

// eliminate the ability to make a "late trade" when trying to filter out(completely skip) trades by creating a No Buy Window after the original unfiltered Trade signal is triggered.
InUnfilteredTrade = False; // Initialize the flag variable for the first bar (this will also fill 0/False in every bar unless we change it)

// check if unfiltered Trades are entered and update the flag.
FlagPlotDistance = SelectedValue(Low) * .99; // chart values 1% below the selected bar to avoid chart compression (this may need to be changed based on security type)
Plot(Ref(InUnfilteredTrade, -1)+FlagPlotDistance+20, "InUnfilteredTrade", IIf(InUnfilteredTrade, colorGold, colorDarkOliveGreen), styleDots);

InUnfilteredTrade = IIf(buyTriggerUnfiltered
, True
, Ref(InUnfilteredTrade, -1) // trying to refer to the previous value but it's always reset to FALSE since the end of the code. I have charted it before and after the code and even if true at the end, it's false on the next bar, (or set to false by the variable initialization)
);

BarsSinceUnfilteredEntry = iif(InUnfilteredTrade, BarsSince(InUnfilteredTrade AND NOT Ref(InUnfilteredTrade,-1)), -1); // InUnfilteredTrade has not been calculated yet for current bar, using previous bars' info
UnFilteredEntryPrice = IIf(BarsSinceUnfilteredEntry == 0, Max(Open, brkOutPrice), Null); // In previous code brkOutPrice is calculated based on previous bar already, no need to use Ref(xxx, -1).
// This entry price is for BuyStop at Market calculation Open if there is a gap up, brkOutPrice if High (of current candle) > brkOutPrice
UnFilteredPctStopPrice = IIf(BarsSinceUnfilteredEntry == 0 AND StopPercent > 0, UnFilteredEntryPrice * (1 - StopPercent), Null);
UnFilteredStopDollarPrice = IIf(BarsSinceUnfilteredEntry == 0 AND StopDollar > 0, UnFilteredEntryPrice - StopDollar, Null);
// Add other Stop and/or Profit Target calculations here in the same manner

// check if an unfiltered Trade ended and update the flag.
InUnfilteredTrade = iif(InUnfilteredTrade == True // This logic prevent an entry and immediate exit before other logic to
AND (ExitTime // Stop for End of day, End of trading period (ex. TimeNum() == 160000 for RTH), or other manually set end time
OR (BarsSinceEntry > 0 and BarsSinceUnfilteredEntry >= BarsSinceEntry) // For # of Bars Stop
OR (StopPercent > 0 AND Low < UnFilteredPctStopPrice) // For % stop trigger
OR (StopDollar > 0 AND Low < UnFilteredStopDollarPrice) // For absolute dollar stop trigger
// add other Stop loss or Profit Target calculations here in the same manner
), False, InUnfilteredTrade)
; // in AFL there are no indentation restrictions other than for your own visual useful, the end of a line it a ";". It is in its own line to easily add more conditions

// Post Filters from optimizer
PostFilter =
Ref(ImpVolRank(15 ), -1) < .4118
// add other filters here
;

buyTrigger = IIf(InUnfilteredTrade AND PostFilter, True, False); // tells backtester to buy on this candle
stopTrigger = Iif(NOT InUnfilteredTrade AND Ref(InUnfilteredTrade, -1), True, False); // tells backtester to execute a stop ApplyStop works on backtest trades only and we have manually calculated
// both live and unfiltered stops. This is to plot vs. AmiBroker arrows to make sure code is working as expected.

FlagPlotDistance = SelectedValue(Low) * .99; // chart values 1% below the selected bar to avoid chart compression (this may need to be changed based on security type)
Plot( C, "Price", colorDefault, styleCandle );
Plot( FlagPlotDistance-5, "FlagPlotDistance", colorDefault, styleDashed );
Plot(InUnfilteredTrade+FlagPlotDistance, "InUnfilteredTrade", IIf(InUnfilteredTrade, colorGold, colorDarkOliveGreen), styleDots);
Plot(BarsSinceUnfilteredEntry+FlagPlotDistance-5, "BarsSinceUnfilteredEntry", colorLightYellow , styleDots);
Plot(UnFilteredEntryPrice, "UnFilteredEntryPrice", IIf(InUnfilteredTrade, colorBrightGreen, colorDarkOliveGreen), styleDots);
Plot(UnFilteredPctStopPrice, "UnFilteredPctStopPrice", IIf(InUnfilteredTrade>0, colorLightOrange, colorDarkOliveGreen), styleDots);
Plot(UnFilteredStopDollarPrice, "UnFilteredStopDollarPrice", IIf(UnFilteredStopDollarPrice, colorLightYellow, colorDarkYellow), styleDots);
Plot(PostFilter+FlagPlotDistance-1, "PostFilter", IIf(PostFilter, colorLightBlue, colorTeal), styleDots);
Plot(buyTriggerUnfiltered+FlagPlotDistance+10, "buyTriggerUnfiltered", IIf(buyTriggerUnfiltered, colorLightBlue, colorTeal), styleDots);

When posting the formula, please make sure that you use Code Tags (using </> code button) as explained here: How to use this site.

Using code button

Code tags are required so formulas can be properly displayed and copied without errors.

1 Like

I've read your post several times and looked at your hard-to-read code as well, and it's still not clear to me what exactly you're trying to accomplish. Something to do with preventing late entries? I suggest you review this post: How to ask a good question, then repost your question along with a clear statement of what your goal is.

Very generally speaking, you should be able to do something like this:

isUnfilteredEntry = // your logic here
isUnfilteredExit = // your logic here. 
inUnfilteredTrade = Flip(isUnfilteredEntry, isUnfilteredExit);

Also make sure that you fully understand how AmiBroker array processing works. Use an Exploration or the built-in debugger to see what's going on with your variables.

1 Like

Thanks to both @Tomasz and @mradtke for your help! I will properly insert the code sample below after asking the question a little more clearly:

  1. My code has several Plot lines in it because I was trying to figure out what happens to arrays.
  2. My conclusion is: Arrays are rewritten on each bar in the order of the code. So several modifications on Bar #99 may happen during the code run on Bar #99, but on Bar #100, Ref(Array1, -1) does NOT return the final value of Array1 on Bar #99, but rather the modifications that happened to it so far on Bar #100.
  3. @mradtke suggested:

isUnfilteredEntry = // your logic here
isUnfilteredExit = // your logic here.
inUnfilteredTrade = Flip(isUnfilteredEntry, isUnfilteredExit);

But in my particular code I need to calculate isUnfilteredExit AFTER the the Flip of isUnfilteredEntry.

isUnfilteredEntry = // your logic here
inUnfilteredTrade = Flip(isUnfilteredEntry, isUnfilteredExit);
isUnfilteredExit = // your logic here. After having an isUnfilteredEntry that can't be moved a few bars later.

I want to duplicate the full track of a trade entered with a Buy and exited with an ApplyStop(), without ACTUALLY triggering a Buy. A lot of extra signals are ignored after a Buy in the backtester until one of the ApplyStops trigger. A Buy is then able to trigger again.

Here is the important part of my code without the debuggin plots:

 // eliminate the ability to make a "late trade" when trying to filter out(completely skip) trades by creating a No Buy Window after the original unfiltered Trade signal is triggered.
StartUnfilteredTrade = ExRem(buyTriggerUnfiltered,  BarsSince(NOT Ref(buyTriggerUnfiltered, -1)) > BarsSinceEntry OR ExitTime);													// Initialize the flag variable for the first bar (this will also fill 0/False in every bar unless we change it)

InUnfilteredTrade = Flip(StartUnfilteredTrade,  BarsSince(StartUnfilteredTrade) >= BarsSinceEntry OR ExitTime);
BarsSinceUnfilteredEntry = iif(InUnfilteredTrade, BarsSince(NOT Ref(InUnfilteredTrade,-1)), -1);  // InUnfilteredTrade has not been calculated yet for current bar, using previous bars' info
UnFilteredEntryPrice = IIf(BarsSinceUnfilteredEntry == 0,  Max(Open, brkOutPrice), Null);  // In previous code brkOutPrice is calculated based on previous bar already, no need to use Ref(xxx, -1).  
																								// This entry price is for BuyStop at Market calculation Open if there is a gap up, brkOutPrice if High (of current candle)  > brkOutPrice
UnFilteredPctStopPrice = IIf(BarsSinceUnfilteredEntry == 0  AND StopPercent > 0, UnFilteredEntryPrice * (1 - StopPercent), Null);
UnFilteredStopDollarPrice = IIf(BarsSinceUnfilteredEntry == 0  AND StopDollar > 0, UnFilteredEntryPrice - StopDollar, Null);
// Add other Stop and/or Profit Target calculations here in the same manner

// check if an unfiltered Trade ended and update the flag.
 InUnfilteredTrade = iif(InUnfilteredTrade == True			// This logic prevent an entry and immediate exit before other logic to 
		AND (ExitTime																			// Stop for End of day, End of trading period (ex. TimeNum() == 160000 for RTH), or other manually set end time
			OR (BarsSinceEntry >= 0 and BarsSinceUnfilteredEntry >= BarsSinceEntry)   // For # of Bars Stop
			OR (StopPercent > 0 AND Low < UnFilteredPctStopPrice)								// For % stop trigger
			OR (StopDollar > 0 AND Low < UnFilteredStopDollarPrice)								// For absolute dollar stop trigger
			// add other Stop loss or Profit Target calculations here in the same manner
			), False, InUnfilteredTrade)
		;  

// Post Filters from optimizer the PostFilter on the trigger bar should stop any entry during the entire duration of an unFilteredTrade.
PostFilter = 
	Ref(ImpVolRank(15 ), -1) < .4118
	// add other filters here
	;

buyTrigger = IIf(InUnfilteredTrade AND PostFilter, True,  False);  // tells backtester to buy on this candle

																											


My code ALMOST works. The issue is the variable StartUnfilteredTrade resets if there is a second occurrence of NOT Ref(buyTriggerUnfiltered, -1)) > BarsSinceEntry during the trade and makes the "No Buying Window" longer than it should be.

So to repeat the main goal:
I want to have an array that duplicates the behavior of a backtester Buy preventing a second Buy until any of several ApplyStops execute, but without creating an actual backtester Buy in the Backtest results.

Your conclusion is incorrect. Your AFL does not run once per bar, it runs once per symbol, and all bars in an array are calculated in parallel (at least conceptually). You really need to fully master this concept before AFL will make sense.

If you want to replicate the backtester's functionality, take a look at the Equity() function, which will basically run a single-symbol backtest.

2 Likes

@mradtke
Hey Matt, thanks for point out my misunderstanding. It's always good to have more precise knowledge.

The point remains, though. The first time Array1 is calculated in the order of the code is immutable. If Array1 is modified later in the code with an updated value, I can't refer to that final value higher up in the code on the following bar, or at least I don't know how to. If I call it Array2, I can't refer to Ref(Array2, -1) either until Array2 is mentioned in the code and when it's mentioned, it's creating its first definition of itself. So whether I redefine Array1 lower in the code or create Array2, I get the same situation. My issue is pretty easy in other languages but that's probably why they are slower, too.

I believe the term I'm looking for is recursive - where an array refers to its previous value. I can't see the final value of array 1 from Bar #99 on Bar #100 to use the final Bar #99 value in a calculation because as you explained to me Bar #100 higher version of the array was already fully calculated by the time the code reaches the final value of modified Array1.

I've read and reread https://www.amibroker.com/guide/h_understandafl.html. I've thought about using the AMA() function which does refer to its previous value, but I think I would run into the same issue, because it's referring to the previous value on the same command line of Bar #100, not the final value on Bar #99.

Perhaps what I want to do can only be done in a loop, which I was really hoping to avoid. I was hoping I might get you, @Tomasz or Fxshrat (whose names I've seen over and over) or another experienced AFL coder to provide a clue to a more efficient solution. Perhaps a command or data structure I don't know about or don't know how to use correctly yet.
I've tried ExRem(), Flip(), Hold(), ValueWhen() and can't quite get my code to replicate my goal:

"Don't allow trade entries after an entry signal until that entry signal would exit." I'm trying to re-create the Don't Buy Again window ability of the backtester WITHOUT actually taking a backtester trade. Based on my AFL limited understanding, I think Foriegn("~~~EQUITY", "C") , Equity() and EquityArray() all rely on the code actually taking the trade in the backtest engine. If my PostFilter says don't trade, i want to skip the whole trade's hypothetic duration and not just skip the entry bar and enter a few bars later if the PostFilter becomes true.

@mradtke if I could do this:

InUnfilteredTrade = Flip(buyTriggerUnfiltered,  BarsSince(NOT InUnfilteredTrade) > BarsSinceEntry OR ExitTime or SomeOtherStopCalculation);

THEN my code would do what I want it to. The problem is I can't refer to the array on its first mention. But I've TRIED initializing the first bar only to 0 only so I could refer to the previous bar, and it didn't work:

if( Nz( StaticVarGet("InitializationDone") ) == 0 )
{
StaticVarSet("InitializationDone", 1);
InUnfilteredTrade = False;}


Maybe I'll think some more about AMA() before jumping to looping.

My thought is to flip the AMA between positive and negative using an iif(StopOrNewEntryCondition, -1, 1) as the factor

First, there are certain problems that can only be solved with loops. It's always a good idea to look for a non-looping solution first, but there's no shane in using a loop when it's necessary.

Second, I think the Equity() function will do exactly what you want. This is not the same as the Backtester Equity or EquityArray, which are only available during Phase 2 of a backtest. I imagine a flow similar to this:

Buy = // unfiltered entry logic
Sell = // unfiltered exit logic
ApplyStop() // As needed by your strategy
Equity(1);
InUnfilteredTrade = Flip(Buy, Sell);
Buy = // new Buy rules that include the isUnfilteredTrade and PostFilter logic