// Downloaded From https://www.WiseStockTrader.com
/* ABCD PATTERN DETECTION

- based on earlier work done by joy.edakad@gmail.com, see:
	www.inditraders.com/amibroker/1934-afl-harmonic-patterns.html
	file: Harmonic1.1.afl (2009)
- using ATR type Peaks and Troughs.
- Nomenclature of variables, constants and arrays following code
	from David Keleher.

see also:
http://harmonictrader.com/blog/2013/08/03/abcd/
http://harmonictrader.com/blog/2013/08/03/alternate-abcd/

Reciprocal ratios following Scott M. Carney,
Harmonic Trading (2010)

C Point Retracement		BC Projection
0.382 					2.618
0.50 					2.0
0.618 					1.618
0.707 					1.41
0.786 					1.27
0.886 					1.13

This code looks for a C point retracement (AB leg retracement)
within the margin of error (see parameter window). Then it
looks for the reciprocal to that retracement, retracing the
BC leg towards point D (again within the same margin of error).
The margin of error is set to 5% by default.

E.M.Pottasch (Dec 2016). */

Version( 6.0 );
GfxSetCoordsMode( 1 );
GfxSetOverlayMode( 1 );

BullABC = BullABCD = 0;
BearABC = BearABCD = 0;
pk = tr = pkn = trn = 0;

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

GraphXSpace = 5;
SetChartBkColor( colorBlack );
SetChartOptions( 1, chartShowDates, chartGridMiddle, 0, 0, 0 );
SetBarFillColor( IIf( C > O, ColorRGB( 0, 75, 0 ), IIf( C <= O, ColorRGB( 75, 0, 0 ), colorLightGrey ) ) );
Plot( C, "", IIf( C > O, ColorRGB( 0, 255, 0 ), IIf( C <= O, ColorRGB( 255, 0, 0 ), colorLightGrey ) ), 64, Null, Null, 0, 0, 1 );

_SECTION_BEGIN( "Patterns" );
perBull = Param( "Bullish ATR Period", 20, 1, 150, 1 );
perBear = Param( "Bearish ATR Period", 20, 1, 150, 1 );
multBull = Param( "Bullish ATR Multiple", 2, 1, 4, 0.05 );
multBear = Param( "Bearish ATR Multiple", 2, 1, 4, 0.05 );
trailValueClose = ParamToggle( "Trail value", "High/Low|Close", 1 );
//tfrm = in1Minute * Param( "Time Frame (min)", 5, 1, 1440 * 10, 1 ); // 1440 minutes is 1 day
tfrm = in1Minute * Interval() / 60 * Param( "Chart Time Frame Factor", 1, 1, 10, 1 ); // factor 1 uses timeframe of chart
showATRPivots = ParamToggle( "Show ATR Pivots", "Off|On", 0 );
showLabels = ParamToggle( "Show ATR Pivot Labels", "Off|On", 0 );
bu = ParamToggle( "Show Bullish Pattern", "Off|On", 1 );
be = ParamToggle( "Show Bearish Pattern", "Off|On", 1 );
nBull = Param( "Max Number of Bullish Patterns", 10, 0, 100, 1 );
nBear = Param( "Max Number of Bearish Patterns", 10, 0, 100, 1 );
dABCD = ParamToggle( "Draw ABCD", "Off|On", 1 );
showPatternDevelopmentPoints = ParamToggle( "Show Points of Pattern Development", "Off|On", 1 );
showPatternLabels = ParamToggle( "Show Pattern Labels", "Off|On", 0 );
showPatternName = ParamToggle( "Show Pattern Name", "Off|On", 1 );
_SECTION_END();

_SECTION_BEGIN( "ABCD" );
maxd = Param( "Maximal Retracement Deviation (%)", 5, 0, 100.0, 1 );
_SECTION_END();

ABRet = 0;
ABRet[0] = 0.382;
ABRet[1] = 0.500;
ABRet[2] = 0.618;
ABRet[3] = 0.707;
ABRet[4] = 0.786;
ABRet[5] = 0.886;
BCRet = 0;
BCRet[0] = 2.618;
BCRet[1] = 2.000;
BCRet[2] = 1.618;
BCRet[3] = 1.410;
BCRet[4] = 1.270;
BCRet[5] = 1.130;

