public override dynamic Get(IEnumerable <decimal?> candles, IIndicatorOptions options = null) { throw new NotImplementedException(); }
public override dynamic Get(IEnumerable <ICandle> source, IIndicatorOptions options = null) { // TODO: Move to options bool returnRaw = false; // Calculate our Moving Averages IEnumerable <decimal?> smaFastData = source.Select(x => (decimal?)((x.High + x.Low) / 2)); List <decimal?> smaFast = smaFastData.Sma(5); IEnumerable <decimal?> smaSlowData = source.Select(x => (decimal?)((x.High + x.Low) / 2)); List <decimal?> smaSlow = smaFastData.Sma(34); List <decimal?> result = new List <decimal?>(); for (int i = 0; i < smaFast.Count(); i++) { if (returnRaw) { if (!smaFast[i].HasValue || !smaSlow[i].HasValue) { result.Add(null); } else { result.Add(smaFast[i].Value - smaSlow[i].Value); } } else { // The last and second to last values interest us, because we're looking for a cross of these lines. // If it's not the first item, we can check the previous. if (i > 0) { decimal?smaFastLast = smaFast[i]; decimal?smaSlowLast = smaSlow[i]; decimal?smaFastSecondLast = smaFast[i - 1]; decimal?smaSlowSecondLast = smaSlow[i - 1]; decimal?aoSecondLast = smaFastSecondLast - smaSlowSecondLast; decimal?aoLast = smaFastLast - smaSlowLast; if (aoSecondLast <= 0 && aoLast > 0) { result.Add(100); } else if (aoSecondLast >= 0 && aoLast < 0) { result.Add(-100); } else { result.Add(0); } } else { result.Add(0); } } } return(result); }
public override dynamic Get(IEnumerable <ICandle> source, IIndicatorOptions options = null) { CandlePatternsOptions config = options != null ? (CandlePatternsOptions)options.Options : new CandlePatternsOptions(0.05m); List <CandlePatternCode> result = new List <CandlePatternCode>(); List <decimal> open = source.Open(); List <decimal> close = source.Close(); List <decimal> high = source.High(); List <decimal> low = source.Low(); for (int i = 0; i < source.Count(); i++) { if (Math.Abs(open[i] - close[i]) <= (high[i] - low[i]) * config.DojiSize) { result.Add(CandlePatternCode.DOJI); continue; } if (high[i] - low[i] > 3 * (open[i] - close[i]) && (close[i] - low[i]) / (.001m + high[i] - low[i]) > 0.6m && (open[i] - low[i]) / (.001m + high[i] - low[i]) > 0.6m) { result.Add(CandlePatternCode.BULLISH_HAMMER); continue; } if (high[i] - low[i] > 3 * (open[i] - close[i]) && (high[i] - close[i]) / (.001m + high[i] - low[i]) > 0.6m && (high[i] - open[i]) / (.001m + high[i] - low[i]) > 0.6m) { result.Add(CandlePatternCode.BEARISH_INVERTED_HAMMER); continue; } // These patterns require at least 2 data points if (i > 0) { if (open[i - 1] < close[i - 1] && open[i] > close[i - 1] && high[i] - Math.Max(open[i], close[i]) >= Math.Abs(open[i] - close[i]) * 3 && Math.Min(close[i], open[i]) - low[i] <= Math.Abs(open[i] - close[i])) { result.Add(CandlePatternCode.SHOOTING_STAR); continue; } if (close[i - 1] > open[i - 1] && open[i] > close[i] && open[i] <= close[i - 1] && open[i - 1] <= close[i] && open[i] - close[i] < close[i - 1] - open[i - 1]) { result.Add(CandlePatternCode.BEARISH_HARAMI); continue; } if (open[i - 1] > close[i - 1] && close[i] > open[i] && close[i] <= open[i - 1] && close[i - 1] <= open[i] && close[i] - open[i] < open[i - 1] - close[i - 1]) { result.Add(CandlePatternCode.BULLISH_HARAMI); continue; } if (close[i - 1] > open[i - 1] && open[i] > close[i] && open[i] >= close[i - 1] && open[i - 1] >= close[i] && open[i] - close[i] > close[i - 1] - open[i - 1]) { result.Add(CandlePatternCode.BEARISH_ENGULFING); continue; } if (open[i - 1] > close[i - 1] && close[i] > open[i] && close[i] >= open[i - 1] && close[i - 1] >= open[i] && close[i] - open[i] > open[i - 1] - close[i - 1]) { result.Add(CandlePatternCode.BULLISH_ENGULFING); continue; } if (open[i - 1] > close[i - 1] && open[i] >= open[i - 1] && close[i] > open[i]) { result.Add(CandlePatternCode.BULLISH_KICKER); continue; } if (open[i - 1] < close[i - 1] && open[i] <= open[i - 1] && close[i] <= open[i]) { result.Add(CandlePatternCode.BEARISH_KICKER); continue; } if (close[i - 1] > open[i - 1] && (close[i - 1] + open[i - 1]) / 2 > close[i] && open[i] > close[i] && open[i] > close[i - 1] && close[i] > open[i - 1] && (open[i] - close[i]) / (.001m + (high[i] - low[i])) > 0.6m) { result.Add(CandlePatternCode.BEARISH_DARK_CLOUD_COVER); continue; } // These patterns require at least 3 data points if (i > 1) { if (close[i - 2] < open[i - 2] && Math.Max(open[i - 1], close[i - 1]) < close[i - 2] && open[i] > Math.Max(open[i - 1], close[i - 1]) && close[i] > open[i]) { result.Add(CandlePatternCode.BULLISH_MORNING_STAR); continue; } if (close[i - 2] > open[i - 2] && Math.Min(open[i - 1], close[i - 1]) > close[i - 2] && open[i] < Math.Min(open[i - 1], close[i - 1]) && close[i] < open[i]) { result.Add(CandlePatternCode.BEARISH_EVENING_STAR); continue; } if (high[i] - low[i] > 4 * (open[i] - close[i]) && (close[i] - low[i]) / (.001m + high[i] - low[i]) >= 0.75m && (open[i] - low[i]) / (.001m + high[i] - low[i]) >= 0.75m && high[i - 1] < open[i] && high[i - 2] < open[i]) { result.Add(CandlePatternCode.BEARISH_HANGING_MAN); continue; } } if (i > 9) { decimal upper = high.Skip(i - 10).Take(10).OrderByDescending(x => x).ToList()[1]; if (close[i - 1] < open[i - 1] && open[i] < low[i - 1] && close[i] > close[i - 1] + (open[i - 1] - close[i - 1]) / 2 && close[i] < open[i - 1]) { result.Add(CandlePatternCode.PIERCING_LINE); continue; } decimal lower = high.Skip(i - 10).Take(10).OrderBy(x => x).ToList()[1]; if (low[i] == open[i] && open[i] < lower && open[i] < close[i] && close[i] > (high[i - 1] - low[i - 1]) / 2 + low[i - 1]) { result.Add(CandlePatternCode.BULLISH_BELT); continue; } } } result.Add(null); } return(result); }
public override dynamic Get(IEnumerable <ICandle> source, IIndicatorOptions options = null) { try { IchimokuOptions config = options != null ? (IchimokuOptions)options.Options : new IchimokuOptions(20, 60, 120, 30); List <decimal> highs = source.Select(x => x.High).ToList(); List <decimal> lows = source.Select(x => x.Low).ToList(); List <decimal> closes = source.Select(x => x.Close).ToList(); var ichi = new IchimokuItem { TenkanSen = Donchian(source, config.ConversionLinePeriod, highs, lows), KijunSen = Donchian(source, config.BaseLinePeriod, highs, lows), SenkouSpanB = Donchian(source, config.LaggingSpanPeriods, highs, lows), SenkouSpanA = new List <decimal?>() }; // SenkouSpanA is calculated... for (int i = 0; i < ichi.TenkanSen.Count; i++) { if (ichi.TenkanSen[i].HasValue && ichi.KijunSen[i].HasValue) { ichi.SenkouSpanA.Add((ichi.TenkanSen[i].Value + ichi.KijunSen[i].Value) / 2); } else { ichi.SenkouSpanA.Add(null); } } // Add the displacement for the cloud for (int i = 0; i < config.Displacement; i++) { ichi.SenkouSpanA.Insert(0, null); ichi.SenkouSpanB.Insert(0, null); } // Add the ChikouSpan ichi.ChikouSpan = new List <decimal?>(); // Add the displacement for the lagging span var displacedCloses = closes.Skip(config.Displacement).ToList(); for (int i = 0; i < closes.Count; i++) { if (i < closes.Count - config.Displacement) { ichi.ChikouSpan.Add(displacedCloses[i]); } else { ichi.ChikouSpan.Add(null); } } return(ichi); } catch (Exception ex) { throw new Exception("Could not calculate ichimoku cloud"); } }
public override dynamic Get(IEnumerable <ICandle> source, IIndicatorOptions options = null) { PivotLowOptions config = options != null ? (PivotLowOptions)options.Options : new PivotLowOptions(4, 2, false); List <decimal?> result = new List <decimal?>(); for (int i = 0; i < source.Count(); i++) { if (i < config.BarsLeft + config.BarsRight) { result.Add(null); continue; } bool isPivot = true; List <ICandle> subSet = source.Skip(i - config.BarsLeft - config.BarsRight).Take(config.BarsLeft + config.BarsRight + 1).ToList(); ICandle valueToCheck = subSet[config.BarsLeft]; // Check if the [barsLeft] bars left of what we're checking all have lower highs or equal for (int leftPivot = 0; leftPivot < config.BarsLeft; leftPivot++) { if (subSet[leftPivot].Low < valueToCheck.Low) { isPivot = false; break; } } // If it's still a pivot by this point, carry on checking the right side... if (isPivot) { // If the [barsRight] right side all have lower highs, it's a pivot! for (int rightPivot = config.BarsLeft + 1; rightPivot < subSet.Count; rightPivot++) { if (subSet[rightPivot].Low <= valueToCheck.Low) { isPivot = false; break; } } // If it's a pivot if (isPivot) { result.Add(valueToCheck.Low); } else { result.Add(null); } } else { result.Add(null); } } if (config.FillNullValues) { return(FillPivotNulls(result)); } return(result); }