private static List <StochResult> SmoothOscillator( List <StochResult> results, int lookbackPeriod, int smoothPeriod) { // temporarily store interim smoothed oscillator int smoothIndex = lookbackPeriod + smoothPeriod - 2; for (int i = smoothIndex; i < results.Count; i++) { StochResult r = results[i]; int index = i + 1; decimal sumOsc = 0m; for (int p = index - smoothPeriod; p < index; p++) { StochResult d = results[p]; sumOsc += (decimal)d.Oscillator; } r.Smooth = sumOsc / smoothPeriod; } // replace oscillator foreach (StochResult r in results) { r.Oscillator = (r.Smooth != null) ? r.Smooth : null; } return(results); }
// STOCHASTIC RSI public static IEnumerable <StochRsiResult> GetStochRsi <TQuote>( IEnumerable <TQuote> history, int rsiPeriod, int stochPeriod, int signalPeriod, int smoothPeriod = 1) where TQuote : IQuote { // validate parameters ValidateStochRsi(history, rsiPeriod, stochPeriod, signalPeriod, smoothPeriod); // initialize List <StochRsiResult> results = new List <StochRsiResult>(); // get RSI List <RsiResult> rsiResults = GetRsi(history, rsiPeriod).ToList(); // convert rsi to quote format List <Quote> rsiQuotes = rsiResults .Where(x => x.Rsi != null) .Select(x => new Quote { Date = x.Date, High = (decimal)x.Rsi, Low = (decimal)x.Rsi, Close = (decimal)x.Rsi }) .ToList(); // get Stochastic of RSI List <StochResult> stoResults = GetStoch(rsiQuotes, stochPeriod, signalPeriod, smoothPeriod).ToList(); // compose for (int i = 0; i < rsiResults.Count; i++) { RsiResult r = rsiResults[i]; int index = i + 1; StochRsiResult result = new StochRsiResult { Date = r.Date }; if (index >= rsiPeriod + stochPeriod) { StochResult sto = stoResults[index - rsiPeriod - 1]; result.StochRsi = sto.Oscillator; result.Signal = sto.Signal; } results.Add(result); } return(results); }
// STOCHASTIC RSI public static IEnumerable <StochRsiResult> GetStochRsi(IEnumerable <Quote> history, int rsiPeriod, int stochPeriod, int signalPeriod, int smoothPeriod = 1) { // clean quotes history = Cleaners.PrepareHistory(history); // validate parameters ValidateStochRsi(history, rsiPeriod, stochPeriod, signalPeriod, smoothPeriod); // initialize List <StochRsiResult> results = new List <StochRsiResult>(); // get RSI IEnumerable <RsiResult> rsiResults = GetRsi(history, rsiPeriod); // convert rsi to quote format List <Quote> rsiQuotes = rsiResults .Where(x => x.Rsi != null) .Select(x => new Quote { Index = null, Date = x.Date, High = (decimal)x.Rsi, Low = (decimal)x.Rsi, Close = (decimal)x.Rsi }) .ToList(); // get Stochastic of RSI IEnumerable <StochResult> stoResults = GetStoch(rsiQuotes, stochPeriod, signalPeriod, smoothPeriod); // compose foreach (RsiResult r in rsiResults) { StochRsiResult result = new StochRsiResult { Index = r.Index, Date = r.Date }; if (r.Index >= rsiPeriod + stochPeriod) { StochResult sto = stoResults .Where(x => x.Index == r.Index - stochPeriod) .FirstOrDefault(); result.StochRsi = sto.Oscillator; result.Signal = sto.Signal; result.IsIncreasing = sto.IsIncreasing; } results.Add(result); } return(results); }
// STOCHASTIC OSCILLATOR public static IEnumerable <StochResult> GetStoch(IEnumerable <Quote> history, int lookbackPeriod = 14, int signalPeriod = 3, int smoothPeriod = 3) { // clean quotes history = Cleaners.PrepareHistory(history); // validate parameters ValidateStoch(history, lookbackPeriod, signalPeriod, smoothPeriod); // initialize List <StochResult> results = new List <StochResult>(); // oscillator foreach (Quote h in history) { StochResult result = new StochResult { Index = (int)h.Index, Date = h.Date }; if (h.Index >= lookbackPeriod) { decimal lowLow = history.Where(x => x.Index > (h.Index - lookbackPeriod) && x.Index <= h.Index) .Select(v => v.Low) .Min(); decimal highHigh = history.Where(x => x.Index > (h.Index - lookbackPeriod) && x.Index <= h.Index) .Select(v => v.High) .Max(); if (lowLow != highHigh) { result.Oscillator = 100 * (float)((h.Close - lowLow) / (highHigh - lowLow)); } else { result.Oscillator = 0; } } results.Add(result); } // smooth the oscillator if (smoothPeriod > 1) { // temporarily store interim smoothed oscillator foreach (StochResult r in results.Where(x => x.Index >= (lookbackPeriod + smoothPeriod))) { r.Smooth = results.Where(x => x.Index > (r.Index - smoothPeriod) && x.Index <= r.Index) .Select(v => v.Oscillator) .Average(); } // replace oscillator foreach (StochResult r in results) { if (r.Smooth != null) { r.Oscillator = (float)r.Smooth; } else { r.Oscillator = null; // erase unsmoothed } } } // new signal and trend info float lastOsc = 0; bool? lastIsIncreasing = null; foreach (StochResult r in results .Where(x => x.Index >= (lookbackPeriod + signalPeriod + smoothPeriod) && x.Oscillator != null)) { r.Signal = results.Where(x => x.Index > (r.Index - signalPeriod) && x.Index <= r.Index) .Select(v => v.Oscillator) .Average(); if (r.Index >= (lookbackPeriod + signalPeriod + smoothPeriod) + 1) { if (r.Oscillator > lastOsc) { r.IsIncreasing = true; } else if (r.Oscillator < lastOsc) { r.IsIncreasing = false; } else { // no change, keep trend r.IsIncreasing = lastIsIncreasing; } } lastOsc = (float)r.Oscillator; lastIsIncreasing = r.IsIncreasing; } return(results); }
// STOCHASTIC OSCILLATOR /// <include file='./info.xml' path='indicator/*' /> /// public static IEnumerable <StochResult> GetStoch <TQuote>( IEnumerable <TQuote> history, int lookbackPeriod = 14, int signalPeriod = 3, int smoothPeriod = 3) where TQuote : IQuote { // sort history List <TQuote> historyList = history.Sort(); // check parameter arguments ValidateStoch(history, lookbackPeriod, signalPeriod, smoothPeriod); // initialize int size = historyList.Count; List <StochResult> results = new(size); // roll through history for (int i = 0; i < historyList.Count; i++) { TQuote h = historyList[i]; int index = i + 1; StochResult result = new() { Date = h.Date }; if (index >= lookbackPeriod) { decimal highHigh = 0; decimal lowLow = decimal.MaxValue; for (int p = index - lookbackPeriod; p < index; p++) { TQuote d = historyList[p]; if (d.High > highHigh) { highHigh = d.High; } if (d.Low < lowLow) { lowLow = d.Low; } } result.Oscillator = lowLow != highHigh ? 100 * ((h.Close - lowLow) / (highHigh - lowLow)) : 0; } results.Add(result); } // smooth the oscillator if (smoothPeriod > 1) { results = SmoothOscillator(results, size, lookbackPeriod, smoothPeriod); } // signal (%D) and %J int stochIndex = lookbackPeriod + smoothPeriod - 2; for (int i = stochIndex; i < size; i++) { StochResult r = results[i]; int index = i + 1; // add signal int signalIndex = lookbackPeriod + smoothPeriod + signalPeriod - 2; if (signalPeriod <= 1) { r.Signal = r.Oscillator; } else if (index >= signalIndex) { decimal sumOsc = 0m; for (int p = index - signalPeriod; p < index; p++) { StochResult d = results[p]; sumOsc += (decimal)d.Oscillator; } r.Signal = sumOsc / signalPeriod; r.PercentJ = (3 * r.Oscillator) - (2 * r.Signal); } } return(results); }
// STOCHASTIC OSCILLATOR public static IEnumerable <StochResult> GetStoch(IEnumerable <Quote> history, int lookbackPeriod = 14, int signalPeriod = 3, int smoothPeriod = 3) { // clean quotes history = Cleaners.PrepareHistory(history); // check exceptions int qtyHistory = history.Count(); int minHistory = lookbackPeriod; if (qtyHistory < minHistory) { throw new BadHistoryException("Insufficient history provided for Stochastic. " + string.Format("You provided {0} periods of history when {1} is required.", qtyHistory, minHistory)); } // initialize List <StochResult> results = new List <StochResult>(); // oscillator foreach (Quote h in history) { StochResult result = new StochResult { Index = (int)h.Index, Date = h.Date }; if (h.Index >= lookbackPeriod) { decimal lowLow = history.Where(x => x.Index > (h.Index - lookbackPeriod) && x.Index <= h.Index) .Select(v => v.Low) .Min(); decimal highHigh = history.Where(x => x.Index > (h.Index - lookbackPeriod) && x.Index <= h.Index) .Select(v => v.High) .Max(); if (lowLow != highHigh) { result.Oscillator = 100 * (float)((h.Close - lowLow) / (highHigh - lowLow)); } else { result.Oscillator = 0; } } results.Add(result); } // smooth the oscillator if (smoothPeriod > 1) { // temporarily store interim smoothed oscillator foreach (StochResult r in results.Where(x => x.Index >= (lookbackPeriod + smoothPeriod))) { r.Smooth = results.Where(x => x.Index > (r.Index - smoothPeriod) && x.Index <= r.Index) .Select(v => v.Oscillator) .Average(); } // replace oscillator foreach (StochResult r in results) { if (r.Smooth != null) { r.Oscillator = (float)r.Smooth; } else { r.Oscillator = null; // erase unsmoothed } } } // new signal and trend info float lastOsc = 0; foreach (StochResult r in results .Where(x => x.Index >= (lookbackPeriod + signalPeriod + smoothPeriod) && x.Oscillator != null)) { r.Signal = results.Where(x => x.Index > (r.Index - signalPeriod) && x.Index <= r.Index) .Select(v => v.Oscillator) .Average(); r.IsIncreasing = (r.Oscillator >= lastOsc) ? true : false; lastOsc = (float)r.Oscillator; } return(results); }
// STOCHASTIC OSCILLATOR public static IEnumerable <StochResult> GetStoch <TQuote>( IEnumerable <TQuote> history, int lookbackPeriod = 14, int signalPeriod = 3, int smoothPeriod = 3) where TQuote : IQuote { // clean quotes List <TQuote> historyList = history.Sort(); // validate parameters ValidateStoch(history, lookbackPeriod, signalPeriod, smoothPeriod); // initialize List <StochResult> results = new List <StochResult>(); // oscillator for (int i = 0; i < historyList.Count; i++) { TQuote h = historyList[i]; int index = i + 1; StochResult result = new StochResult { Date = h.Date }; if (index >= lookbackPeriod) { decimal highHigh = 0; decimal lowLow = decimal.MaxValue; for (int p = index - lookbackPeriod; p < index; p++) { TQuote d = historyList[p]; if (d.High > highHigh) { highHigh = d.High; } if (d.Low < lowLow) { lowLow = d.Low; } } if (lowLow != highHigh) { result.Oscillator = 100 * ((h.Close - lowLow) / (highHigh - lowLow)); } else { result.Oscillator = 0; } } results.Add(result); } // smooth the oscillator if (smoothPeriod > 1) { results = SmoothOscillator(results, lookbackPeriod, smoothPeriod); } // signal and period direction info int stochIndex = lookbackPeriod + smoothPeriod - 2; for (int i = stochIndex; i < results.Count; i++) { StochResult r = results[i]; int index = i + 1; // add signal int signalIndex = lookbackPeriod + smoothPeriod + signalPeriod - 2; if (signalPeriod <= 1) { r.Signal = r.Oscillator; } else if (index >= signalIndex) { decimal sumOsc = 0m; for (int p = index - signalPeriod; p < index; p++) { StochResult d = results[p]; sumOsc += (decimal)d.Oscillator; } r.Signal = sumOsc / signalPeriod; } } return(results); }
// STOCHASTIC OSCILLATOR public static IEnumerable <StochResult> GetStoch(IEnumerable <Quote> history, int lookbackPeriod = 14, int signalPeriod = 3, int smoothPeriod = 3) { // clean quotes List <Quote> historyList = Cleaners.PrepareHistory(history).ToList(); // validate parameters ValidateStoch(history, lookbackPeriod, signalPeriod, smoothPeriod); // initialize List <StochResult> results = new List <StochResult>(); // oscillator for (int i = 0; i < historyList.Count; i++) { Quote h = historyList[i]; StochResult result = new StochResult { Index = (int)h.Index, Date = h.Date }; if (h.Index >= lookbackPeriod) { decimal highHigh = 0; decimal lowLow = decimal.MaxValue; for (int p = (int)h.Index - lookbackPeriod; p < h.Index; p++) { Quote d = historyList[p]; if (d.High > highHigh) { highHigh = d.High; } if (d.Low < lowLow) { lowLow = d.Low; } } if (lowLow != highHigh) { result.Oscillator = 100 * ((h.Close - lowLow) / (highHigh - lowLow)); } else { result.Oscillator = 0; } } results.Add(result); } // smooth the oscillator if (smoothPeriod > 1) { results = SmoothOscillator(results, lookbackPeriod, smoothPeriod); } // signal and period direction info int stochIndex = lookbackPeriod + smoothPeriod - 1; foreach (StochResult r in results.Where(x => x.Index >= stochIndex)) { // add signal int signalIndex = lookbackPeriod + smoothPeriod + signalPeriod - 2; if (signalPeriod <= 1) { r.Signal = r.Oscillator; } else if (r.Index >= signalIndex) { decimal sumOsc = 0m; for (int p = r.Index - signalPeriod; p < r.Index; p++) { StochResult d = results[p]; sumOsc += (decimal)d.Oscillator; } r.Signal = sumOsc / signalPeriod; } } return(results); }
// STOCHASTIC OSCILLATOR public static IEnumerable <StochResult> GetStoch(IEnumerable <Quote> history, int lookbackPeriod = 14, int signalPeriod = 3, int smoothPeriod = 3) { // clean quotes Cleaners.PrepareHistory(history); // validate parameters ValidateStoch(history, lookbackPeriod, signalPeriod, smoothPeriod); // initialize List <Quote> historyList = history.ToList(); List <StochResult> results = new List <StochResult>(); // oscillator for (int i = 0; i < historyList.Count; i++) { Quote h = historyList[i]; StochResult result = new StochResult { Index = (int)h.Index, Date = h.Date }; if (h.Index >= lookbackPeriod) { List <Quote> period = historyList .Where(x => x.Index > (h.Index - lookbackPeriod) && x.Index <= h.Index) .ToList(); decimal lowLow = period.Select(v => v.Low).Min(); decimal highHigh = period.Select(v => v.High).Max(); if (lowLow != highHigh) { result.Oscillator = 100 * ((h.Close - lowLow) / (highHigh - lowLow)); } else { result.Oscillator = 0; } } results.Add(result); } // smooth the oscillator if (smoothPeriod > 1) { results = SmoothOscillator(results, lookbackPeriod, smoothPeriod); } // signal and period direction info int stochIndex = lookbackPeriod + smoothPeriod - 1; foreach (StochResult r in results.Where(x => x.Index >= stochIndex)) { // add signal int signalIndex = lookbackPeriod + smoothPeriod + signalPeriod - 2; if (signalPeriod <= 1) { r.Signal = r.Oscillator; } else if (r.Index >= signalIndex) { r.Signal = results .Where(x => x.Index > (r.Index - signalPeriod) && x.Index <= r.Index) .ToList() .Select(v => v.Oscillator) .Average(); } } return(results); }
// STOCHASTIC OSCILLATOR public static IEnumerable <StochResult> GetStoch(IEnumerable <Quote> history, int lookbackPeriod = 14, int signalPeriod = 3, int smoothPeriod = 3) { // clean quotes history = Cleaners.PrepareHistory(history); // validate parameters ValidateStoch(history, lookbackPeriod, signalPeriod, smoothPeriod); // initialize List <StochResult> results = new List <StochResult>(); // oscillator foreach (Quote h in history) { StochResult result = new StochResult { Index = (int)h.Index, Date = h.Date }; if (h.Index >= lookbackPeriod) { decimal lowLow = history.Where(x => x.Index > (h.Index - lookbackPeriod) && x.Index <= h.Index) .Select(v => v.Low) .Min(); decimal highHigh = history.Where(x => x.Index > (h.Index - lookbackPeriod) && x.Index <= h.Index) .Select(v => v.High) .Max(); if (lowLow != highHigh) { result.Oscillator = 100 * ((h.Close - lowLow) / (highHigh - lowLow)); } else { result.Oscillator = 0; } } results.Add(result); } // smooth the oscillator if (smoothPeriod > 1) { results = SmoothOscillator(results, lookbackPeriod, smoothPeriod); } // signal and period direction info decimal?lastOsc = null; bool? lastIsIncreasing = null; foreach (StochResult r in results .Where(x => x.Index >= (lookbackPeriod + smoothPeriod - 1)) .OrderBy(x => x.Index)) { // add signal if (r.Index >= lookbackPeriod + smoothPeriod + signalPeriod - 2) { r.Signal = results.Where(x => x.Index > (r.Index - signalPeriod) && x.Index <= r.Index) .Select(v => v.Oscillator) .Average(); } // add direction if (lastOsc != null) { if (r.Oscillator > lastOsc) { r.IsIncreasing = true; } else if (r.Oscillator < lastOsc) { r.IsIncreasing = false; } else { // no change, keep trend r.IsIncreasing = lastIsIncreasing; } } lastOsc = (decimal)r.Oscillator; lastIsIncreasing = r.IsIncreasing; } return(results); }