Do not disqualify levels on the next occurrence

I am trying to build a series of gap levels. Where one gap cannot be disqualified unless it is either filled, or X bars has passed since inception. I need the gap to continue until one of these two conditions has been met, not get "reset" once another has formed. So I have a feeling I will have to build multiple arrays like the following in order to get multiples going at once. But my first challenge is how to not disqualify the currently working gap levels when the next occurrence of one has happened.

For instance, in the following chart, I am drawing circles on the gap window and fill lines, but I need these lines to continue (as I have hand drawn the dark blue lines), until the gap is disqualified per above two rules.

image

How can I alter the following code to do this?

GapBullishPctReq = 1;
GapBullishNumBars = 100;

GapBullishSetup = Open - Ref(Close, -1) > Open * GapBullishPctReq * .01;
GapBullishBarCnt = BarsSince(GapBullishSetup);

printf( " GapBullishBarCnt: " + NumToStr(  GapBullishBarCnt ) + "\n" ); 

GapBullishWindow = ValueWhen(GapBullishSetup, Open);
GapBullishFill = ValueWhen(GapBullishSetup, Ref(Close, -1));

GapBullishCond = Ref(Low,0) > GapBullishFill OR Ref(Low,-1) > GapBullishFill;// AND GapBullishBarCnt < GapBullishNumBars;

printf( " GapBullishCond: " + NumToStr(  GapBullishCond ) + "\n" ); 

PlotShapes(IIf(GapBullishCond, shapeSmallCircle, shapeNone),colorAqua,  0, GapBullishFill, Offset=0); 
PlotShapes(IIf(GapBullishCond, shapeHollowSmallCircle, shapeNone),colorAqua,  0, GapBullishWindow, Offset=0);

@vjsworld a couple of questions. I am not a price pattern trader so perhaps I am mistaken but ... you are aware that you are defining "gap" as something non-traditional? i.e. a Gap up traditionally meaning today's Low is greater than yesterday's High. Intentional on your part correct?

// my understanding of traditional "Gaps"
aGapUp = ( L > Ref(H, -1) ); // Identify GapUp bars
aGapDn = ( H < Ref(L, -1) ); // Identify GapDown bars

Secondly, I am not sure why this line is coded the way it is,

GapBullishCond = Ref(Low,0) > GapBullishFill OR Ref(Low,-1) > GapBullishFill;// AND GapBullishBarCnt < GapBullishNumBars;

Uh,

Ref(Low, 0) = Low; // today's Low

And lastly, which gap (if any exist) do you want to activate after your initial gap is nullified. The most recent or if multiple gaps exist do you want the gap immediately following the nullification of your 1st one?

(not saying I have a solution but need clarification).

1.) Yes, I am aware of the definition, but this is the way I need this to work.
2.) That was an accident. I was experimenting with the # of bars disqualifier and wanted to just temp turn it off, and forgot to uncomment that before posting.
3.) Yes, I know Ref(Low,0) = Low. I was experimenting with lookbacks lining it up and just left the Ref.

And lastly:
Ultimately, I am not trying to activate one at a time. I want to be able to reference levels that have not been disqualified in other parts of the strategy. So, there might be many "active" gap levels that I want to key off of later. Sometimes there will be just one, sometimes none. They are all in-play if not disqualified.

For what it's worth, in Tradestation I did this using a vector of levels.

in my opinion you first define the gaps and then handle them each individually.

here is a way:

// http://forum.amibroker.com/t/do-not-disqualify-levels-on-the-next-occurrence/5287

GapBullishPctReq = Param( "Bullish Gap Percentage", 4, 0.1, 20, 0.1 );
GapBullishNumBars = Param( "Bullish Bars Since Inception", 300, 5, 1000, 1 );

GfxSetZOrder( -5 );
GfxSetCoordsMode( 1 );

bi = BarIndex();
fvb = FirstVisibleValue( bi );
lvb = LastVisibleValue( bi );

Buy = Sell = Short = Cover = 0;
BuyPrice = SellPrice = ShortPrice = CoverPrice = 0;

GapBullishSetup = Open - Ref( Close, -1 ) > Open * GapBullishPctReq * .01;
GapBullishBarCnt = BarsSince( GapBullishSetup );
GapBullishSetupJumpto = ValueWhen( GapBullishSetup, bi, 1 );

