private static ZigZagEval GetZigZagEval <TQuote>(ZigZagType type, int index, TQuote q) where TQuote : IQuote { ZigZagEval eval = new ZigZagEval() { Index = index }; // consider `type` switch (type) { case ZigZagType.Close: eval.Low = q.Close; eval.High = q.Close; break; case ZigZagType.HighLow: eval.Low = q.Low; eval.High = q.High; break; } return(eval); }
private static ZigZagEval GetZigZagEval(ZigZagType type, Quote q) { ZigZagEval eval = new ZigZagEval() { Index = (int)q.Index }; // consider `type` switch (type) { case ZigZagType.Close: eval.Low = q.Close; eval.High = q.Close; break; case ZigZagType.HighLow: eval.Low = q.Low; eval.High = q.High; break; } return(eval); }
// ZIG ZAG public static IEnumerable <ZigZagResult> GetZigZag <TQuote>( IEnumerable <TQuote> history, ZigZagType type = ZigZagType.Close, decimal percentChange = 5) where TQuote : IQuote { // clean quotes List <TQuote> historyList = history.Sort(); // check parameters ValidateZigZag(history, percentChange); // initialize List <ZigZagResult> results = new List <ZigZagResult>(historyList.Count); decimal changeThreshold = percentChange / 100m; TQuote firstQuote = historyList[0]; ZigZagEval eval = GetZigZagEval(type, 1, firstQuote); ZigZagPoint lastPoint = new ZigZagPoint { Index = eval.Index, Value = firstQuote.Close, PointType = "U" }; ZigZagPoint lastHighPoint = new ZigZagPoint { Index = eval.Index, Value = eval.High, PointType = "H" }; ZigZagPoint lastLowPoint = new ZigZagPoint { Index = eval.Index, Value = eval.Low, PointType = "L" }; int finalPointIndex = historyList.Count; // roll through history until to find initial trend for (int i = 0; i < historyList.Count; i++) { TQuote h = historyList[i]; int index = i + 1; eval = GetZigZagEval(type, index, h); decimal changeUp = (eval.High - lastLowPoint.Value) / lastLowPoint.Value; decimal changeDn = (lastHighPoint.Value - eval.Low) / lastHighPoint.Value; if (changeUp >= changeThreshold && changeUp > changeDn) { lastPoint.Index = lastLowPoint.Index; lastPoint.Value = lastLowPoint.Value; lastPoint.PointType = lastLowPoint.PointType; break; } if (changeDn >= changeThreshold && changeDn > changeUp) { lastPoint.Index = lastHighPoint.Index; lastPoint.Value = lastHighPoint.Value; lastPoint.PointType = lastHighPoint.PointType; break; } } // add first point to results ZigZagResult firstResult = new ZigZagResult { Date = firstQuote.Date }; results.Add(firstResult); // find and draw lines while (lastPoint.Index < finalPointIndex) { ZigZagPoint nextPoint = EvaluateNextPoint(historyList, type, changeThreshold, lastPoint); string lastDirection = lastPoint.PointType; // draw line (and reset last point) DrawZigZagLine(results, historyList, lastPoint, nextPoint); // draw retrace line (and reset last high/low point) DrawRetraceLine(results, lastDirection, lastLowPoint, lastHighPoint, nextPoint); } return(results); }
private static ZigZagPoint EvaluateNextPoint <TQuote>(List <TQuote> historyList, ZigZagType type, decimal changeThreshold, ZigZagPoint lastPoint) where TQuote : IQuote { // initialize bool trendUp = (lastPoint.PointType == "L"); decimal?change = 0; ZigZagPoint extremePoint = new ZigZagPoint { Index = lastPoint.Index, Value = lastPoint.Value, PointType = trendUp ? "H" : "L" }; // find extreme point before reversal point for (int i = lastPoint.Index; i < historyList.Count; i++) { TQuote h = historyList[i]; int index = i + 1; ZigZagEval eval = GetZigZagEval(type, index, h); // reset extreme point switch (trendUp) { case true: if (eval.High >= extremePoint.Value) { extremePoint.Index = eval.Index; extremePoint.Value = eval.High; } else { change = (extremePoint.Value == 0) ? null : (extremePoint.Value - eval.Low) / extremePoint.Value; } break; case false: if (eval.Low <= extremePoint.Value) { extremePoint.Index = eval.Index; extremePoint.Value = eval.Low; } else { change = (extremePoint.Value == 0) ? null : (eval.High - extremePoint.Value) / extremePoint.Value; } break; } // return extreme point when deviation threshold met if (change >= changeThreshold) { return(extremePoint); } } // handle last unconfirmed point int finalPointIndex = historyList.Count; if (extremePoint.Index == finalPointIndex && change < changeThreshold) { extremePoint.PointType = null; } return(extremePoint); }
// ZIG ZAG /// <include file='./info.xml' path='indicator/*' /> /// public static IEnumerable <ZigZagResult> GetZigZag <TQuote>( IEnumerable <TQuote> history, ZigZagType type = ZigZagType.Close, decimal percentChange = 5) where TQuote : IQuote { // sort history List <TQuote> historyList = history.Sort(); // check parameter arguments ValidateZigZag(history, percentChange); // initialize List <ZigZagResult> results = new(historyList.Count); decimal changeThreshold = percentChange / 100m; TQuote firstQuote = historyList[0]; ZigZagEval eval = GetZigZagEval(type, 1, firstQuote); ZigZagPoint lastPoint = new() { Index = eval.Index, Value = firstQuote.Close, PointType = "U" }; ZigZagPoint lastHighPoint = new() { Index = eval.Index, Value = eval.High, PointType = "H" }; ZigZagPoint lastLowPoint = new() { Index = eval.Index, Value = eval.Low, PointType = "L" }; int finalPointIndex = historyList.Count; // roll through history, to find initial trend for (int i = 0; i < historyList.Count; i++) { TQuote h = historyList[i]; int index = i + 1; eval = GetZigZagEval(type, index, h); decimal?changeUp = (lastLowPoint.Value == 0) ? null : (eval.High - lastLowPoint.Value) / lastLowPoint.Value; decimal?changeDn = (lastHighPoint.Value == 0) ? null : (lastHighPoint.Value - eval.Low) / lastHighPoint.Value; if (changeUp >= changeThreshold && changeUp > changeDn) { lastPoint.Index = lastLowPoint.Index; lastPoint.Value = lastLowPoint.Value; lastPoint.PointType = lastLowPoint.PointType; break; } if (changeDn >= changeThreshold && changeDn > changeUp) { lastPoint.Index = lastHighPoint.Index; lastPoint.Value = lastHighPoint.Value; lastPoint.PointType = lastHighPoint.PointType; break; } } // add first point to results ZigZagResult firstResult = new() { Date = firstQuote.Date }; results.Add(firstResult); // find and draw lines while (lastPoint.Index < finalPointIndex) { ZigZagPoint nextPoint = EvaluateNextPoint(historyList, type, changeThreshold, lastPoint); string lastDirection = lastPoint.PointType; // draw line (and reset last point) DrawZigZagLine(results, historyList, lastPoint, nextPoint); // draw retrace line (and reset last high/low point) DrawRetraceLine(results, lastDirection, lastLowPoint, lastHighPoint, nextPoint); } return(results); } private static ZigZagPoint EvaluateNextPoint <TQuote>( List <TQuote> historyList, ZigZagType type, decimal changeThreshold, ZigZagPoint lastPoint) where TQuote : IQuote { // initialize bool trendUp = (lastPoint.PointType == "L"); decimal?change = 0; ZigZagPoint extremePoint = new() { Index = lastPoint.Index, Value = lastPoint.Value, PointType = trendUp ? "H" : "L" }; // find extreme point before reversal point for (int i = lastPoint.Index; i < historyList.Count; i++) { TQuote h = historyList[i]; int index = i + 1; ZigZagEval eval = GetZigZagEval(type, index, h); // reset extreme point if (trendUp) { if (eval.High >= extremePoint.Value) { extremePoint.Index = eval.Index; extremePoint.Value = eval.High; } else { change = (extremePoint.Value == 0) ? null : (extremePoint.Value - eval.Low) / extremePoint.Value; } } else { if (eval.Low <= extremePoint.Value) { extremePoint.Index = eval.Index; extremePoint.Value = eval.Low; } else { change = (extremePoint.Value == 0) ? null : (eval.High - extremePoint.Value) / extremePoint.Value; } } // return extreme point when deviation threshold met if (change >= changeThreshold) { return(extremePoint); } } // handle last unconfirmed point int finalPointIndex = historyList.Count; if (extremePoint.Index == finalPointIndex && change < changeThreshold) { extremePoint.PointType = null; } return(extremePoint); } private static void DrawZigZagLine <TQuote>(List <ZigZagResult> results, List <TQuote> historyList,
private static ZigZagPoint EvaluateNextPoint(List <Quote> historyList, ZigZagType type, decimal changeThreshold, ZigZagPoint lastPoint) { // initialize bool trendUp = (lastPoint.PointType == "L"); decimal change = 0; ZigZagEval eval = new ZigZagEval(); ZigZagPoint extremePoint = new ZigZagPoint { Index = lastPoint.Index, Value = lastPoint.Value, PointType = trendUp ? "H" : "L" }; List <Quote> period = historyList .Where(x => x.Index > lastPoint.Index) .ToList(); // find extreme point before reversal point foreach (Quote h in period) { eval = GetZigZagEval(type, h); // reset extreme point switch (trendUp) { case true: if (eval.High >= extremePoint.Value) { extremePoint.Index = eval.Index; extremePoint.Value = eval.High; } else { change = (extremePoint.Value - eval.Low) / extremePoint.Value; } break; case false: if (eval.Low <= extremePoint.Value) { extremePoint.Index = eval.Index; extremePoint.Value = eval.Low; } else { change = (eval.High - extremePoint.Value) / extremePoint.Value; } break; } // return extreme point when deviation threshold met if (change >= changeThreshold) { return(extremePoint); } } // handle last unconfirmed point int finalPointIndex = historyList.Select(x => (int)x.Index).Max(); if (extremePoint.Index == finalPointIndex && change < changeThreshold) { extremePoint.PointType = null; } return(extremePoint); }