# Asymetric Zig Zag

I would like to plot an asymmetric ZIG ZAG indicator a la John Cookson's work; say 6% upswings and 8% down swings and would appreciate any suggestions, trail heads, or pointers.

John

PS If you feel the need to tell me to Google it or search the forums, please understand that I am a human being who tries hard and refrain as I already have done so extensively and failed to find a usable answer.

Short of writing one yourself in AFL, I would say try the AFL library, search for "zig" and there are a few rewrites and alternatives that can give you hints and inspirations https://www.amibroker.com/members/library/list.php

Something like this one might get you on the right track to writing one in AFL, I haven't looked at it at all:
https://www.amibroker.com/members/library/formula.php?id=417

I actually wanted to write one myself at one point because I found that the Zig function works off one of the OHLC arrays, but I wanted it to work off the High if it's looking for the next peak or a Low if it's the next trough. Instead, as a workaround, I just increased the resolution of the candle chart by going to a smaller interval which gives me a similar effect.

There is a search on this forum too and few pointers that come up are (among others):

1 Like

I adjusted some of the previous code I posted for this.

``````uppercentage = Param( "Upward Zig %", 2, 0.1, 10, 0.1 );
downpercentage = Param( "Downward Zig %", 2, 0.1, 10, 0.1 );
priceswitch = ParamToggle( "Use Close or High and Low price", "Use Close|Use High and Low", 0 );
showUpDnSwing = 1;//ParamToggle( "Show Up/Down Swing", "Off|On", 0 );
labelsswitchswing = ParamToggle( "Show Labels", "Off|On", 1 );
showTrailline = ParamToggle( "Show Trail Line", "Off|On", 1 );

bi = BarIndex();
fvb = FirstVisibleValue( bi );
lvb = LastVisibleValue( bi );
pk = tr = Buy = Sell = BuyPrice = SellPrice = 0;
ZigZag = line1 = line2 = Null;
trailarrayup = Null;
trailarraydn = Null;
mode = "";
SetBarsRequired( ( lvb - fvb ) * 2 );

if( priceswitch )
{
prch = H;
prcl = L;
mode = "High/Low price";
}
else
{
prch = C;
prcl = C;
mode = "Close price";
}

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

function percfluc( prc, perc )
{
retprice = round( ( prc * perc / 100 ) / TickSize ) * TickSize;
return retprice;
}

function calculatePivots()
{
// initial condition trend is up (but -1 works also)
trend = 1;
topprc = prch[0];
topidx = 0;
botprc = prcl[0];
botidx = 0;
trailarrayup[0] = topprc - percfluc( topprc, downpercentage );
trailarraydn[0] = botprc + percfluc( botprc, uppercentage );

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

if( priceswitch )
SellPrice[i] = Min( O[i], trailarrayup[i] );
else
SellPrice[i] = C[i];
}
else

// still in uptrend and new top reached
if( prch[i] >= topprc )
{
topprc = prch[i];
topidx = i;
trailarrayup[i] = Max( trailarrayup[i - 1], prch[i] - percfluc( topprc, downpercentage ) );
}
// continuation inside uptrend
else
{
trailarrayup[i] = Max( trailarrayup[i - 1], prch[i] - percfluc( prch[i], downpercentage ) );
}
}
else
if( trend < 0 )
{
// trend turning up, avoid same bar as the trough
if( prch[i] >= trailarraydn[i - 1] AND prcl[i] > botprc )
{
tr[botidx] = 1;
topprc = prch[i];
topidx = i;
trend = 1;
trailarrayup[i] = topprc - percfluc( topprc, downpercentage );
trailarraydn[i] = trailarraydn[i - 1];

if( priceswitch )
BuyPrice[i] = Max( O[i], trailarraydn[i] );
else
}
else

// still in downtrend and new trough reached
if( prcl[i] <= botprc )
{
botprc = prcl[i];
botidx = i;
trailarraydn[i] = Min( trailarraydn[i - 1], prcl[i] + percfluc( botprc, uppercentage ) );
}
// continuation inside downtrend
else
{
trailarraydn[i] = Min( trailarraydn[i - 1], prcl[i] + percfluc( prcl[i], uppercentage ) );
}
}
}
}

function calculateZigZag()
{
// 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 );
}

