Comparing stock with an index

Hello my trader friends,

I don't know much about afl, so I need help with creating a divergence indicator between a stock and an index symbol I choose. See below image and example.

As you can see in the image that stock CELH is making a higher highs and Index SPX is making a lower lows. Someone please help me with creating this divergence indicator ?

Thank you and have a great year 2023.

Your question isn't really clear what you are trying to accomplish. Are you just try to add the trendlines? Or are you trying to run an exploration that finds such divergences?

@npweb005 there are many discussions on this forum on divergence. Have you searched the forum and in the Knowledge Base. Which codes have you tried and where are your code efforts failing you? For example a list of resources on divergence

Perhaps begin with the simple example in the Official Knowledge Base and then work your way through the other code examples,

3 Likes

@awilson showed how to do that here: https://forum.amibroker.com/t/rsi-divergence-plot-on-chart/15795

I add some code here that you can drag over your price function (CELH).

What you need to add yourself in the code is func2. It compares 2 functions, func1 and func2. In func2 you have to put your SPX data. In the code below I have put in func2 ES-mini futures data. You can also use the RSI or whatever.

func1 = ZigZag;
//func2 = RSI();
func2 = Foreign( "@ES#", "C" );
_SECTION_BEGIN( "Divergence Forum" );

per = Param( "ATR Period", 100, 1, 100, 1 ); // you need at least "per" data points to run this code
mult = Param( "ATR Multiple", 3, 0.5, 20, 0.1 );
priceswitch = ParamToggle( "Use Close or High and Low price", "Use Close|Use High and Low", 0 );
showregularBull = ParamToggle( "Show Regular Divergence Bullish", "No|Yes", 1 );
showregularBear = ParamToggle( "Show Regular Divergence Bearish", "No|Yes", 1 );
showhiddenBull = ParamToggle( "Show Hidden Divergence Bullish", "No|Yes", 1 );
showhiddenBear = ParamToggle( "Show Hidden Divergence Bearish", "No|Yes", 1 );
showaffirmativeBull = ParamToggle( "Show Affirmative Divergence Bullish", "No|Yes", 0 );
showaffirmativeBear = ParamToggle( "Show Affirmative Divergence Bearish", "No|Yes", 0 );
showZigZag = ParamToggle( "Show ZigZag", "No|Yes", 1 );
showLabels = ParamToggle( "Show Labels", "No|Yes", 1 );
colorBullishRegular = ParamColor( "Bullish Regular Color", ColorRGB( 50, 50, 255 ) );
colorBullishHidden = ParamColor( "Bullish Hidden Color", ColorRGB( 176, 196, 222 ) );
colorBullishAffirmative = ParamColor( "Bullish Affirmative Color", ColorRGB( 0, 191, 255 ) );
colorBearishRegular = ParamColor( "Bearish Regular Color", ColorRGB( 154, 1, 80 ) );
colorBearishHidden = ParamColor( "Bearish Hidden Color", ColorRGB( 255, 69, 0 ) );
colorBearishAffirmative = ParamColor( "Bearish Affirmative Color", ColorRGB( 240, 128, 128 ) );
sz = Param( "Font Size", 10, 7, 20, 1 );
linethickness = Param( "Line Thickness", 2, 1, 10, 1 );
maxcnt = Param( "Maximum Number of Divergences shown in Chart", 10, 2, 20, 1 ); // maximum divergences shown in plot

bi = BarIndex();
fvb = FirstVisibleValue( bi );
lvb = LastVisibleValue( bi );
pk = tr = Buy = Sell = BuyPrice = SellPrice = 0;
trailarrayup = trailarraydn = Null;

if( priceswitch )
{
    prch = H;
    prcl = L;
}
else
{
    prch = C;
    prcl = C;
}

// if ticksize is not set in code or information window use 0.01
if( TickSize == 0 )
{
    TickSize = 0.01;
}

slip = TickSize * 0;
sup = round( ( prch - mult * ATR( per ) ) / TickSize ) * TickSize;
res = round( ( prcl + mult * ATR( per ) ) / TickSize ) * TickSize;

