public override IEnumerable <(ICandle, ITradingAdviceCode)> AllForecasts(IEnumerable <ICandle> candles) { if (candles.Count() < MinNumberOfCandles) { throw new Exception("Number of candles less then expected"); } List <(ICandle, ITradingAdviceCode)> result = new List <(ICandle, ITradingAdviceCode)>(); IchimokuItem ichiMoku = candles.Ichimoku(); List <decimal> close = candles.Close(); List <bool> cloudBreakUpA = close.Crossover(ichiMoku.SenkouSpanA); List <bool> cloudBreakDownA = close.Crossunder(ichiMoku.SenkouSpanA); List <bool> cloudBreakUpB = close.Crossover(ichiMoku.SenkouSpanB); List <bool> cloudBreakDownB = close.Crossunder(ichiMoku.SenkouSpanB); for (int i = 0; i < candles.Count(); i++) { if (i == 0) { result.Add((candles.ElementAt(i), TradingAdviceCode.HOLD)); } // Upward cloud break from the bottom else if (ichiMoku.SenkouSpanA[i] > ichiMoku.SenkouSpanB[i] && cloudBreakUpB[i]) { result.Add((candles.ElementAt(i), TradingAdviceCode.BUY)); } else if (ichiMoku.SenkouSpanA[i] < ichiMoku.SenkouSpanB[i] && cloudBreakUpA[i]) { result.Add((candles.ElementAt(i), TradingAdviceCode.BUY)); } // Downward cloud break from the top else if (ichiMoku.SenkouSpanA[i] > ichiMoku.SenkouSpanB[i] && cloudBreakDownA[i]) { result.Add((candles.ElementAt(i), TradingAdviceCode.SELL)); } else if (ichiMoku.SenkouSpanA[i] < ichiMoku.SenkouSpanB[i] && cloudBreakDownB[i]) { result.Add((candles.ElementAt(i), TradingAdviceCode.SELL)); } else { result.Add((candles.ElementAt(i), TradingAdviceCode.HOLD)); } } 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"); } }