// PARABOLIC SAR public static IEnumerable <ParabolicSarResult> GetParabolicSar( IEnumerable <Quote> history, decimal accelerationStep = (decimal)0.02, decimal maxAccelerationFactor = (decimal)0.2) { // clean quotes history = Cleaners.PrepareHistory(history); // initialize List <ParabolicSarResult> results = new List <ParabolicSarResult>(); Quote first = history.Where(x => x.Index == 1).FirstOrDefault(); decimal accelerationFactor = accelerationStep; decimal extremePoint = first.High; decimal priorSar = first.Low; bool isRising = true; // roll through history foreach (Quote h in history) { ParabolicSarResult result = new ParabolicSarResult { Index = (int)h.Index, Date = h.Date }; // skip first one if (h.Index == 1) { results.Add(result); continue; } // was rising if (isRising) { decimal currentSar = priorSar + accelerationFactor * (extremePoint - priorSar); // turn down if (h.Low < currentSar) { result.IsReversal = true; result.Sar = extremePoint; isRising = false; accelerationFactor = accelerationStep; extremePoint = h.Low; } // continue rising else { result.IsReversal = false; result.Sar = currentSar; // SAR cannot be higher than last two lows decimal minLastTwo = history.Where(x => x.Index >= h.Index - 2 && x.Index < h.Index).Select(x => x.Low).Min(); result.Sar = Math.Min((decimal)result.Sar, minLastTwo); if (h.High > extremePoint) { extremePoint = h.High; accelerationFactor = Math.Min(accelerationFactor += accelerationStep, maxAccelerationFactor); } } } // was falling else { decimal currentSar = priorSar - accelerationFactor * (priorSar - extremePoint); // turn up if (h.High > currentSar) { result.IsReversal = true; result.Sar = extremePoint; isRising = true; accelerationFactor = accelerationStep; extremePoint = h.High; } // continue falling else { result.IsReversal = false; result.Sar = currentSar; // SAR cannot be lower than last two highs decimal maxLastTwo = history.Where(x => x.Index >= h.Index - 2 && x.Index < h.Index).Select(x => x.High).Max(); result.Sar = Math.Max((decimal)result.Sar, maxLastTwo); if (h.Low < extremePoint) { extremePoint = h.Low; accelerationFactor = Math.Min(accelerationFactor += accelerationStep, maxAccelerationFactor); } } } result.IsRising = isRising; priorSar = (decimal)result.Sar; results.Add(result); } return(results); }
// PARABOLIC SAR public static IEnumerable <ParabolicSarResult> GetParabolicSar <TQuote>( IEnumerable <TQuote> history, decimal accelerationStep = (decimal)0.02, decimal maxAccelerationFactor = (decimal)0.2) where TQuote : IQuote { // clean quotes List <TQuote> historyList = history.Sort(); // check parameters ValidateParabolicSar(history, accelerationStep, maxAccelerationFactor); // initialize List <ParabolicSarResult> results = new List <ParabolicSarResult>(historyList.Count); TQuote first = historyList[0]; decimal accelerationFactor = accelerationStep; decimal extremePoint = first.High; decimal priorSar = first.Low; bool isRising = true; // initial guess // roll through history for (int i = 0; i < historyList.Count; i++) { TQuote h = historyList[i]; ParabolicSarResult result = new ParabolicSarResult { Date = h.Date }; // skip first one if (i == 0) { results.Add(result); continue; } // was rising if (isRising) { decimal currentSar = priorSar + accelerationFactor * (extremePoint - priorSar); // turn down if (h.Low < currentSar) { result.IsReversal = true; result.Sar = extremePoint; isRising = false; accelerationFactor = accelerationStep; extremePoint = h.Low; } // continue rising else { result.IsReversal = false; result.Sar = currentSar; // SAR cannot be higher than last two lows if (i >= 2) { decimal minLastTwo = Math.Min(historyList[i - 1].Low, historyList[i - 2].Low); result.Sar = Math.Min((decimal)result.Sar, minLastTwo); } else { result.Sar = (decimal)result.Sar; } if (h.High > extremePoint) { extremePoint = h.High; accelerationFactor = Math.Min(accelerationFactor += accelerationStep, maxAccelerationFactor); } } } // was falling else { decimal currentSar = priorSar - accelerationFactor * (priorSar - extremePoint); // turn up if (h.High > currentSar) { result.IsReversal = true; result.Sar = extremePoint; isRising = true; accelerationFactor = accelerationStep; extremePoint = h.High; } // continue falling else { result.IsReversal = false; result.Sar = currentSar; // SAR cannot be lower than last two highs if (i >= 2) { decimal maxLastTwo = Math.Max(historyList[i - 1].High, historyList[i - 2].High); result.Sar = Math.Max((decimal)result.Sar, maxLastTwo); } else { result.Sar = (decimal)result.Sar; } if (h.Low < extremePoint) { extremePoint = h.Low; accelerationFactor = Math.Min(accelerationFactor += accelerationStep, maxAccelerationFactor); } } } priorSar = (decimal)result.Sar; results.Add(result); } // remove first trend to reversal, since it is an invalid guess ParabolicSarResult firstReversal = results .Where(x => x.IsReversal == true) .OrderBy(x => x.Date) .FirstOrDefault(); if (firstReversal != null) { int cutIndex = results.IndexOf(firstReversal); for (int d = 0; d <= cutIndex; d++) { ParabolicSarResult r = results[d]; r.Sar = null; r.IsReversal = null; } } return(results); }