SetChartOptions( 0, chartShowDates );
Plot( C, "Close", colorViolet , styleCandle, Null, Null, 0, 0, 1 );

GfxSelectPen( ColorRGB( 0, 80, 0 ), 2, 0 );
GfxSelectSolidBrush( ColorRGB( 0, 30, 0 ) );

for( i = lvb; i > fvb; i-- )
{
    if( GapBullishSetup[i] )
    {
        // initial coordinated
        x0top = i - 1;
        x1top = Min( i + GapBullishNumBars, BarCount - 1 );
        y0top = O[i];
        y1top = O[i];

        x0bot = i - 1;
        x1bot = Min( i + GapBullishNumBars, BarCount - 1 );
        y0bot = C[i - 1];
        y1bot = C[i - 1];

        gaptop = LineArray( x0top, y0top, x1top, y1top );
        gapbot = LineArray( x0bot, y0bot, x1bot, y1bot );

        // condition when filled
        fillCondition = IIf( !IsEmpty( gapbot ), Cross( gapbot, L ) OR L < gapbot, 0 );
        fillCondition = fillCondition && SumSince( i == bi, fillCondition ) == 1;
        lx = LastValue( ValueWhen( fillCondition, bi ) );
        lidx = lx;

        if( lx == 0 ) lx = x1bot;

        // adjusted coordinates for fill condition
        x0top = i - 1;
        x1top = lx;
        y0top = O[i];
        y1top = O[i];

        x0bot = i - 1;
        x1bot = lx;
        y0bot = C[i - 1];
        y1bot = C[i - 1];

        gaptop = LineArray( x0top, y0top, x1top, y1top );
        gapbot = LineArray( x0bot, y0bot, x1bot, y1bot );

        GfxRectangle( x0bot, y0bot, x1top, y1top );

        //Plot( gaptop, "", ColorRGB( 255, 155, 0 ), styleLine | styleNoRescale | styleNoLabel, Null, Null, 0, 1, 2 );
        //Plot( gapbot, "", ColorRGB( 0, 155, 255 ), styleLine | styleNoRescale | styleNoLabel, Null, Null, 0, 1, 2 );

        if( lidx != 0 )
        {
            Buy[lidx] = 1;
            BuyPrice[lidx] = C[lidx];
        }
    }

    i = GapBullishSetupJumpto[i - 1] + 1;
}

PlotShapes( IIf( Buy, shapeUpArrow, shapeNone ), colorGreen, 0, L, -15 );
PlotShapes( IIf( Buy, shapeSmallCircle, shapeNone ), colorWhite, 0, BuyPrice, 0 );
3 Likes

Very good Edward! This looks excellent!

thanks. I added a little bit to it. You can now set both the minimum and maximum length of the pattern. Also I use polygon so that overlapping patterns are better visible

// http://forum.amibroker.com/t/do-not-disqualify-levels-on-the-next-occurrence/5287

GapBullishPctReq = Param( "Bullish Gap Percentage", 4, 0.1, 20, 0.1 );
GapBullishMinBars = Param( "Bullish Minimum Bars Since Inception", 2, 0, 100, 1 );
GapBullishMaxBars = Param( "Bullish Maximim Bars Since Inception", 300, 5, 1000, 1 );
fillPatternWithColor = ParamToggle( "Fill Zone with Color", "Off|On", 0 );

GfxSetZOrder( -5 );
GfxSetCoordsMode( 1 );

bi = BarIndex();
fvb = FirstVisibleValue( bi );
lvb = LastVisibleValue( bi );

Buy = Sell = Short = Cover = 0;
BuyPrice = SellPrice = ShortPrice = CoverPrice = 0;

GapBullishSetup = Open - Ref( Close, -1 ) > Open * GapBullishPctReq * .01;
GapBullishBarCnt = BarsSince( GapBullishSetup );
GapBullishSetupJumpto = ValueWhen( GapBullishSetup, bi, 1 );

SetChartOptions( 0, chartShowDates );
Plot( C, "Close", colorViolet , styleCandle, Null, Null, 0, 0, 1 );

GfxSelectPen( ColorRGB( 0, 0, 180 ), 4, 0 );
GfxSelectSolidBrush( ColorRGB( 0, 0, 60 ) );

