Identifying/Coding Multiple Days of Overlapping Price Action

Hi All,

I am curious if someone can point me in the right direction as to how to write something in AFL that would identify multiple days of overlapping price action.

An "Inside Day" for example, I assume could be written as the following:

InsideDay = Ref(H, -1) > H AND Ref(L, -1) < L;

But if I want to capture multiple days of overlapping price action, say over the last 5-10 days, and then classify that as "consolidation" and have identifiable extremes of that overlapping price action, any suggestions on how I should go about doing that? I am cautious to not just use HHV or LLV over the last 5-10 days, as that won't delineate between trending vs. consolidation.

Any guidance as to where to start on this would be hugely appreciated!

Inside bar clusters

2 Likes

Thank you @fxshrat , I appreciate you pointing me to the inside bar clusters. In a more simplistic example, which I plan to apply to inside bar clusters as I advance my abilities, is there a way to anchor the reference to the extreme of the inside bar rather than have a rolling lookback, as you will see in my code below.

The goal of this basic system is to identify an inside bar, see a breakdown out of that inside bar with a close below the extreme, followed by a recovery back inside that inside bar sequence the following day. The entry would be on the close of the "recovery day". Target is the high of the inside bar sequence, stop out would be a close back below the low of the inside bar sequence. (I plan to further this using intraday exits, but keeping it simple for now). As you can see in my code below, the target and the stop reference the high and low from 3 bars ago, which is accurate with regards to the entry day, but I imagine Amibroker will read this as a rolling price level, rather than anchored on the Inside Bar extremes as I am trying to achieve.

// InsideDayBreakdownBalanceRegain
SetTradeDelays(0,0,0,0);


// Entry Rules

InsideDay = Ref(H,-3) >= Ref(C,-2) AND Ref(L,-3) <= Ref(C,-2);
Breakdown = Ref(C,-1) < Ref(L,-3);
RecoverDayPercent = 30; // To ensure that there is still some return posibility to the opposing extreme of the InsideDay High
RecoveryDay = C > Ref(L,-3) AND C <= (((Ref(H,-3) - Ref(L,-3)) * (RecoveryDayPercent/100)) + Ref(L,-3));
EntryTrigger = InsideDay AND Breakdown AND RecoveryDay;

// Exit Rules

Target = H >= (Ref(H, -3) - 0.01); // Need to figure out how to anchor the target to the InsideBarHigh Ref(H,-3), rather than rolling high 3 bars ago...
StopOut = C < Ref(L, -3); // Need to figure out how to anchor the stop out level to the InsideBarLow Ref(L,-3), rather than rolling low 3 bars ago...

// Entry & Exit

Buy = EntryTrigger;
BuyPrice = Close;
Sell = Target OR StopOut;
SellPrice = Close;


In the screenshot below, here is an example with some liberties taken... Yes, this specific example would have had to use inside bar clusters, as there are more than two bars in the inside bar sequence, and the "recovery day" in this example did not quite close within the inside bar sequence lows (as seen by the pink line), but I am simply trying to illustrate the example.

InsideDayBreakdownBalanceRegain

Question is how I might anchor those price level extremes, rather than use the Ref(H, -3) for target and Ref(L, -3) for stop out. Thank you, any help is greatly appreciated!

I have used APPLYSTOP.
Can't you see it?!

Ahh yes I see it now! Using the "Amount1" & "Amount2" identifier and then using ApplyStop with amount of points. Thank you sir!!

@fxshrat I am curious if there is a way to reference prior inside bar clusters, without knowing the exact number of bars since that inside bar cluster...

Here is the underlying market action I am trying to identify/test. I would consider those inside bar clusters a way to codify "balance". Price often retests areas of balance and either "re-accepts" that area of balance, or "rejects" (Market Profile, Volume Profile concepts...). In the screenshot attached, you will see an inside bar cluster, which was broken to the upside. Price then revisited briefly, and then "rejected" and broke back to the upside.

ES - Balance Breakout retest continuation

Is there a way to reference those prior inside bar clusters, without knowing that it is x number of bars later? Maybe there must be a full bar or some percentage of a bar outside of the cluster, and then the first close back inside the cluster triggers consideration of a "rejection setup", within a 15 bar window since the initial breakout?

Please do yourself a favour and study the code.
You can call variables after Equity function call and create new signals.

See hh and ll variables.
Also see flags Sell == 2 and Sell == 3 there.

dn_break = Sell==2;
up_break = Sell==3;