trend = 1; // start trend at 1 or -1 doesnt matter
topprc = 0;
topidx = 0;
botprc = 0;
botidx = 0;

for( i = per + 1; i < BarCount; i++ )
{
    if( trend > 0 )
    {
        if( prcl[i] <= trailarrayup[i - 1] )// AND prch[i] < topprc )
        {
            // trend turning down, avoid same bar as the peak
            pk[topidx] = 1;
            botprc = prcl[i];
            botidx = i;
            trend = -1;
            Sell[i] = 1;
            trailarraydn[i] = res[i];
            trailarrayup[i] = trailarrayup[i - 1];

            if( priceswitch )
                SellPrice[i] = Min( O[i], trailarrayup[i] ) - slip;
            else
                SellPrice[i] = C[i] - slip;
        }
        else
            if( prch[i] >= topprc )
            {
                // still in uptrend but new top reached
                topprc = prch[i];
                topidx = i;
                trailarrayup[i] = Max( trailarrayup[i - 1], sup[i] );
            }
            else
            {
                // continuation inside uptrend
                trailarrayup[i] = Max( trailarrayup[i - 1], sup[i] );
            }
    }
    else
        if( trend < 0 )
        {
            if( prch[i] >= trailarraydn[i - 1] )// AND prcl[i] > botprc )
            {
                // trend turning up, avoid same bar as the trough
                tr[botidx] = 1;
                topprc = prch[i];
                topidx = i;
                trend = 1;
                Buy[i] = 1;
                trailarrayup[i] = sup[i];
                trailarraydn[i] = trailarraydn[i - 1];

                if( priceswitch )
                    BuyPrice[i] = Max( O[i], trailarraydn[i] ) + slip;
                else
                    BuyPrice[i] = C[i] + slip;
            }
            else
                if( prcl[i] <= botprc )
                {
                    // still in downtrend but new trough reached
                    botprc = prcl[i];
                    botidx = i;
                    trailarraydn[i] = Min( trailarraydn[i - 1], res[i] );
                }
                else
                {
                    // continuation inside downtrend
                    trailarraydn[i] = Min( trailarraydn[i - 1], res[i] );
                }
        }
}

line1 = Null;
lastidxpk = LastValue( ValueWhen( pk, bi ) );
lastidxtr = LastValue( ValueWhen( tr, bi ) );
lastvalpk = LastValue( ValueWhen( pk, prch ) );
lastvaltr = LastValue( ValueWhen( tr, prcl ) );
lastidxbuy = LastValue( ValueWhen( Buy, bi ) );
lastidxsell = LastValue( ValueWhen( Sell, bi ) );
valpk = LastValue( HighestSince( Ref( tr, -1 ), prch , 1 ) );
idxpk = LastValue( ValueWhen( prch == valpk, bi ) );
valtr = LastValue( LowestSince( Ref( pk, -1 ), prcl, 1 ) );
idxtr = LastValue( ValueWhen( prcl == valtr, bi ) );
lastidxbuy0 = ValueWhen( Buy , bi, 0 );
lastidxsell0 = ValueWhen( Sell, bi, 0 );

if( lastidxsell > lastidxbuy AND lastidxsell > lastidxpk AND lastidxpk > lastidxtr )
{
    x0 = lastidxpk;
    y0 = lastvalpk;
    x1 = idxtr;
    y1 = valtr;
    line1 = linedn = LineArray( x0, y0, x1, y1 );
    tr[idxtr] = 1;
    valpk = LastValue( HighestSince( Ref( tr, -1 ), prch, 1 ) );
    idxpk = LastValue( ValueWhen( prch == valpk, bi ) );
}

if( lastidxsell < lastidxbuy AND lastidxbuy > lastidxtr AND lastidxpk < lastidxtr )
{
    x0 = lastidxtr;
    y0 = lastvaltr;
    x1 = idxpk;
    y1 = valpk;
    line1 = lineup = LineArray( x0, y0, x1, y1 );
    pk[idxpk] = 1;
    valtr = LastValue( LowestSince( Ref( pk, -1 ), prcl, 1 ) );
    idxtr = LastValue( ValueWhen( prcl == valtr, bi ) );
}