ABRetMin = ABRet - ABRet / 100 * maxd;
ABRetMax = ABRet + ABRet / 100 * maxd;
BCRetMin = BCRet - BCRet / 100 * maxd;
BCRetMax = BCRet + BCRet / 100 * maxd;

function ATRtrail_func()
{
    // Trail code largely from:
    // http://traders.com/Documentation/FEEDbk_docs/2009/06/TradersTips.html
    if( trailValueClose )
    {
        tvHigh = C;
        tvLow = C;
    }
    else
    {
        tvHigh = H;
        tvLow = L;
    }

    sup = tvHigh - multBull * ATR( perBull );
    res = tvLow + multBear * ATR( perBear );

    trailARRAY = Null;
    trailstop = 0;

    for( i = 1; i < BarCount; i++ )
    {
        if( C[ i ] > trailstop AND C[ i - 1 ] > trailstop )
            trailstop = Max( trailstop, sup[ i ] );
        else
            if( C[ i ] < trailstop AND C[ i - 1 ] < trailstop )
                trailstop = Min( trailstop, res[ i ] );
            else
                trailstop = IIf( C[ i ] > trailstop, sup[ i ], res[ i ] );

        trailARRAY[ i ] = trailstop;
    }

    return trailARRAY;
}

TimeFrameSet( tfrm );
trBull = multBull * ATR( perBull );
trBear = multBear * ATR( perBear );
trailArray = ATRtrail_func();
ts = IIf( trailArray > C, trailArray, Null ); // dntrend
tl = IIf( trailArray < C, trailArray, Null ); // uptrend
TimeFrameRestore();

ts = TimeFrameExpand( ts, tfrm, expandlast );
tl = TimeFrameExpand( tl, tfrm, expandlast );

lll = LLV( L, BarsSince( !IsEmpty( tl ) ) );
lll = IIf( ts, lll, Null );
trn = ts AND L == lll;

hhh = HHV( H, BarsSince( !IsEmpty( ts ) ) );
hhh = IIf( tl, hhh, Null );
pkn = tl AND H == hhh;

tr = ExRem( Reverse( trn ), Reverse( pkn ) );
pk = ExRem( Reverse( pkn ), Reverse( trn ) );

tr = Reverse( tr );
pk = Reverse( pk );

for( i = 0; i < 3; i++ )
{
    VarSet( "px" + i, ValueWhen( pk, bi, i ) );
    VarSet( "tx" + i, ValueWhen( tr, bi, i ) );
    VarSet( "ph" + i, ValueWhen( pk, H, i ) );
    VarSet( "tl" + i, ValueWhen( tr, L, i ) );
}

ll = tr AND tl1 < tl2;
hl = tr AND tl1 > tl2;
hh = pk AND ph1 > ph2;
lh = pk AND ph1 < ph2;
dt = pk AND ph1 == ph2;
db = tr AND tl1 == tl2;

if( showATRPivots )
{
    PlotShapes( shapeSmallCircle * tr, IIf( tx1 < px0, ColorRGB( 0, 0, 255 ), colorWhite ), 0, L, -10 );
    PlotShapes( shapeSmallCircle * pk, IIf( px1 < tx0, ColorRGB( 255, 0, 0 ), colorWhite ), 0, H, 10 );
}

// +++ Bullish ABCD
PTvalid = ( px1 > tx1 AND tx1 > px2 AND px2 > tx2 ) AND pk;