With those markers you can then code re-break (if that's what you look for).

Also study functions
ValueWhen, Flip, SumSince, ExRem, LowestSince.

34

3 Likes

Thank you @fxshrat , greatly appreciate you pointing me in the right direction. :pray: :pray:

My apologies @fxshrat but I am very confused and hoping you can further nudge me in the right direction...

I have studied the original code for the inside bar clusters and understand now that the code is a trading system that buys the close of any inside bar and then sells on either a break of the high or low of the inside bar cluster extreme. Am I correct in this? From the original thread, I was under the impression that the code was to identify the inside bar clusters and take a position on the breakout of either extreme?

Is that code still the correct path if I am attempting to identify those inside bar cluster extremes without taking a position until price revisits/interacts with the inside bar cluster some X bars later?

In my attempt to mark those inside bar cluster extremes using your notes above, would I do something like this?

// Attempting to create a reference point for price action upon a revisit...

dn_break = Sell==2;
up_break = Sell==3;

UpperEdge = ValueWhen(up_break, HH, 1);
LowerEdge = ValueWhen(dn_break, LL, 1);

dn_break = Flip(dn_break, up_break);
up_break = Flip(dn_break, up_break);

And then use C >= LowerEdge; for example if I saw price break to the downside and wanted to see price close back up within the inside bar cluster?

Bottom line, I am trying to wrap my head around how to mark those extremes and then reference them as price revisits. My apologies, I am sure I am WAY off. Thank you for any help and/or guidance :pray: :pray:

1 Like

It is both. But its purpose is/was not trading system.
Main purpose has been to create array version for identifying inside bar clusters and getting start and end points of clusters. Trading system is of secondary importance.

Yes.

So again you can create new Buy,Sell,Short,Cover signals after Equity call and they will override previous ones.

Your code lines are "a bit" off the track.
Use Flip in ValueWhen and with Buy and break.

2 Likes

@fxshrat I have been working to understand this code and have expanded on it through my own trial and error. Thank you for your initial help :pray:

I am running into an issue with stops not triggering correctly, and am hoping you might be able to point me in the right direction.

I will include the code here but the basic idea is building off of your inside bar clusters, taking positions in the direction of the trend on a break of the inside bar cluster. A points based stop loss is set to exceed the prior bar low as of the entry bar and a target stop is also points based, but calculates a percentage of the inside bar cluster size from high to low.

/// InsideBarClustersLongShort - CL 

SetBacktestMode(backtestRegular);
SetOption("ActivateStopsImmediately", 0);
SetOption("AllowSameBarExit", True);
SetPositionSize(1, spsShares);
SetTradeDelays(0, 0, 0, 0);

TickSize = 0.01;
Slippage = 0.05;

InsideBarLong = High <= Ref(High, -1) AND Low >= Ref(Low, -1);

BuyPrice = Close;
Buy = InsideBarLong;
Sell = 0;

LongAmount1 = Ref(H,-1) - BuyPrice;
LongAmount2 = BuyPrice - Ref(L,-1);
ApplyStop(stopTypeProfit, stopModePoint, LongAmount1 + TickSize, 1);
ApplyStop(stopTypeLoss, stopModePoint, LongAmount2 + TickSize, 1);

eq = Equity(1,0); 

intradeLong = Flip(Buy,Sell);
HHLong = IIf(intradeLong OR Sell>0, ValueWhen(Buy, Ref(H,-1)), Null);
LLLong = IIf(intradeLong OR Sell>0, ValueWhen(Buy, Ref(L,-1)), Null);

// Check Instrument Trend
IndexLongMAPeriods = 350; //Optimize("TrendMA", 350, 10, 400, 10);
IndexLongMA = Ref(MA(C, IndexLongMAPeriods), -1);
IndexTrendUp = Ref(C, -1) > IndexLongMA;

// Open in Balance
OpenInBalanceLong = O < HHLong;

// Cluster Percent
LongClusterSize = (HHLong - LLLong)/Ref(C,-1);
LongClusterPercentThreshold = 8; //Optimize("LongClusterPercent", 10, 5, 15, .5);
LongClusterSizeOkay = LongClusterSize <= (LongClusterPercentThreshold/100);

//Breakout
dn_breakLong = Sell==2; 
up_breakLong = Sell==3; 

LongEntryTrigger = IndexTrendUp AND OpenInBalanceLong AND LongClusterSizeOkay AND up_breakLong;

Buy = LongEntryTrigger;
BuyPrice = HHLong + Slippage;
Sell = 0;

LongTargetPercent = 90; //Optimize("LongTargetPercent", 90, 50, 110, 5);
LongTarget = (HHLong - LLLong) * (LongTargetPercent/100);
LongStopLevel = Ref(L, -1) - Slippage;
LongStopPoints = BuyPrice - LongStopLevel;
ApplyStop(stopTypeProfit, stopModePoint, LongTarget, 1);
ApplyStop(stopTypeLoss, stopModePoint, LongStopPoints, 1);

// SHORT RULES

InsideBarShort = High <= Ref(High, -1) AND Low >= Ref(Low, -1);

ShortPrice = Close;
Short = InsideBarShort;
Cover = 0;

ShortAmount1 = Ref(H,-1)- ShortPrice;
ShortAmount2 = ShortPrice - Ref(L,-1);
ApplyStop(stopTypeProfit, stopModePoint, ShortAmount2 + TickSize, 1);
ApplyStop(stopTypeLoss, stopModePoint, ShortAmount1 + TickSize, 1);

eq = Equity(1,0);

intradeShort = Flip(Short, Cover);
HHShort = IIf(intradeShort OR Cover > 0, ValueWhen(Short, Ref(H,-1)), Null); 
LLShort = IIf(intradeShort OR Cover > 0, ValueWhen(Short, Ref(L,-1)), Null); 

// Short Index Trend
IndexShortMAPeriods = 20; //Optimize("ShortMA", 20, 10, 400, 10);
IndexShortMA = Ref(MA(C, IndexShortMAPeriods), -1);
IndexTrendDown = Ref(C, -1) < IndexShortMA;

// Open in Balance
OpenInBalanceShort = O > LLShort;

// Short Cluster Percent
ShortClusterSize = (HHShort - LLShort)/Ref(C,-1);
ShortClusterPercentThreshold = 8; //Optimize("ShortClusterPercent", 10, 5, 15, .5);
ShortClusterSizeOkay = ShortClusterSize <= (ShortClusterPercentThreshold/100);

//Breakout
dn_breakShort = Cover==3; 
up_breakShort = Cover==2; 

ShortEntryTrigger = IndexTrendDown AND OpenInBalanceShort AND ShortClusterSizeOkay AND dn_breakShort;

Short = ShortEntryTrigger;
ShortPrice = LLShort - Slippage;
Cover = 0;

ShortTargetPercent = 90; //Optimize("ShortTargetPercent", 90, 50, 110, 5);
ShortTarget = (HHShort - LLShort) * (ShortTargetPercent/100);
ShortStopLevel = Ref(H, -1) + Slippage;
ShortStopPoints = ShortStopLevel - ShortPrice;
ApplyStop(stopTypeProfit, stopModePoint, ShortTarget, 1);
ApplyStop(stopTypeLoss, stopModePoint, ShortStopPoints, 1);

LongSetup = InsideBarLong AND IndexTrendUP;
ShortSetup = InsideBarShort AND IndexTrendDown;

Filter = LongSetup OR ShortSetup;

AddColumn(Iif(Ref(C, -1) > Ref(IndexLongMA, -1), 1, 0), "LONG", 1, colorGreen);
AddColumn(IIf(Ref(C, -1) < Ref(IndexShortMA, -1), 1, 0), "SHORT", 1, colorRed);
IIf(LongSetup, AddColumn(HHLong + TickSize, "Long - Buy Stop", 1.2, colorGreen), Null);
IIf(LongSetup, AddColumn(HHLong + TickSize + Slippage, "Long - Buy Limit", 1.2, colorGreen), Null);
IIf(LongSetup, AddColumn(HHLong + LongTarget, "Long - Target", 1.2, colorGreen), Null);
IIf(LongSetup, AddColumn(HHLong - LongStopPoints + (2 * Slippage) - TickSize, "Long - Stop (DAILY ADJUSTMENT)", 1.2, colorGreen), Null);
IIf(ShortSetup, AddColumn(LLShort - TickSize, "Short - Sell Stop", 1.2, colorRed), Null);
IIf(ShortSetup, AddColumn(LLShort - TickSize - Slippage, "Short - Sell Limit", 1.2, colorRed), Null);
IIf(ShortSetup, AddColumn(LLShort - ShortTarget, "Short - Target", 1.2, colorRed), Null);
IIf(ShortSetup, AddColumn(LLShort + ShortStopPoints - (2 * Slippage) + TickSize, "Short - Stop (DAILY ADJUSTMENT)", 1.2, colorRed), Null);

The code seems to work for me on a majority of trades but I have isolated one example that is not making sense to me.

Trade List - CL
Trade Arrows - CL

Please see the trade on 6/21/2021. The entry price is correct, but the stop is triggered as a "(max loss)", despite the trade being profitable, and nowhere near the stop loss point. The trade is then exited on the following day's open...? The market continued higher in the days following and would have successfully reached the intended target. I am confused as a number of bars later, 7/28/2021, another long is entered and the code works correctly.

On a side note, I have also seen that if the entry bar low exceeds the prior bar low, it will trigger a stop which is filled the following day's open as a max loss, but that should not be the case here as the low of the entry bar did not exceed the prior bar low. I have unchecked the box for "allow same bar exit / entry signal" in backtester settings and this does not seem to resolve the issue.

Any help would be greatly appreciated.

This topic was automatically closed 100 days after the last reply. New replies are no longer allowed.