// create ZIGZAG array line
zigup = Flip( tr, pk );
zigupLow = ValueWhen( tr, prcl, 1 );
zigupHigh = ValueWhen( pk, prch, 0 );
zigupLowIndex = ValueWhen( tr, bi, 1 );
zigupHighIndex = ValueWhen( pk, bi, 0 );
slopeup = IIf( zigup, ( zigupHigh - zigupLow ) / ( zigupHighIndex - zigupLowIndex ) , Null );
zigupLine = IIf( zigup, zigupLow + slopeup * BarsSince( tr ), Null );

zigdn = Flip( pk, tr );
zigdnLow = ValueWhen( tr, prcl, 0 );
zigdnHigh = ValueWhen( pk, prch, 1 );
zigdnLowIndex = ValueWhen( tr, bi, 0 );
zigdnHighIndex = ValueWhen( pk, bi, 1 );
slopedn = IIf( zigdn, ( zigdnLow - zigdnHigh ) / ( zigdnLowIndex - zigdnHighIndex ) , Null );
zigdnLine = IIf( zigdn, zigdnHigh + slopedn * BarsSince( pk ), Null );

ZigZag = IIf( zigup, zigupLine, IIf( zigdn, zigdnLine, Null ) );
ZigZag = IIf( bi > Max( LastValue( ValueWhen( tr, bi ) ), LastValue( ValueWhen( pk, bi ) ) ), Null, ZigZag );
ZigZag = IIf( !IsEmpty( line1 ), line1, ZigZag );

func1 = ZigZag;
//func2 = RSI();
func2 = Foreign( "@ES#", "C" );

Buy = Sell = 0;
onlywhen = pk;
pkFunc2 = SparseCompress( onlywhen, func2 );
pkFunc1 = SparseCompress( onlywhen, func1 );
Sell1 = pkFunc2 < Ref( pkFunc2, -1 ) AND pkFunc1 > Ref( pkFunc1, -1 ); // regular
Sell2 = pkFunc2 > Ref( pkFunc2, -1 ) AND pkFunc1 < Ref( pkFunc1, -1 ); // hidden
Sell3 = pkFunc2 < Ref( pkFunc2, -1 ) AND pkFunc1 < Ref( pkFunc1, -1 ); // affirmative
Sell = Sell1 OR Sell2 OR Sell3;
Sell = SparseExpand( onlywhen, Sell );
Sell1 = SparseExpand( onlywhen, Sell1 );
Sell2 = SparseExpand( onlywhen, Sell2 );
Sell3 = SparseExpand( onlywhen, Sell3 );
Sy0 = SparseExpand( onlywhen, Ref( pkFunc1, -1 ) );
Sy1 = SparseExpand( onlywhen, pkFunc1 );
pkBi = SparseCompress( onlywhen, bi );
Sx0 = SparseExpand( onlywhen, Ref( pkBi, -1 ) );

onlywhen = tr;
thFunc2 = SparseCompress( onlywhen, func2 );
thFunc1 = SparseCompress( onlywhen, func1 );
Buy1 = thFunc2 > Ref( thFunc2, -1 ) AND thFunc1 < Ref( thFunc1, -1 ); // regular
Buy2 = thFunc2 < Ref( thFunc2, -1 ) AND thFunc1 > Ref( thFunc1, -1 ); // hidden
Buy3 = thFunc2 > Ref( thFunc2, -1 ) AND thFunc1 > Ref( thFunc1, -1 ); // affirmative
Buy = Buy1 OR Buy2 OR Buy3;
Buy = SparseExpand( onlywhen, Buy );
Buy1 = SparseExpand( onlywhen, Buy1 );
Buy2 = SparseExpand( onlywhen, Buy2 );
Buy3 = SparseExpand( onlywhen, Buy3 );
By0 = SparseExpand( onlywhen, Ref( thFunc1, -1 ) );
By1 = SparseExpand( onlywhen, thFunc1 );
thBi = SparseCompress( onlywhen, bi );
Bx0 = SparseExpand( onlywhen, Ref( thBi, -1 ) );