if( dABCD AND bu )
{
    for( i = 0; i < 6; i++ )
    {

        ABCDCmin = ABRetMin[i];
        ABCDCmax = ABRetMax[i];
        ABCDDmin = BCRetMin[i];
        ABCDDmax = BCRetMax[i];

        BullABCw = PTvalid AND( ph1 - tl1 ) / ( ph2 - tl1 ) > ABCDCmin AND( ph1 - tl1 ) / ( ph2 - tl1 ) < ABCDCmax;
        BullABC = IIf( BullABCw, BullABCw, BullABC );

        BullABCDw = IIf( Nz( LowestSince( BullABC, L ) ) < Nz( ValueWhen( BullABC, ph1 ) ) - ( Nz( ValueWhen( BullABC, ph1 ) ) - Nz( ValueWhen( BullABC, tl1 ) ) ) * ABCDDmin AND
                         Nz( LowestSince( BullABC, L ) ) > Nz( ValueWhen( BullABC, ph1 ) ) - ( Nz( ValueWhen( BullABC, ph1 ) ) - Nz( ValueWhen( BullABC, tl1 ) ) ) * ABCDDmax AND
                         Nz( HighestSince( BullABC, H ) ) <= Nz( ValueWhen( BullABC, ph1 ) ) AND
                         Nz( LowestSince( BullABC, L ) ) < Nz( ValueWhen( BullABC, tl1 ) ) AND
                         Nz( trn ) AND
                         Nz( LowestSince( BullABC, L ) ) == L, True, False );
        BullABCD = IIf( BullABCDw, BullABCDw, BullABCD );
    }
}

buAy = ValueWhen( BullABC, ph2 );
buAx = ValueWhen( BullABC, px2 );
buBy = ValueWhen( BullABC, tl1 );
buBx = ValueWhen( BullABC, tx1 );
buCy = ValueWhen( BullABC, ph1 );
buCx = ValueWhen( BullABC, px1 );
buDy = ValueWhen( BullABCD, L );
buDx = ValueWhen( BullABCD, bi );

buBCdAB = ( buCy - buBy ) / ( buAy - buBy );
buBCdCD = ( buCy - buDy ) / ( buCy - buBy );

function drawBullishPattern( i, patternName )
{
    GfxSelectSolidBrush( ColorRGB( 0, 0, 50 ) );
    GfxSetBkColor( colorBlack );
    GfxPolygon( buAx[i], buAy[i], buBx[i], buBy[i], buDx[i], buDy[i], buCx[i], buCy[i], buAx[i], buAy[i] );

    GfxSelectPen( ColorRGB( 0, 0, 255 ), 2, 0 );
    GfxMoveTo( buAx[i], buAy[i] );
    GfxLineTo( buBx[i], buBy[i] );
    GfxMoveTo( buBx[i], buBy[i] );
    GfxLineTo( buCx[i], buCy[i] );
    GfxMoveTo( buCx[i], buCy[i] );
    GfxLineTo( buDx[i], buDy[i] );

    GfxSelectPen( ColorRGB( 0, 0, 255 ), 1, 2 );
    GfxMoveTo( buAx[i], buAy[i] );
    GfxLineTo( buCx[i], buCy[i] );
    GfxMoveTo( buBx[i], buBy[i] );
    GfxLineTo( buDx[i], buDy[i] );

    if( showPatternName )
    {
        GfxSetTextColor( ColorRGB( 0, 0, 0 ) );
        GfxSelectFont( "Helvetica", 10, 700 );
        GfxSetBkColor( ColorRGB( 0, 0, 255 ) );
        GfxSetTextAlign( 0 | 8 );
        GfxTextOut( patternName, buCx[i] + 3, buCy[i] );
    }

    GfxSetTextAlign( 0 | 0 );
    GfxSetTextColor( ColorRGB( 0, 0, 255 ) );
    GfxSetBkColor( ColorRGB( 0, 0, 0 ) );
    GfxSelectFont( "Helvetica", 8, 700 );
    GfxTextOut( "" + Prec( buBCdAB[i], 2 ), ( buCx[i] + buAx[i] ) / 2, ( buCy[i] + buAy[i] ) / 2 );
    GfxTextOut( "" + Prec( buBCdCD[i], 2 ), ( buBx[i] + buDx[i] ) / 2, ( buBy[i] + buDy[i] ) / 2 );

    if( showPatternLabels )
    {
        GfxSetTextColor( ColorRGB( 0, 0, 0 ) );
        GfxSelectFont( "Helvetica", 9, 700 );
        GfxSetBkColor( ColorRGB( 0, 0, 255 ) );
        GfxSetTextAlign( 0 | 24 );
        GfxTextOut( "A", buAx[i] - 2, buAy[i] );
        GfxTextOut( "B", buBx[i] - 2, buBy[i] );
        GfxTextOut( "C", buCx[i] + 1, buCy[i] );
        GfxTextOut( "D", buDx[i] + 1, buDy[i] );
    }
}