for( i = lvb; i > fvb + 1; i-- )
{
    if( GapBullishSetup[i] )
    {
        // initial coordinated
        x0top = i - 1;
        x1top = Min( i + GapBullishMaxBars, BarCount - 1 );
        y0top = O[i];
        y1top = O[i];

        x0bot = i - 1;
        x1bot = Min( i + GapBullishMaxBars, BarCount - 1 );
        y0bot = C[i - 1];
        y1bot = C[i - 1];

        gaptop = LineArray( x0top, y0top, x1top, y1top );
        gapbot = LineArray( x0bot, y0bot, x1bot, y1bot );

        // condition when filled
        fillCondition = IIf( !IsEmpty( gapbot ), Cross( gapbot, L ) OR L < gapbot, 0 );
        fillCondition = fillCondition && SumSince( i == bi, fillCondition ) == 1;
        lx = LastValue( ValueWhen( fillCondition, bi ) );
        lidx = lx;

        if( lx == 0 ) // no cross found
        {
            lx = x1bot;
        }

        if( lx - i >= GapBullishMinBars ) // exclude where cross is too early
        {
            // adjusted coordinates for fill condition
            x0top = i - 1;
            x1top = lx;
            y0top = O[i];
            y1top = O[i];

            x0bot = i - 1;
            x1bot = lx;
            y0bot = C[i - 1];
            y1bot = C[i - 1];

            gaptop = LineArray( x0top, y0top, x1top, y1top );
            gapbot = LineArray( x0bot, y0bot, x1bot, y1bot );

            GfxPolyline( x0bot, y0bot, x0bot + 0, y0top, x1top, y1top, x1bot, y1bot, x0bot, y0bot );

            if( fillPatternWithColor )
            {
                GfxPolygon( x0bot, y0bot, x0bot + 0, y0top, x1top, y1top, x1bot, y1bot, x0bot, y0bot );
            }

            if( lidx != 0 )
            {
                Buy[lidx] = 1;
                BuyPrice[lidx] = C[lidx];
            }
        }
    }

    i = GapBullishSetupJumpto[i - 1] + 1;
}

PlotShapes( IIf( Buy, shapeUpArrow, shapeNone ), colorGreen, 0, L, -15 );
PlotShapes( IIf( Buy, shapeSmallCircle, shapeNone ), colorWhite, 0, BuyPrice, 0 );
4 Likes

@empottasch very nice work!

Personally, I only applied a couple of small changes:

  • Instead of using the firstvisiblebar, I further look back, so when I scroll left, I see also past gaps that are still in play (unfilled and not 'expired')

  • To make the gaps more easily identifiable I used different colors for the polyline and the polygon.
    Using ColorHSB( hue, saturation, brightness ) instead of the ColorRGB is a lot easier to "rotate" colors. The idea is to create, for each gap, a pair of colors with the same hue and a different brightness (the fill is darker than the line).

Here is the result (compared to your formula result mainly to show the extra "gaps", visible at the left side of the chart, due to the first change):

immagine

The loop is initialized in this way:

gapCnt = 1; // used for the color rotation
for( i = lvb; i > (Max(0, fvb-GapBullishMaxBars)) + 1; i-- ) 

And the coloring part (inside the loop) is something like:

lineColor = ColorHSB( (gapCnt * fillPatternColorStep) % 256, 255, 223);
fillColor = ColorHSB( (gapCnt * fillPatternColorStep) % 256, 255, 95);		
gapCnt++;

The variable "fillPatternColorStep" in my case is an additional Param with a default value of 33.

Finally, I also added some (gfx related) range checking to draw lines/polygons inside the pane limits (sometimes the "gaps" overlapped the scales).

Thanks again for sharing your code. :slight_smile:

3 Likes

thanks Bebbe,

yes I have been using the fvb/lvb range a lot lately because I like the speed. In this case however, this gap fill finder seems to only give nice signals when using EOD data where there is no pre-market or afterhours data added. I made a version where instead of using a percentage I use ATR (see below). I like ATR because when switching time frames it adjusts to the bars and one does not have to figure out an alternative percentage value to use. But I noticed that in other time frames I do not see these nice signals.

So might as well just use:

for( i = BarCount - 1; i > 1; i-- )

since I also built in a "jump", so it jumps from pattern to pattern. Here is the ATR version.

// http://forum.amibroker.com/t/do-not-disqualify-levels-on-the-next-occurrence/5287
// E.M.Pottasch 3/2018