// Plot the Lines
if( showZigZag )
{
    Plot( ZigZag, "", colorYellow, styleLine | styleNoRescale | styleNoLabel, Null, Null, 0, -1, linethickness );
}

ft = "arial black";
cnt = 0;
ymin = Status( "axisminy" );
ymax = Status( "axismaxy" );
dy = ( ymax - ymin ) / 13;

lastidxbuy1 = ValueWhen( buy1, bi );
lastidxbuy2 = ValueWhen( buy2, bi );
lastidxbuy3 = ValueWhen( buy3, bi );
lastidxsell1 = ValueWhen( sell1, bi );
lastidxsell2 = ValueWhen( sell2, bi );
lastidxsell3 = ValueWhen( sell3, bi );

for( b = lvb; b > fvb; b-- )
{
    // regular divergence (Exhaustion)
    if( Buy[b] AND Buy1[b] AND showRegularBull )
    {
        if( lastidxbuy1[b] < lastidxbuy0[b] )
        {
            clrbck = ColorRGB( 135, 206, 250 );
        }
        else
            if( lastidxbuy1[b] >= lastidxbuy0[b] )
            {
                clrbck = colorLightGrey;
            }

        Plot( LineArray( Bx0[b], By0[b], b, By1[b] ), "", colorBullishRegular, styleLine | styleNoRescale | styleNoLabel, Null, Null, 0, 15, linethickness );
        cnt = cnt + 1;

        if( showLabels ) PlotTextSetFont( "Regular (Exhaustion)", ft, sz, b, Max( ymin + dy, L[b] ), colorBlack, clrbck, -sz * 5 );
    }

    // hidden divergence  (Absorbtion)
    if( Buy[b] AND Buy2[b] AND showHiddenBull )
    {
        if( lastidxbuy2[b] < lastidxbuy0[b] )
        {
            clrbck = ColorRGB( 135, 206, 250 );
        }
        else
            if( lastidxbuy2[b] >= lastidxbuy0[b] )
            {
                clrbck = colorLightGrey;
            }

        Plot( LineArray( Bx0[b], By0[b], b, By1[b] ), "", colorBullishHidden, styleLine | styleNoRescale | styleNoLabel, Null, Null, 0, 15, linethickness );
        cnt = cnt + 1;

        if( showLabels ) PlotTextSetFont( "Hidden (Absorbtion)", ft, sz, b,  Max( ymin + dy, L[b] ), colorBlack, clrbck, -sz * 5 );
    }

    // affirmative
    if( Buy[b] AND Buy3[b] AND showAffirmativeBull )
    {
        if( lastidxbuy3[b] < lastidxbuy0[b] )
        {
            clrbck = ColorRGB( 135, 206, 250 );
        }
        else
            if( lastidxbuy3[b] >= lastidxbuy0[b] )
            {
                clrbck = colorLightGrey;
            }

        Plot( LineArray( Bx0[b], By0[b], b, By1[b] ), "", colorBullishAffirmative, styleLine | styleNoRescale | styleNoLabel, Null, Null, 0, 15, linethickness );
        cnt = cnt + 1;

        if( showLabels ) PlotTextSetFont( "Affirmative", ft, sz, b,  Max( ymin + dy, L[b] ), colorBlack, clrbck, -sz * 5 );
    }

    // regular divergence  (Exhaustion)
    if( Sell[b] AND Sell1[b] AND showRegularBear )
    {
        if( lastidxsell1[b] < lastidxsell0[b] )
        {
            clrbck = ColorRGB( 255, 165, 0 );
        }
        else
            if( lastidxsell1[b] >= lastidxsell0[b] )
            {
                clrbck = colorLightGrey;
            }

        Plot( LineArray( Sx0[b], Sy0[b], b, Sy1[b] ), "", colorBearishRegular, styleLine | styleNoRescale | styleNoLabel, Null, Null, 0, 15, linethickness );
        cnt = cnt + 1;

        if( showLabels ) PlotTextSetFont( "Regular (Exhaustion)", ft, sz, b, Min( ymax - dy, H[b] ), colorBlack, clrbck, sz * 4 );
    }

    // hidden divergence (absorbtion)
    if( Sell[b] AND Sell2[b] AND showHiddenBear )
    {
        if( lastidxsell2[b] < lastidxsell0[b] )
        {
            clrbck = ColorRGB( 255, 165, 0 );
        }
        else
            if( lastidxsell2[b] >= lastidxsell0[b] )
            {
                clrbck = colorLightGrey;
            }

        Plot( LineArray( Sx0[b], Sy0[b], b, Sy1[b] ), "", colorBearishHidden, styleLine | styleNoRescale | styleNoLabel, Null, Null, 0, 15, linethickness );
        cnt = cnt + 1;

        if( showLabels ) PlotTextSetFont( "Hidden (Absorbtion)", ft, sz, b, Min( ymax - dy, H[b] ), colorBlack, clrbck, sz * 4 );
    }

    // affirmative
    if( Sell[b] AND Sell3[b] AND showAffirmativeBear )
    {
        if( lastidxsell3[b] < lastidxsell0[b] )
        {
            clrbck = ColorRGB( 255, 165, 0 );
        }
        else
            if( lastidxsell1[b] >= lastidxsell0[b] )
            {
                clrbck = colorLightGrey;
            }

        Plot( LineArray( Sx0[b], Sy0[b], b, Sy1[b] ), "", colorBearishAffirmative, styleLine | styleNoRescale | styleNoLabel, Null, Null, 0, 15, linethickness );
        cnt = cnt + 1;

        if( showLabels ) PlotTextSetFont( "Affirmative", ft, sz, b, Min( ymax - dy, H[b] ), colorBlack, clrbck, sz * 4 );
    }

    if( cnt >= maxcnt ) break;
}