function drawBullishPatterns()
{
    flag1 = 1;
    flag2 = 0;
    cnt = 0;

    for( i = lvb; i > fvb; i-- )
    {
        if( BullABCD[i] AND flag1 AND cnt < nBull )
        {
            flag1 = 0;
            flag2 = 1;
            cnt = cnt + 1;

            if( BullABCD[i] AND bu AND dABCD )
            {
                drawBullishPattern( i, "Bullish ABCD" );
            }
        }

        if( BullABC[i] AND flag2 )
        {
            flag1 = 1;
            flag2 = 0;
        }
    }
}
drawBullishPatterns();

if( showPatternDevelopmentPoints )
{
    if( bu )
    {
        PlotShapes( shapeDigit3 * BullABC, colorBlue, O, H, 35 );
        PlotShapes( shapeSmallCircle * BullABCD, ColorLightBlue, O, L, -10 );
    }
}

// +++ Bearish ABCD
PTvalid = ( tx1 > px1 AND px1 > tx2 AND tx2 > px2 ) AND tr;

if( dABCD AND be )
{

    for( i = 0; i < 6; i++ )
    {

        ABCDCmin = ABRetMin[i];
        ABCDCmax = ABRetMax[i];
        ABCDDmin = BCRetMin[i];
        ABCDDmax = BCRetMax[i];

        BearABCw = PTvalid AND( ph1 - tl1 ) / ( ph1 - tl2 ) > ABCDCmin AND( ph1 - tl1 ) / ( ph1 - tl2 ) < ABCDCmax;
        BearABC = IIf( BearABCw, BearABCw, BearABC );

        BearABCDw = IIf( Nz( HighestSince( BearABC, H ) ) > Nz( ValueWhen( BearABC, tl1 ) ) + ( Nz( ValueWhen( BearABC, ph1 ) ) - Nz( ValueWhen( BearABC, tl1 ) ) ) * ABCDDmin AND
                         Nz( HighestSince( BearABC, H ) ) < Nz( ValueWhen( BearABC, tl1 ) ) + ( Nz( ValueWhen( BearABC, ph1 ) ) - Nz( ValueWhen( BearABC, tl1 ) ) ) * ABCDDMax AND
                         Nz( LowestSince( BearABC, L ) ) >= Nz( ValueWhen( BearABC, tl1 ) ) AND
                         Nz( HighestSince( BearABC, H ) ) > Nz( ValueWhen( BearABC, ph1 ) ) AND
                         Nz( pkn ) AND
                         Nz( HighestSince( BearABC, H ) ) == H, True, False );
        BearABCD = IIf( BearABCDw, BearABCDw, BearABCD );
    }
}

beAy = ValueWhen( BearABC, tl2 );
beAx = ValueWhen( BearABC, tx2 );
beBy = ValueWhen( BearABC, ph1 );
beBx = ValueWhen( BearABC, px1 );
beCy = ValueWhen( BearABC, tl1 );
beCx = ValueWhen( BearABC, tx1 );
beDy = ValueWhen( BearABCD, H );
beDx = ValueWhen( BearABCD, bi );

beBCdAB = ( beBy - beCy ) / ( beBy - beAy );
beBCdCD = ( beDy - beCy ) / ( beBy - beCy );