function calculateLastSegments( )
{
line1 = line2 = Null;
lastidxpk = LastValue( ValueWhen( pk, bi ) );
lastidxtr = LastValue( ValueWhen( tr, bi ) );
lastvalpk = LastValue( ValueWhen( pk, prch ) );
lastvaltr = LastValue( ValueWhen( tr, prcl ) );
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 ) );

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 ) );
}

ZigZag = IIf( !IsEmpty( line1 ), line1, ZigZag );
}

SetChartBkColor( ColorRGB( 0, 0, 0 ) );
SetChartOptions( 0, chartShowArrows | chartShowDates );
Plot( C, "Price", colorWhite, styleCandle, Null, Null, 0, 0, 0 );

calculatePivots();
calculateZigZag();
calculateLastSegments();

Plot( zigzag, "ZigZag", colorGold, styleLine | styleNoLabel | styleNoRescale, Null, Null, 0, 1, 1 );
PlotShapes( shapeSmallCircle * tr, colorGreen, 0, L, -10 );
PlotShapes( shapeSmallCircle * pk, colorRed, 0, H, 10 );

if( showUpDnSwing )
{
sz = 8;
ft = "Arial Black";
PlotShapes( shapeSmallUpTriangle * Buy, colorAqua, 0, L, -20 );
PlotShapes( shapeSmallDownTriangle * Sell, colorGold, 0, H, -20 );
//PlotShapes( shapeSmallCircle * Buy, colorAqua, 1, Max( O, trailarraydn ), 0 );
//PlotShapes( shapeSmallCircle * Sell, colorGold, 1, Min( O, trailarrayup ), 0 );
PlotShapes( shapeSmallCircle * Sell, colorGold, 0, SellPrice, 0 );

Short = Sell;
ShortPrice = SellPrice;

ShortPrice = ValueWhen( Short, ShortPrice );
CoverPrice = ValueWhen( Cover, CoverPrice );
SellPrice = ValueWhen( Sell, SellPrice );

longResult = Nz( Prec( IIf( Sell, SellPrice - ValueWhen( Buy, BuyPrice ), 0 ), 2 ) );
shortResult = Nz( Prec( IIf( Cover, ValueWhen( Short, ShortPrice ) - CoverPrice, 0 ), 2 ) );
totalResult = LastValue( Cum( longResult ) + Cum( shortResult ) );
//_TRACE( "tot: " + totalResult );

clr = colorDefault;
GfxSetZOrder( 0 );
GfxSetCoordsMode( 1 );
shiftLabels = 10;//Param( "Shift Labels", 10, -20, 100, 1 );
upColor = colorAqua;
dnColor = colorGold;

if( labelsswitchSwing )
{
for( i = fvb; i <= lvb; i++ )
{
{
str = "Buy: " + BuyPrice[i] + " (" + shortResult[i] + ")";
PlotTextSetFont( str, ft, sz, i, L[i], upColor, clr, -35 - shiftLabels );
//str = "Cover: " + CoverPrice[i] + " (" + shortResult[i] + ")";
//PlotTextSetFont( str, ft, sz, i, L[i], upColor, clr, -50 - shiftLabels );
}

{
str = "Cover: " + CoverPrice[i] + " (" + shortResult[i] + ")";
PlotTextSetFont( str, ft, sz, i, L[i], upColor, clr, -35 - shiftLabels );
}

{
PlotTextSetFont( str, ft, sz, i, L[i], upColor, clr, -35 - shiftLabels );
}

if( Short[i] && Sell[i] )
{
str = "Short: " + ShortPrice[i] + " (" + longResult[i] + ")";
PlotTextSetFont( str, ft, sz, i, H[i], dnColor, clr, 25 + shiftLabels );
//str = "Sell: " + SellPrice[i] + " (" + longResult[i] + ")";
//PlotTextSetFont( str, ft, sz, i, H[i], dnColor, clr, 40 + shiftLabels );
}

if( !Short[i] && Sell[i] )
{
str = "Sell: " + SellPrice[i] + " (" + longResult[i] + ")";
PlotTextSetFont( str, ft, sz, i, H[i], dnColor, clr, 25 + shiftLabels );
}

if( Short[i] && !Sell[i] )
{
str = "Short: " + ShortPrice[i];
PlotTextSetFont( str, ft, sz, i, H[i], dnColor, clr, 25 + shiftLabels );
}
}
}

if( showTrailline )
{
Plot( trailarrayup, "trail up", colorLightBlue, styleStaircase | styleNoRescale | styleNoLabel, Null, Null, 0, 1, 1 );

if( !IsEmpty( trailarrayup[BarCount - 1] ) )
{
PlotTextSetFont( "" + trailarrayup[BarCount - 1 ], ft, sz, BarCount + 1, trailarrayup[BarCount - 1], colorLightBlue, clr, 0 );
}

Plot( trailarraydn, "trail dn", colorOrange, styleStaircase | styleNoRescale | styleNoLabel, Null, Null, 0, 1, 1 );

if( !IsEmpty( trailarraydn[BarCount - 1] ) )
{
PlotTextSetFont( "" + trailarraydn[BarCount - 1], ft, sz, BarCount + 1, trailarraydn[BarCount - 1], colorOrange, clr, 0 );
}
}
}
``````
8 Likes