_SECTION_END();

6 Likes

Thank you Edward and appreciate your help. This is really useful for what I was looking for.

Edward @empottasch, I just wanted to check with you that all the divergences are not back-painted with this formula, right ? I understand that there are some that will do..... but not sure which ones.

hi, I added a color for that. As you see in the chart I added (above) the last divergence signal has a "colorLightGrey" background. This means that the signal is not yet confirmed. In the chart above I used ATR Multiple 4. But as soon as it detects divergence it is shown in the chart. But then the location can still change and also it could completely disappear.

Best is to do a "playback" in Amibroker and then you see what will happen. It could be an early indication of divergence. To wait for confirmation is often too late.

So the background of the label is colorLightGrey when there is divergence but the divergence is not yet confirmed. Best to test it with the Playback utility in Amibroker.

also this is just example code. You can think of many variations. I use it but I only show the exhaustion signals. And I will finetune this as well. For instance in the chart below I compare the Price with the CVD (Cumulative Volume Delta). The first divergence is quite strong. You see clear divergence. The second signal is just a marginal divergence. That 1 should have been rejected. The last 1 is still unconfirmed but there is medium strong divergence visible, I would say :smiley:

2 Likes

This is nice Edward and thank you for explaining it. I will check with bar replay in amibroker. Also please post the code here when you finetune this divergence code in the future. I will use it in conjunction with other signals. Out of these 3 divergence which one do you think are more reliable and stronger ?

Hello Edward,

I have checked with bar replay. It is taking too long to confirm the divergence. I will play with indicator and see how it goes. Also would you mind sharing the code of the delta volume indicator (bottom one in the image) if its ok with you.

Thank you,

yes, unfortunately tops and bottoms are always only known in hindsight. But it starts showing potential/possible divergences.

With respect to the Volume Delta indicator you need tick data for that. There is some information on the forum how to calculate it. Search on the forum for BuyVolume and SellVolume. The DeltaVolume is just BuyVolume-SellVolume. Then the CVD is the Cumulative DeltaVolume. But as I said you will need a data subscription with for instance IQFeed because to calculate the BuyVolume and the SellVolume you will need the volume traded at the ask price and volume traded at the bid price.

Thank you Edward. I will look into CVD for more information.