Been very inspired by @rocketPower's scripts. In particular the VCP screener and High Tight Flag script.
One thing about both of these scripts is they seem to be almost too particular and give few results when scanning. I attempted to make a more generic flag script and on a shorter term timeframe in order to catch any bull flag, including high tight ones. The benefit of this is it will also catch cup and handles or VCPs as well (but it is only focusing on the most recent contraction vs. the one before it and ignores volume).
When adding this filter to others I was using, it seems to help my performance by only taking breakouts that meet the flag criteria the day before, so figured I'd share this with the group. Open to comments/criticism.
// Chart
SetChartOptions(0,chartShowArrows|chartShowDates);
_N(Title = StrFormat("{{NAME}} - " + FullName() + " | {{INTERVAL}} {{DATE}}: Open %g, Hi %g, Lo %g, Close %g (%.1f%%) {{VALUES}}", O, H, L, C, SelectedValue( ROC( C, 1 ) ) ));
Plot( C, "Close", ParamColor("Color", colorDefault ), styleNoTitle | ParamStyle("Style") | GetPriceStyle() );
// ==========================================================================================
// === FLAG DETECTION === https://forum.amibroker.com/t/high-tight-flag-power-play-detection/21895
// ==========================================================================================
flagLookback = 13; // Number of bars to look back for top of flag
PoleHigh = HHV(H, flagLookback); // Highest high within the lookback period
PHBar = HHVBars(H, flagLookback); // How many bars back the pivot high bar occurred
FlagLow = LLV(L, PHBar); // Flag Low is the lowest price since PoleHigh
FLBar = LLVBars(L, PHBar); // How many bars back is the low point of the flag
flagPoleLookback = 21; // Number of bars to look back from the pole top to find the base of the pole
PoleLow = Ref(LLV(L, flagPoleLookback), -PHBar-1); // Value of the base of the pole
// Flag characteristics
PoleLength = Nz((PoleHigh - PoleLow)/PoleLow); // Percentage move that forms the flag pole
FlagDepth = Nz((PoleHigh - FlagLow)/PoleHigh); // Percentage retracement off the highs
FlagRatio = Nz(FlagDepth/PoleLength); // Flag-to-Pole ratio
// Flag Requirements
Flag =
PoleLength > 0.10 AND // Must have had at least a 10% rise
FlagDepth < 0.25 AND // Flag must not have come down more than 25% off the flag pole top
FlagRatio < 0.5 AND // Flag cannot have retraced more than 50% of the initial move
PHBar > 1; // Flag must be more than two candles from high (will trigger at third)
PlotShapes(Flag*shapeCircle, colorBlue, 0, Low);// Plot dots indicating consolidation meets requirements
// === PLOT HORIZONTAL LINES SHOWING CURRENT FLAG MEASUREMENT BOUNDARIES === https://forum.amibroker.com/t/swing-high-swing-low-afl-code/3361/19
// Turning these lines on can help visualize where the flags are
function ResLevels( bars, color )
{
bi = BarIndex();
lvbi = LastValue( bi );
// return HHV value only for bars starting from the bar where HHV level was established
level = IIf( bi >= lvbi - LastValue( HHVBars( High, bars ) ), LastValue( HHV( High, bars ) ), Null );
// plot levels
Plot( level, "lev", color, styleLine | styleThick); // NO PLOT!
}
function SupLevels( bars, color )
{
bi = BarIndex();
lvbi = LastValue( bi );
// return LLV value only for bars starting from the bar where HHV level was established
level = IIf( bi >= lvbi - LastValue( LLVBars( Low, bars ) ), LastValue( LLV( Low, bars ) ), Null );
// plot levels
Plot( level, "lev", color, styleLine | styleThick); // NO PLOT!
}
// Unhide these to show the lines on the chart
//ResLevels( FlagLookback, colorBrightGreen);
//SupLevels( PHBar, colorViolet);
//SupLevels( PHBar + flagPoleLookback, colorRed);
// === FILTERING ===
Filter = Flag;