GapBullishATRPeriod = Param( "Bullish ATR Period", 100, 2, 200, 1 );
GapBullishATRMultiple = Param( "Bullish ATR Multiple", 2, 0.1, 10, 0.1 );
GapBullishMinBars = Param( "Bullish Minimum Bars Since Inception", 5, 0, 100, 1 );
GapBullishMaxBars = Param( "Bullish Maximim Bars Since Inception", 5000, 5, 10000, 1 );
fillPatternWithColor = ParamToggle( "Fill Zone with Color", "Off|On", 0 );

GfxSetZOrder( -5 );
GfxSetCoordsMode( 1 );

bi = BarIndex();
fvb = FirstVisibleValue( bi );
lvb = LastVisibleValue( bi );

Buy = Sell = Short = Cover = 0;
BuyPrice = SellPrice = ShortPrice = CoverPrice = 0;

GapBullishSetup = Open - Ref( Close, -1 ) > Ref( ATR( GapBullishATRPeriod ), -1 ) * GapBullishATRMultiple;
GapBullishSetupJumpto = ValueWhen( GapBullishSetup, bi, 1 );

SetChartBkColor( ColorRGB( 0, 0, 0 ) );
SetChartOptions( 0, chartShowDates );
Plot( C, "Close", colorViolet , styleCandle, Null, Null, 0, 0, 1 );

GfxSelectPen( ColorRGB( 0, 200, 200 ), 4, 0 );
GfxSelectSolidBrush( ColorRGB( 0, 21, 21 ) );

cnt = 0;

//for( i = lvb; i > fvb; i-- )
for( i = BarCount - 1; i > 1; i-- )
{
    if( GapBullishSetup[i] )
    {
        // initial coordinates
        x0top = i - 1;
        x1top = Min( i + GapBullishMaxBars, BarCount - 1 );
        y0top = O[i];
        y1top = O[i];

        x0bot = i - 1;
        x1bot = Min( i + GapBullishMaxBars, BarCount - 1 );
        y0bot = C[i - 1];
        y1bot = C[i - 1];

        gaptop = LineArray( x0top, y0top, x1top, y1top );
        gapbot = LineArray( x0bot, y0bot, x1bot, y1bot );

        // condition when filled
        fillCondition = IIf( !IsEmpty( gapbot ), Cross( gapbot, L ) OR L < gapbot, 0 );
        fillCondition = fillCondition && SumSince( i == bi, fillCondition ) == 1;
        lx = LastValue( ValueWhen( fillCondition, bi ) );
        lidx = lx;

        if( lx == 0 ) // no cross found
        {
            lx = x1bot;
        }

        if( lx - i >= GapBullishMinBars ) // exclude where cross is too early
        {
            // adjusted coordinates for fill condition
            x0top = i - 1;
            x1top = lx;
            y0top = O[i];
            y1top = O[i];

            x0bot = i - 1;
            x1bot = lx;
            y0bot = C[i - 1];
            y1bot = C[i - 1];

            GfxPolyline( x0bot, y0bot, x0bot + 0, y0top, x1top, y1top, x1bot, y1bot, x0bot, y0bot );

            if( fillPatternWithColor )
            {
                GfxPolygon( x0bot, y0bot, x0bot + 0, y0top, x1top, y1top, x1bot, y1bot, x0bot, y0bot );
            }

            if( lidx != 0 ) // buy when gap is filled
            {
                Buy[lidx] = 1;
                BuyPrice[lidx] = C[lidx];
            }
        }
    }

    cnt++;
    i = GapBullishSetupJumpto[i - 1] + 1;
}

PlotShapes( IIf( Buy, shapeUpArrow, shapeNone ), colorGreen, 0, L, -15 );
PlotShapes( IIf( Buy, shapeSmallCircle, shapeNone ), colorWhite, 0, BuyPrice, 0 );

Filter = Buy;
AddColumn( Buy, "Buy Signal", 1.2, colorWhite, colorGreen );
1 Like

Very nice, both of you

with intra-day data, instead of looking for gaps (which mostly only occur after a weekend) one could also look for a price surge occurring within a limited number of bars. Here is an early result for a bullish surges:

img

1 Like

Edward,

Can you tell me, or point me to the literature re what the exclamation point is in this line? I have searched and searched and all I can find is the not equal != sign.

fillCondition = IIf( !IsEmpty( gapbot ), Cross( gapbot, L ) OR L < gapbot, 0 );

Thank you,
James

1 Like