here is a version with a "variable percentage". In this case I based it on the ATR. So basically what you get are ATR pivots expressed in percentages. I like this better because you get a similar ZigZag profile when you switch between timeframes

``````period = Param( "Period", 100, 5, 100, 1 );
uppercentageFactor = Param( "Upward Zig Factor", 2, 0.1, 10, 0.1 );
downpercentageFactor = Param( "Downward Zig Factor", 2, 0.1, 10, 0.1 );
priceswitch = ParamToggle( "Use Close or High and Low price", "Use Close|Use High and Low", 0 );
showUpDnSwing = 1;//ParamToggle( "Show Up/Down Swing", "Off|On", 0 );
labelsswitchswing = ParamToggle( "Show Labels", "Off|On", 1 );
showTrailline = ParamToggle( "Show Trail Line", "Off|On", 1 );

// build variable percentage array
//variablePercentage = StDev( 100 * ( H - L ) / ( ( H + L ) / 2 ), period );
variablePercentage = ATR( period ) / MA( C, period ) * 100;
uppercentage = uppercentageFactor * Ref( variablePercentage, -1 );
downpercentage = downpercentageFactor * Ref( variablePercentage, -1 );

bi = BarIndex();
fvb = FirstVisibleValue( bi );
lvb = LastVisibleValue( bi );
pk = tr = Buy = Sell = BuyPrice = SellPrice = 0;
ZigZag = line1 = line2 = Null;
trailarrayup = Null;
trailarraydn = Null;
mode = "";
SetBarsRequired( ( lvb - fvb ) * 2 );

if( priceswitch )
{
prch = H;
prcl = L;
mode = "High/Low price";
}
else
{
prch = C;
prcl = C;
mode = "Close price";
}

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

function percfluc( prc, perc )
{
retprice = round( ( prc * perc / 100 ) / TickSize ) * TickSize;
return retprice;
}

function calculatePivots()
{
// initial condition trend is up (but -1 works also)
trend = 1;
topprc = prch[0];
topidx = 0;
botprc = prcl[0];
botidx = 0;
trailarrayup[period] = topprc - percfluc( topprc, downpercentage[period] );
trailarraydn[period] = botprc + percfluc( botprc, uppercentage[period] );

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

if( priceswitch )
SellPrice[i] = Min( O[i], trailarrayup[i] );
else
SellPrice[i] = C[i];
}
else

// still in uptrend and new top reached
if( prch[i] >= topprc )
{
topprc = prch[i];
topidx = i;
trailarrayup[i] = Max( trailarrayup[i - 1], prch[i] - percfluc( topprc, downpercentage[i] ) );
}
// continuation inside uptrend
else
{
trailarrayup[i] = Max( trailarrayup[i - 1], prch[i] - percfluc( prch[i], downpercentage[i] ) );
}
}
else
if( trend < 0 )
{
// trend turning up, avoid same bar as the trough
if( prch[i] >= trailarraydn[i - 1] AND prcl[i] > botprc )
{
tr[botidx] = 1;
topprc = prch[i];
topidx = i;
trend = 1;
trailarrayup[i] = topprc - percfluc( topprc, downpercentage[i] );
trailarraydn[i] = trailarraydn[i - 1];

if( priceswitch )
BuyPrice[i] = Max( O[i], trailarraydn[i] );
else
}
else

// still in downtrend and new trough reached
if( prcl[i] <= botprc )
{
botprc = prcl[i];
botidx = i;
trailarraydn[i] = Min( trailarraydn[i - 1], prcl[i] + percfluc( botprc, uppercentage[i] ) );
}
// continuation inside downtrend
else
{
trailarraydn[i] = Min( trailarraydn[i - 1], prcl[i] + percfluc( prcl[i], uppercentage[i] ) );
}
}
}
}

