private static List <ConnorsRsiResult> CalcConnorsRsiBaseline( List <BasicData> bdList, int rsiPeriod, int rankPeriod) { // initialize List <RsiResult> rsiResults = CalcRsi(bdList, rsiPeriod).ToList(); int size = bdList.Count; List <ConnorsRsiResult> results = new List <ConnorsRsiResult>(size); decimal?[] gain = new decimal?[size]; decimal?lastClose = null; decimal streak = 0; // compose interim results for (int i = 0; i < size; i++) { BasicData h = bdList[i]; int index = i + 1; ConnorsRsiResult result = new ConnorsRsiResult { Date = h.Date, RsiClose = rsiResults[i].Rsi }; // bypass for first record if (lastClose == null) { lastClose = h.Value; results.Add(result); continue; } // streak of up or down if (h.Value == lastClose) { streak = 0; } else if (h.Value > lastClose) { if (streak >= 0) { streak++; } else { streak = 1; } } else // h.Value < lastClose { if (streak <= 0) { streak--; } else { streak = -1; } } result.Streak = streak; // percentile rank gain[i] = (lastClose == 0) ? null : (decimal)((lastClose <= 0) ? null : (h.Value - lastClose) / lastClose); results.Add(result); if (index > rankPeriod) { int qty = 0; for (int p = index - rankPeriod - 1; p < index; p++) { if (gain[p] < gain[i]) { qty++; } } result.PercentRank = 100m * qty / rankPeriod; } lastClose = h.Value; } return(results); }
private static IEnumerable <RsiResult> CalcRsi(IEnumerable <BasicData> basicData, int lookbackPeriod = 14) { // clean data List <BasicData> bdList = Cleaners.PrepareBasicData(basicData).ToList(); // check parameters ValidateRsi(basicData, lookbackPeriod); // initialize decimal lastValue = bdList[0].Value; List <RsiResult> results = new List <RsiResult>(); // load gain data for (int i = 0; i < bdList.Count; i++) { BasicData h = bdList[i]; RsiResult result = new RsiResult { Index = (int)h.Index, Date = h.Date, Gain = (h.Value > lastValue) ? h.Value - lastValue : 0, Loss = (h.Value < lastValue) ? lastValue - h.Value : 0 }; results.Add(result); lastValue = h.Value; } // initialize average gain decimal avgGain = results.Where(x => x.Index <= lookbackPeriod).Select(g => g.Gain).Average(); decimal avgLoss = results.Where(x => x.Index <= lookbackPeriod).Select(g => g.Loss).Average(); // initial first record decimal lastRSI = (avgLoss > 0) ? 100 - (100 / (1 + (avgGain / avgLoss))) : 100; RsiResult first = results.Where(x => x.Index == lookbackPeriod + 1).FirstOrDefault(); first.Rsi = lastRSI; // calculate RSI foreach (RsiResult r in results.Where(x => x.Index > (lookbackPeriod + 1))) { avgGain = (avgGain * (lookbackPeriod - 1) + r.Gain) / lookbackPeriod; avgLoss = (avgLoss * (lookbackPeriod - 1) + r.Loss) / lookbackPeriod; if (avgLoss > 0) { decimal rs = avgGain / avgLoss; r.Rsi = 100 - (100 / (1 + rs)); } else { r.Rsi = 100; } lastRSI = (decimal)r.Rsi; } return(results); }
// PRICE VOLUME OSCILLATOR (PVO) /// <include file='./info.xml' path='indicator/*' /> /// public static IEnumerable <PvoResult> GetPvo <TQuote>( IEnumerable <TQuote> history, int fastPeriod = 12, int slowPeriod = 26, int signalPeriod = 9) where TQuote : IQuote { // convert history to basic format List <BasicData> bdList = history.ConvertToBasic("V"); // check parameter arguments ValidatePvo(history, fastPeriod, slowPeriod, signalPeriod); // initialize List <EmaResult> emaFast = CalcEma(bdList, fastPeriod).ToList(); List <EmaResult> emaSlow = CalcEma(bdList, slowPeriod).ToList(); int size = bdList.Count; List <BasicData> emaDiff = new List <BasicData>(); List <PvoResult> results = new List <PvoResult>(size); // roll through history for (int i = 0; i < size; i++) { BasicData h = bdList[i]; EmaResult df = emaFast[i]; EmaResult ds = emaSlow[i]; PvoResult result = new PvoResult { Date = h.Date }; if (df?.Ema != null && ds?.Ema != null) { decimal?pvo = (ds.Ema != 0) ? 100 * (df.Ema - ds.Ema) / ds.Ema : null; result.Pvo = pvo; // temp data for interim EMA of PVO BasicData diff = new BasicData { Date = h.Date, Value = (decimal)pvo }; emaDiff.Add(diff); } results.Add(result); } // add signal and histogram to result List <EmaResult> emaSignal = CalcEma(emaDiff, signalPeriod).ToList(); for (int d = slowPeriod - 1; d < size; d++) { PvoResult r = results[d]; EmaResult ds = emaSignal[d + 1 - slowPeriod]; r.Signal = ds.Ema; r.Histogram = r.Pvo - r.Signal; } return(results); }
private static IEnumerable <RsiResult> CalcRsi(List <BasicData> bdList, int lookbackPeriod) { // check parameter arguments ValidateRsi(bdList, lookbackPeriod); // initialize decimal lastValue = bdList[0].Value; decimal avgGain = 0m; decimal avgLoss = 0m; int size = bdList.Count; List <RsiResult> results = new(size); decimal[] gain = new decimal[size]; // gain decimal[] loss = new decimal[size]; // loss // roll through history for (int i = 0; i < bdList.Count; i++) { BasicData h = bdList[i]; int index = i + 1; RsiResult r = new() { Date = h.Date }; results.Add(r); gain[i] = (h.Value > lastValue) ? h.Value - lastValue : 0; loss[i] = (h.Value < lastValue) ? lastValue - h.Value : 0; lastValue = h.Value; // calculate RSI if (index > lookbackPeriod + 1) { avgGain = (avgGain * (lookbackPeriod - 1) + gain[i]) / lookbackPeriod; avgLoss = (avgLoss * (lookbackPeriod - 1) + loss[i]) / lookbackPeriod; if (avgLoss > 0) { decimal rs = avgGain / avgLoss; r.Rsi = 100 - (100 / (1 + rs)); } else { r.Rsi = 100; } } // initialize average gain else if (index == lookbackPeriod + 1) { decimal sumGain = 0; decimal sumLoss = 0; for (int p = 1; p <= lookbackPeriod; p++) { sumGain += gain[p]; sumLoss += loss[p]; } avgGain = sumGain / lookbackPeriod; avgLoss = sumLoss / lookbackPeriod; r.Rsi = (avgLoss > 0) ? 100 - (100 / (1 + (avgGain / avgLoss))) : 100; } } return(results); }
// MOVING AVERAGE CONVERGENCE/DIVERGENCE (MACD) OSCILLATOR /// <include file='./info.xml' path='indicator/*' /> /// public static IEnumerable <MacdResult> GetMacd <TQuote>( this IEnumerable <TQuote> history, int fastPeriod = 12, int slowPeriod = 26, int signalPeriod = 9) where TQuote : IQuote { // convert history to basic format List <BasicData> bdList = history.ConvertToBasic("C"); // check parameter arguments ValidateMacd(history, fastPeriod, slowPeriod, signalPeriod); // initialize List <EmaResult> emaFast = CalcEma(bdList, fastPeriod).ToList(); List <EmaResult> emaSlow = CalcEma(bdList, slowPeriod).ToList(); int size = bdList.Count; List <BasicData> emaDiff = new(); List <MacdResult> results = new(size); // roll through history for (int i = 0; i < size; i++) { BasicData h = bdList[i]; EmaResult df = emaFast[i]; EmaResult ds = emaSlow[i]; MacdResult result = new() { Date = h.Date }; if (df?.Ema != null && ds?.Ema != null) { decimal macd = (decimal)df.Ema - (decimal)ds.Ema; result.Macd = macd; // temp data for interim EMA of macd BasicData diff = new() { Date = h.Date, Value = macd }; emaDiff.Add(diff); } results.Add(result); } // add signal and histogram to result List <EmaResult> emaSignal = CalcEma(emaDiff, signalPeriod).ToList(); for (int d = slowPeriod - 1; d < size; d++) { MacdResult r = results[d]; EmaResult ds = emaSignal[d + 1 - slowPeriod]; r.Signal = ds.Ema; r.Histogram = r.Macd - r.Signal; } return(results); }