function drawBearishPattern( i, patternName )
{
    GfxSelectSolidBrush( ColorRGB( 50, 0, 0 ) );
    GfxSetBkColor( colorBlack );
    GfxPolygon( beAx[i], beAy[i], beBx[i], beBy[i], beDx[i], beDy[i], beCx[i], beCy[i], beAx[i], beAy[i] );

    GfxSelectPen( ColorRGB( 255, 0, 0 ), 2, 0 );
    GfxMoveTo( beAx[i], beAy[i] );
    GfxLineTo( beBx[i], beBy[i] );
    GfxMoveTo( beBx[i], beBy[i] );
    GfxLineTo( beCx[i], beCy[i] );
    GfxMoveTo( beCx[i], beCy[i] );
    GfxLineTo( beDx[i], beDy[i] );

    GfxSelectPen( ColorRGB( 255, 0, 0 ), 1, 2 );
    GfxMoveTo( beAx[i], beAy[i] );
    GfxLineTo( beCx[i], beCy[i] );
    GfxMoveTo( beBx[i], beBy[i] );
    GfxLineTo( beDx[i], beDy[i] );

    if( showPatternName )
    {
        GfxSetTextColor( ColorRGB( 0, 0, 0 ) );
        GfxSelectFont( "Helvetica", 10, 700 );
        GfxSetBkColor( ColorRGB( 255, 0, 0 ) );
        GfxSetTextAlign( 0 | 0 );
        GfxTextOut( patternName, beCx[i] + 3, beCy[i] );
    }

    GfxSetTextAlign( 0 | 0 );
    GfxSetTextColor( ColorRGB( 255, 0, 0 ) );
    GfxSetBkColor( ColorRGB( 0, 0, 0 ) );
    GfxSelectFont( "Helvetica", 8, 700 );
    GfxTextOut( "" + Prec( beBCdAB[i], 2 ), ( beCx[i] + beAx[i] ) / 2, ( beCy[i] + beAy[i] ) / 2 );
    GfxTextOut( "" + Prec( beBCdCD[i], 2 ), ( beBx[i] + beDx[i] ) / 2, ( beBy[i] + beDy[i] ) / 2 );

    if( showPatternLabels )
    {
        GfxSetTextColor( ColorRGB( 0, 0, 0 ) );
        GfxSelectFont( "Helvetica", 9, 700 );
        GfxSetBkColor( ColorRGB( 255, 0, 0 ) );
        GfxSetTextAlign( 0 | 24 );
        GfxTextOut( "A", beAx[i] - 2, beAy[i] );
        GfxTextOut( "B", beBx[i] - 2, beBy[i] );
        GfxTextOut( "C", beCx[i] + 1, beCy[i] );
        GfxTextOut( "D", beDx[i] + 1, beDy[i] );
    }
}

function drawBearishPatterns()
{
    flag1 = 1;
    flag2 = 0;
    cnt = 0;

    for( i = lvb; i > fvb; i-- )
    {
        if( BearABCD[i] AND flag1 AND cnt < nBear )
        {
            flag1 = 0;
            flag2 = 1;
            cnt = cnt + 1;

            if( BearABCD[i] AND be AND dABCD )
            {
                drawBearishPattern( i, "Bearish ABCD" );
            }
        }

        if( BearABC[i] AND flag2 )
        {
            flag1 = 1;
            flag2 = 0;
        }
    }
}
drawBearishPatterns();

function drawPivotLabels()
{
    sz = 5;

    for( i = lvb; i > fvb; i-- )
    {
        {
            if( ll[i] ) PlotTextSetFont( "LL", "Arial Black", sz, i, L[i], colorBlue, colorDefault, -25 );

            if( hl[i] ) PlotTextSetFont( "HL", "Arial Black", sz, i, L[i], colorBlue, colorDefault, -25 );

            if( db[i] ) PlotTextSetFont( "DB", "Arial Black", sz, i, L[i], colorLightBlue, colorDefault, -25 );

            if( hh[i] ) PlotTextSetFont( "HH", "Arial Black", sz, i, H[i], colorRed, colorDefault, 20 );

            if( lh[i] ) PlotTextSetFont( "LH", "Arial Black", sz, i, H[i], colorRed, colorDefault, 20 );

            if( dt[i] ) PlotTextSetFont( "DT", "Arial Black", sz, i, H[i], colorOrange, colorDefault, 20 );
        }
    }
}

if( showLabels ) drawPivotLabels();

if( showPatternDevelopmentPoints )
{

    if( be )
    {
        PlotShapes( shapeDigit3 * BearABC, colorRed, O, L, -35 );
        PlotShapes( shapeSmallCircle * BearABCD, colorOrange, O, H, 10 );
    }
}

Title = Name() +
        " | " + Now( 2 ) +
        " | " + "PIVOT TIMEFRAME: " + tfrm / 60 + " Minutes or " + tfrm / 3600 + " Hours or " + tfrm / ( 3600 * 24 ) + " Days ";