How to Plot Extend Donchian Low Channel Line from the past?

Hello Expert !

I don't have much programming knowledge, can anyone help me plot the Extension line of Donchian Low Channel if it has had at least 5 equal values ​​in the past?

Donchian LC:

LC = LLV(Ref(L,-1), 20);

Here is Screenshot:

Thanks you!

Plot( C, "Close", colorDefault, styleNoTitle | GetPriceStyle() ); 
LC = LLV(Ref(L,-1), 20);

cLC = Sum(Lc == Ref(LC, -1), 5);
cLC = cLC == 5 AND Ref(cLC, -1) == 4;

//Plot(LC, "LC", colorBlue);
//Plot(cLC, "cLC", colorRed, styleLine | styleOwnScale);

bi = BarIndex(); 

fvb = FirstVisibleValue( bi ); 
lastbar = LastVisibleValue( bi ); 

GfxSetOverlayMode(1); 
GfxSetCoordsMode( 1 );
GfxSelectSolidBrush( colorRed ); 
GfxSelectPen( colorRed, 1 ); 

for ( i = fvb; i < lastbar AND i < BarCount; i++ )
{
	if( cLC[i] )
	{
		GfxMoveTo( i, LC[i] );
		GfxLineTo( lastbar, LC[i]);
	}
}
3 Likes

Thank you @awilson for your help!
There is any other way, ie function for cLC for example we can count all the Extend?
Instead to plot the original LC, we will plot cLC(s) for that. If any value from (barcont -1) back to the past in the block >= 5 with equal value will be cLC.
So we maybe have many cLC values. Each cLC value is the one Extend Line.
In this way, we do not plot LC or turn it off.

Now I have to read the (Understanding how AFL works) to understand your help.

Thanks you!

Sorry , not sure what you want. Please rephrase.

@kiennc below there is a formula, similar to the one posted by @awilson, which additionally allows you to control how many extensions to draw and also to print the number of consecutive repeated lows (I hope I understood your request). It also includes some dynamically editable parameters.
This version is slower and way more convoluted than the one he posted, looping over the bars one by one, to determine the coordinates from which to start the extension, but perhaps easier to understand for someone who has already programmed using loops in any other language.

// https://forum.amibroker.com/t/how-to-plot-extend-donchian-low-channel-line-from-the-past/39465
donchianLowPeriod = Param( "Donchian low period", 20, 5, 100, 5 );
donchianLowColor = ParamColor( "Donchian low color", colorGreen );
donchianLowVisibility = ParamList( "Donchian low line visible", "No|Full|Repeated values", 1 );
donchianLowExtensionColor = ParamColor( "Donchian low extension color", colorOrange );
sameValuesCount = Param( "# of equal values", 5, 3, 100, 1 );
maxExtensions = Param( "# of line extensions", 3, 0, 10, 1 );
showExtensionsPrice = ParamToggle( "Show line extensions price", "No|Yes", 1 );

LC = LLV( Ref( L, -1 ), donchianLowPeriod );

GraphXSpace = 5;
Plot( C, "Price", colorDefault, styleCandle );
if( donchianLowVisibility == "Full" )
    Plot( LC, "Donchian Low", donchianLowColor, styleThick );

