private static void DrawZigZagLine <TQuote>(List <ZigZagResult> results, List <TQuote> historyList, ZigZagPoint lastPoint, ZigZagPoint nextPoint) where TQuote : IQuote { decimal increment = (nextPoint.Value - lastPoint.Value) / (nextPoint.Index - lastPoint.Index); // add new line segment for (int i = lastPoint.Index; i < nextPoint.Index; i++) { TQuote h = historyList[i]; int index = i + 1; ZigZagResult result = new ZigZagResult { Date = h.Date, ZigZag = (lastPoint.Index != 1 || index == nextPoint.Index) ? lastPoint.Value + increment * (index - lastPoint.Index) : null, PointType = (index == nextPoint.Index) ? nextPoint.PointType : null }; results.Add(result); } // reset lastpoint lastPoint.Index = nextPoint.Index; lastPoint.Value = nextPoint.Value; lastPoint.PointType = nextPoint.PointType; }
private static void DrawZigZagLine(List <ZigZagResult> results, List <Quote> historyList, ZigZagPoint lastPoint, ZigZagPoint nextPoint) { // initialize List <ZigZagResult> newResults = new List <ZigZagResult>(); List <Quote> period = historyList .Where(x => x.Index > lastPoint.Index && x.Index <= nextPoint.Index) .ToList(); decimal increment = (nextPoint.Value - lastPoint.Value) / (nextPoint.Index - lastPoint.Index); // add new line segment foreach (Quote h in period) { ZigZagResult result = new ZigZagResult { Index = (int)h.Index, Date = h.Date, ZigZag = (lastPoint.Index != 1 || h.Index == nextPoint.Index) ? lastPoint.Value + increment * (h.Index - lastPoint.Index) : null, PointType = ((int)h.Index == nextPoint.Index) ? nextPoint.PointType : null }; results.Add(result); } // reset lastpoint lastPoint.Index = nextPoint.Index; lastPoint.Value = nextPoint.Value; lastPoint.PointType = nextPoint.PointType; }
private static void DrawRetraceLine(List <ZigZagResult> results, string lastDirection, ZigZagPoint lastLowPoint, ZigZagPoint lastHighPoint, ZigZagPoint nextPoint) { bool isHighLine = (lastDirection == "L"); ZigZagPoint priorPoint = new(); // handle type and reset last point if (isHighLine) { priorPoint.Index = lastHighPoint.Index; priorPoint.Value = lastHighPoint.Value; lastHighPoint.Index = nextPoint.Index; lastHighPoint.Value = nextPoint.Value; } else { priorPoint.Index = lastLowPoint.Index; priorPoint.Value = lastLowPoint.Value; lastLowPoint.Index = nextPoint.Index; lastLowPoint.Value = nextPoint.Value; } // nothing to do if first line if (priorPoint.Index == 1) { return; } // handle error case if (nextPoint.Index == priorPoint.Index) { return; } // narrow to period decimal increment = (nextPoint.Value - priorPoint.Value) / (nextPoint.Index - priorPoint.Index); // add new line segment //foreach (ZigZagResult r in period) for (int i = priorPoint.Index - 1; i < nextPoint.Index; i++) { ZigZagResult r = results[i]; int index = i + 1; if (isHighLine) { r.RetraceHigh = priorPoint.Value + increment * (index - priorPoint.Index); } else { r.RetraceLow = priorPoint.Value + increment * (index - priorPoint.Index); } } }
// 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); }