function calculateZigZag()
{
// 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 );
}

function calculateLastSegments( )
{
line1 = line2 = Null;
lastidxpk = LastValue( ValueWhen( pk, bi ) );
lastidxtr = LastValue( ValueWhen( tr, bi ) );
lastvalpk = LastValue( ValueWhen( pk, prch ) );
lastvaltr = LastValue( ValueWhen( tr, prcl ) );
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 ) );

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 ) );
}

ZigZag = IIf( !IsEmpty( line1 ), line1, ZigZag );
}

SetChartBkColor( ColorRGB( 0, 0, 0 ) );
SetChartOptions( 0, chartShowArrows | chartShowDates );
Plot( C, "Price", colorWhite, styleCandle, Null, Null, 0, 0, 0 );

calculatePivots();
calculateZigZag();
calculateLastSegments();

Plot( zigzag, "ZigZag", colorGold, styleLine | styleNoLabel | styleNoRescale, Null, Null, 0, 1, 1 );
PlotShapes( shapeSmallCircle * tr, colorGreen, 0, L, -10 );
PlotShapes( shapeSmallCircle * pk, colorRed, 0, H, 10 );

if( showUpDnSwing )
{
sz = 8;
ft = "Arial Black";
PlotShapes( shapeSmallUpTriangle * Buy, colorAqua, 0, L, -20 );
PlotShapes( shapeSmallDownTriangle * Sell, colorGold, 0, H, -20 );
PlotShapes( shapeSmallCircle * Sell, colorGold, 0, SellPrice, 0 );

Short = Sell;
ShortPrice = SellPrice;

ShortPrice = ValueWhen( Short, ShortPrice );
CoverPrice = ValueWhen( Cover, CoverPrice );
SellPrice = ValueWhen( Sell, SellPrice );

longResult = Nz( Prec( IIf( Sell, SellPrice - ValueWhen( Buy, BuyPrice ), 0 ), 2 ) );
shortResult = Nz( Prec( IIf( Cover, ValueWhen( Short, ShortPrice ) - CoverPrice, 0 ), 2 ) );
totalResult = LastValue( Cum( longResult ) + Cum( shortResult ) );

clr = colorDefault;
GfxSetZOrder( 0 );
GfxSetCoordsMode( 1 );
shiftLabels = 10;//Param( "Shift Labels", 10, -20, 100, 1 );
upColor = colorAqua;
dnColor = colorGold;

if( labelsswitchSwing )
{
for( i = fvb; i <= lvb; i++ )
{
{
str = "Buy: " + BuyPrice[i] + " (" + shortResult[i] + ")";
PlotTextSetFont( str, ft, sz, i, L[i], upColor, clr, -35 - shiftLabels );
//str = "Cover: " + CoverPrice[i] + " (" + shortResult[i] + ")";
//PlotTextSetFont( str, ft, sz, i, L[i], upColor, clr, -50 - shiftLabels );
}

{
str = "Cover: " + CoverPrice[i] + " (" + shortResult[i] + ")";
PlotTextSetFont( str, ft, sz, i, L[i], upColor, clr, -35 - shiftLabels );
}

{
PlotTextSetFont( str, ft, sz, i, L[i], upColor, clr, -35 - shiftLabels );
}

if( Short[i] && Sell[i] )
{
str = "Short: " + ShortPrice[i] + " (" + longResult[i] + ")";
PlotTextSetFont( str, ft, sz, i, H[i], dnColor, clr, 25 + shiftLabels );
//str = "Sell: " + SellPrice[i] + " (" + longResult[i] + ")";
//PlotTextSetFont( str, ft, sz, i, H[i], dnColor, clr, 40 + shiftLabels );
}

if( !Short[i] && Sell[i] )
{
str = "Sell: " + SellPrice[i] + " (" + longResult[i] + ")";
PlotTextSetFont( str, ft, sz, i, H[i], dnColor, clr, 25 + shiftLabels );
}

if( Short[i] && !Sell[i] )
{
str = "Short: " + ShortPrice[i];
PlotTextSetFont( str, ft, sz, i, H[i], dnColor, clr, 25 + shiftLabels );
}
}
}

if( showTrailline )
{
Plot( trailarrayup, "trail up", colorLightBlue, styleDots | styleStaircase | styleNoRescale | styleNoLabel, Null, Null, 0, 1, 1 );

if( !IsEmpty( trailarrayup[BarCount - 1] ) )
{
PlotTextSetFont( "" + trailarrayup[BarCount - 1 ], ft, sz, BarCount + 1, trailarrayup[BarCount - 1], colorLightBlue, clr, 0 );
}

Plot( trailarraydn, "trail dn", colorOrange, styleDots | styleStaircase | styleNoRescale | styleNoLabel, Null, Null, 0, 1, 1 );

if( !IsEmpty( trailarraydn[BarCount - 1] ) )
{
PlotTextSetFont( "" + trailarraydn[BarCount - 1], ft, sz, BarCount + 1, trailarraydn[BarCount - 1], colorOrange, clr, 0 );
}
}
}