if( maxExtensions > 0 )
{
    // draws only in the "visible" bars range
    bi = Barindex();
    fvb = FirstVisibleValue( bi );
    lvb = LastVisibleValue( bi );
    GfxSetBkMode( 1 );
    GfxSetCoordsMode( 1 );

    GfxSelectPen( donchianLowExtensionColor, 1, 2 );
    GfxSelectFont( "Arial", 9, 800 );
    GfxSetTextColor( donchianLowExtensionColor );

    // loop over the visible bars backward
    prev = LC[lvb];
    counter = 0;
    start = -1;
    drawnLines = 0;
    LCRepeatedValues = null;

    for( i = lvb - 1; i >= fvb; i-- )
    {
        if( drawnLines >= maxExtensions )
            break;

        if( LC[i] == prev )
        {
            if( counter == 0 )
            {
                start = i + 1;
                LCRepeatedValues[start] = LC[start];
            }

            counter++;
            LCRepeatedValues[i] = LC[i];
        }
        else
        {
            if( counter >= sameValuesCount )
            {
                if( start < lvb )
                {
                    GfxTextOut( "" + counter, start, LC[start] );
                    GfxMoveTo( start, LC[start] );
                    GfxLineTo( Lvb, LC[start] );
                    drawnLines++;

                    if( donchianLowVisibility == "Repeated values" )
                    {
                        Plot( LCRepeatedValues, "", donchianLowColor , styleThick );
                        LCRepeatedValues = null;
                    }

                    if( showExtensionsPrice )
                        Plot( LC[start], "", donchianLowExtensionColor, styleNoLine | styleNoTitle );
                }
            }

            counter = 0;
            LCRepeatedValues = null;

        }

        prev = LC[i];
    }

    // if required draw one more extension line in case the repeated values continue until the leftmost visible bar: the displyed count is then only for the visible bars...
    if( drawnLines < maxExtensions )
    {

        if( counter >= sameValuesCount )
        {
            GfxTextOut( ">=" + counter, start, LC[start] );
            GfxMoveTo( start, LC[start] );
            GfxLineTo( Lvb, LC[start] );

            if( donchianLowVisibility == "Repeated values" )
            {
                Plot( LCRepeatedValues, "", donchianLowColor , styleThick );
            }

            if( showExtensionsPrice )
                Plot( LC[start], "", donchianLowExtensionColor, styleNoLine | styleNoTitle );
        }
    }
}

_N( Title = StrFormat( "{{NAME}} - " + FullName() +
                       " - {{INTERVAL}} {{DATE}} Open %g, Hi %g, Lo %g, Close %g (%.1f%%) Vol " +
                       WriteVal( V, 1.0 ) + " {{VALUES}}", O, H, L, C, SelectedValue( ROC( C, 1 ) ) ) );

Note that in this code if the Donchian low line of the last (rightmost) visible bar is part of a sequence of repeated values, the extension is not drawn and consequently not even counted (even if you have some "blank bars").

Although this code example uses a loop limited to a certain number of individual bars, when possible it is always better to use functions that work on entire arrays and for this reason I recommend you continue your study on how AFL works!

2 Likes

Like @beppe post I often do a full looping version to confirm my understanding. As I write that the array processing possibilities sometimes start to become more obvious. This time just looping through defined events happened to work out.

Feedback welcome.
John

SetBarsRequired( sbrAll, sbrAll );  // turn off QuickAfl so all lines from history are drawn (testing execution speed)

LC = LLV(Ref(L,-1), 20);  // lower donchian channel
Plot( LC, "LC", colorBlueGrey, styleDots );

FlatBars = 5;  // number of same value bars in LC to detect
LC_1 = Ref( LC, -1 );
LcFlat = Sum( LC == LC_1, FlatBars-1 ) == FlatBars-1;  // detect n, or more, bars flat line
ExLineStarts = Ref( LcFlat, -1 ) AND LC > LC_1;  // impulses at start of flat extension lines

bi = BarIndex();
lvb = LastVisibleValue( bi );
ChartMinY = Status( "axisminy" );
GfxSetCoordsMode( 1 );  // gfx index/price mode
GfxSelectPen( colorRed, 1, 2 );  // gfx lines: red, thin, short dashes

LineCount = Cum( ExLineStarts );  // array of incrementing line numbers
Lines = LastValue( LineCount );  // number of extention lines (as number) for all symbol history
for( n = 1; n <= Lines; n++ )  // for each line n
{
    LineStart = ExLineStarts AND LineCount == n;  // impulse at start of this line
    StartBi = LastValue( ValueWhen( LineStart, bi ) );  // index of line start
    LinePrice = LC_1[StartBi];
    LineTrue = Flip(  LineStart, LinePrice >= L );  // true state until the line first touches price
    EndBi = LastValue( ValueWhen( LineTrue, bi ) );  // index of line end
    EndBi = Max( StartBi, Min( EndBi, lvb ) );  // constrain end index to between start bar and lvb
    if( LinePrice > ChartMinY )  // prevent linedraw over date axis labels (can fail on refresh)
    {
        GfxMoveTo( StartBi, LinePrice );
        GfxLineTo( EndBi, LinePrice );
    }
}
2 Likes

Thank you @awilson @beppe @JohnHT !

2 Likes