/* * QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals. * Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ using QuantConnect.Data.Market; using System; namespace QuantConnect.Indicators { /// /// This indicator computes the Ichimoku Kinko Hyo indicator. It consists of the following main indicators: /// Tenkan-sen: (Highest High + Lowest Low) / 2 for the specific period (normally 9) /// Kijun-sen: (Highest High + Lowest Low) / 2 for the specific period (normally 26) /// Senkou A Span: (Tenkan-sen + Kijun-sen )/ 2 from a specific number of periods ago (normally 26) /// Senkou B Span: (Highest High + Lowest Low) / 2 for the specific period (normally 52), from a specific number of periods ago (normally 26) /// public class IchimokuKinkoHyo : BarIndicator, IIndicatorWarmUpPeriodProvider { /// /// The Tenkan-sen component of the Ichimoku indicator /// public IndicatorBase Tenkan { get; } /// /// The Kijun-sen component of the Ichimoku indicator /// public IndicatorBase Kijun { get; } /// /// The Senkou A Span component of the Ichimoku indicator /// public IndicatorBase SenkouA { get; } /// /// The Senkou B Span component of the Ichimoku indicator /// public IndicatorBase SenkouB { get; } /// /// The Chikou Span component of the Ichimoku indicator /// public IndicatorBase Chikou { get; } /// /// The Tenkan-sen Maximum component of the Ichimoku indicator /// public IndicatorBase TenkanMaximum { get; } /// /// The Tenkan-sen Minimum component of the Ichimoku indicator /// public IndicatorBase TenkanMinimum { get; } /// /// The Kijun-sen Maximum component of the Ichimoku indicator /// public IndicatorBase KijunMaximum { get; } /// /// The Kijun-sen Minimum component of the Ichimoku indicator /// public IndicatorBase KijunMinimum { get; } /// /// The Senkou B Maximum component of the Ichimoku indicator /// public IndicatorBase SenkouBMaximum { get; } /// /// The Senkou B Minimum component of the Ichimoku indicator /// public IndicatorBase SenkouBMinimum { get; } /// /// The Delayed Tenkan Senkou A component of the Ichimoku indicator /// public WindowIndicator DelayedTenkanSenkouA { get; } /// /// The Delayed Kijun Senkou A component of the Ichimoku indicator /// public WindowIndicator DelayedKijunSenkouA { get; } /// /// The Delayed Maximum Senkou B component of the Ichimoku indicator /// public WindowIndicator DelayedMaximumSenkouB { get; } /// /// The Delayed Minimum Senkou B component of the Ichimoku indicator /// public WindowIndicator DelayedMinimumSenkouB { get; } /// /// Creates a new IchimokuKinkoHyo indicator from the specific periods /// /// The Tenkan-sen period /// The Kijun-sen period /// The Senkou A Span period /// The Senkou B Span period /// The Senkou A Span delay /// The Senkou B Span delay public IchimokuKinkoHyo(int tenkanPeriod = 9, int kijunPeriod = 26, int senkouAPeriod = 26, int senkouBPeriod = 52, int senkouADelayPeriod = 26, int senkouBDelayPeriod = 26) : this( $"ICHIMOKU({tenkanPeriod},{kijunPeriod},{senkouAPeriod},{senkouBPeriod},{senkouADelayPeriod},{senkouBDelayPeriod})", tenkanPeriod, kijunPeriod, senkouAPeriod, senkouBPeriod, senkouADelayPeriod, senkouBDelayPeriod ) { } /// /// Creates a new IchimokuKinkoHyo indicator from the specific periods /// /// The name of this indicator /// The Tenkan-sen period /// The Kijun-sen period /// The Senkou A Span period /// The Senkou B Span period /// The Senkou A Span delay /// The Senkou B Span delay public IchimokuKinkoHyo(string name, int tenkanPeriod = 9, int kijunPeriod = 26, int senkouAPeriod = 26, int senkouBPeriod = 52, int senkouADelayPeriod = 26, int senkouBDelayPeriod = 26) : base(name) { WarmUpPeriod = Math.Max(tenkanPeriod + senkouADelayPeriod, kijunPeriod + senkouADelayPeriod); WarmUpPeriod = Math.Max(WarmUpPeriod, senkouBPeriod + senkouBDelayPeriod); TenkanMaximum = new Maximum(name + "_TenkanMax", tenkanPeriod); TenkanMinimum = new Minimum(name + "_TenkanMin", tenkanPeriod); KijunMaximum = new Maximum(name + "_KijunMax", kijunPeriod); KijunMinimum = new Minimum(name + "_KijunMin", kijunPeriod); SenkouBMaximum = new Maximum(name + "_SenkouBMaximum", senkouBPeriod); SenkouBMinimum = new Minimum(name + "_SenkouBMinimum", senkouBPeriod); DelayedTenkanSenkouA = new Delay(name + "DelayedTenkan", senkouADelayPeriod); DelayedKijunSenkouA = new Delay(name + "DelayedKijun", senkouADelayPeriod); DelayedMaximumSenkouB = new Delay(name + "DelayedMax", senkouBDelayPeriod); DelayedMinimumSenkouB = new Delay(name + "DelayedMin", senkouBDelayPeriod); Chikou = new Delay(name + "_Chikou", senkouADelayPeriod); SenkouA = new FunctionalIndicator( name + "_SenkouA", input => SenkouA.IsReady ? (DelayedTenkanSenkouA.Current.Value + DelayedKijunSenkouA.Current.Value) / 2 : decimal.Zero, senkouA => DelayedTenkanSenkouA.IsReady && DelayedKijunSenkouA.IsReady, () => { Tenkan.Reset(); Kijun.Reset(); }); SenkouB = new FunctionalIndicator( name + "_SenkouB", input => SenkouB.IsReady ? (DelayedMaximumSenkouB.Current.Value + DelayedMinimumSenkouB.Current.Value) / 2 : decimal.Zero, senkouA => DelayedMaximumSenkouB.IsReady && DelayedMinimumSenkouB.IsReady, () => { Tenkan.Reset(); Kijun.Reset(); }); Tenkan = new FunctionalIndicator( name + "_Tenkan", input => Tenkan.IsReady ? (TenkanMaximum.Current.Value + TenkanMinimum.Current.Value) / 2 : decimal.Zero, tenkan => TenkanMaximum.IsReady && TenkanMinimum.IsReady, () => { TenkanMaximum.Reset(); TenkanMinimum.Reset(); }); Kijun = new FunctionalIndicator( name + "_Kijun", input => Kijun.IsReady ? (KijunMaximum.Current.Value + KijunMinimum.Current.Value) / 2 : decimal.Zero, kijun => KijunMaximum.IsReady && KijunMinimum.IsReady, () => { KijunMaximum.Reset(); KijunMinimum.Reset(); }); } /// /// Returns true if all of the sub-components of the Ichimoku indicator is ready /// public override bool IsReady => Tenkan.IsReady && Kijun.IsReady && SenkouA.IsReady && SenkouB.IsReady; /// /// Required period, in data points, for the indicator to be ready and fully initialized. /// public int WarmUpPeriod { get; } /// /// Computes the next value of this indicator from the given state /// /// The input given to the indicator protected override decimal ComputeNextValue(IBaseDataBar input) { TenkanMaximum.Update(input.EndTime, input.High); TenkanMinimum.Update(input.EndTime, input.Low); Tenkan.Update(input.EndTime, input.Close); if (Tenkan.IsReady) DelayedTenkanSenkouA.Update(input.EndTime, Tenkan.Current.Value); KijunMaximum.Update(input.EndTime, input.High); KijunMinimum.Update(input.EndTime, input.Low); Kijun.Update(input.EndTime, input.Close); if (Kijun.IsReady) DelayedKijunSenkouA.Update(input.EndTime, Kijun.Current.Value); SenkouA.Update(input.EndTime, input.Close); SenkouB.Update(input.EndTime, input.Close); SenkouBMaximum.Update(input.EndTime, input.High); if (SenkouBMaximum.IsReady) DelayedMaximumSenkouB.Update(input.EndTime, SenkouBMaximum.Current.Value); SenkouBMinimum.Update(input.EndTime, input.Low); if (SenkouBMinimum.IsReady) DelayedMinimumSenkouB.Update(input.EndTime, SenkouBMinimum.Current.Value); Chikou.Update(input.EndTime, input.Close); return input.Close; } /// /// Resets this indicator to its initial state /// public override void Reset() { base.Reset(); TenkanMaximum.Reset(); TenkanMinimum.Reset(); Tenkan.Reset(); KijunMaximum.Reset(); KijunMinimum.Reset(); Kijun.Reset(); DelayedTenkanSenkouA.Reset(); DelayedKijunSenkouA.Reset(); SenkouA.Reset(); SenkouBMaximum.Reset(); SenkouBMinimum.Reset(); DelayedMaximumSenkouB.Reset(); DelayedMinimumSenkouB.Reset(); Chikou.Reset(); SenkouB.Reset(); } } }