Title =
"Price: " + C
+ EncodeColor( colorGold ) + " | ZigZag: " + ZigZag
+ EncodeColor( colorBrightGreen ) + " | Up Percentage (%): " + Prec( uppercentage, 2 )
+ EncodeColor( colorRed ) + " | Down Percentage (%): " + Prec( downpercentage, 2 )
+ EncodeColor( colorLightBlue ) + " | Trail Array Up: " + trailarrayup
+ EncodeColor( colorOrange ) + " | Trail Array Down: " + trailarraydn;

``````
13 Likes

Dear Mr. Pottasch,

I am bowled over. I never expected a coded solution and you have provided not one but two. The tracing of the reversal levels is a very nice touch. I plan to study the ATR version carefully, could be a nice solution. Bravo! Dinner and drinks on me.

A little pay back: When I coded PatternPower I calculated the average up and down swings and used those values to set the zig zag parameters. That worked really well.

Best,

`` John``
1 Like

thanks. I will look into PatternPower.

I posted similar code so this code is just a small adjustment. When using the Close price then the buy/sell signal is at the close. However, if you cheat and assume you will be able to buy at the price of the trail lines itself (which of course is looking in the future) then it is hugely profitable. And quite often you will be able to buy/sell at that price. Problem is not always and you do not know when that will be. You will have to wait until the signal is valid and then hope the price will move back to the trail line or better.

top chart is ES-mini 5min data where I buy/sell/short/cover at the trailline itself. The chart below that is a backtest. So if you are able to enter /exit at the trail line on average then that would give a good profit

2 Likes

FWIW: Any zig-zag is prone to future leak unless you wait for last leg to stabilize as shown in the Traders Tips

1 Like

hi Tomasz, yes but the buy/sell signals in my code are not looking into the future (in the Close mode). You can do a playback and see for yourself. Only point I make is that the code has 2 modes (Using the Close mode or the High/Low mode). When using mode 1, the close price mode, then the signal is only valid at the close. So you have to wait until the end of the bar else the signal still may disappear. The equity curve I show is cheating in that I do not use the close price as an entry/exit but I use this:

``````BuyPrice = Max( O, trailarraydn );
SellPrice = Min( O, trailarrayup );
ShortPrice = SellPrice;
``````

it is cheating but it shows that if you are able to enter at the trail-line on average then you can make good money. I point out that in the majority of cases you will be able to enter at the trail line or better. Unfortunately there are also cases the price does not pull-back

2 Likes

That is a cogent observation Tomasz. I first worked on the issue when studying Art Merrill's Filtered Waves many years ago. Later when working with HIPs and LOPs (HIgh Points and LOw Points defined as extremes surrounded by lesser extremes) to define turning points I encountered it again. One simply has to note when the element was knowable and not act until it is known even though it references an earlier point. I recall using a new analytical system that reversed time the reference notation from what I was used to and developing a really super duper system only to discover on closer inspection that it had a massive future leak. Crushed, I was.

Thanks for AB and all you do Tomasz,

`` John``
1 Like

HIPs and LOPs are great tools for identifying swings. They have what I call oders, that is the number of bars on either side of the extreme needed to identify a pattern. I typically use orders of two or three. For a LOP order of 2, two higher lows are needed on either side of the nadir. Orders make is easy to deal with the future leaks, you simply need to wait for the order number of of bars, before you can act on a signal when back testing.

`` John``