Lean  $LEAN_TAG$
HikkakeModified.cs
1 /*
2  * QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
3  * Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  *
15 */
16 
17 using System;
19 
21 {
22  /// <summary>
23  /// Hikkake Modified candlestick pattern
24  /// </summary>
25  /// <remarks>
26  /// Must have:
27  /// - first candle
28  /// - second candle: candle with range less than first candle and close near the bottom(near the top)
29  /// - third candle: lower high and higher low than 2nd
30  /// - fourth candle: lower high and lower low(higher high and higher low) than 3rd
31  /// The returned value for the hikkake bar is positive(+1) or negative(-1) meaning bullish or bearish hikkake
32  /// Confirmation could come in the next 3 days with:
33  /// - a day that closes higher than the high(lower than the low) of the 3rd candle
34  /// The returned value for the confirmation bar is equal to 1 + the bullish hikkake result or -1 - the bearish hikkake result
35  /// Note: if confirmation and a new hikkake come at the same bar, only the new hikkake is reported(the new hikkake
36  /// overwrites the confirmation of the old hikkake);
37  /// The user should consider that modified hikkake is a reversal pattern, while hikkake could be both a reversal
38  /// or a continuation pattern, so bullish(bearish) modified hikkake is significant when appearing in a downtrend(uptrend)
39  /// </remarks>
41  {
42  private readonly int _nearAveragePeriod;
43 
44  private decimal _nearPeriodTotal;
45 
46  private int _patternIndex;
47  private int _patternResult;
48 
49  /// <summary>
50  /// Initializes a new instance of the <see cref="HikkakeModified"/> class using the specified name.
51  /// </summary>
52  /// <param name="name">The name of this indicator</param>
53  public HikkakeModified(string name)
54  : base(name, Math.Max(1, CandleSettings.Get(CandleSettingType.Near).AveragePeriod) + 5 + 1)
55  {
56  _nearAveragePeriod = CandleSettings.Get(CandleSettingType.Near).AveragePeriod;
57  }
58 
59  /// <summary>
60  /// Initializes a new instance of the <see cref="HikkakeModified"/> class.
61  /// </summary>
62  public HikkakeModified()
63  : this("HIKKAKEMODIFIED")
64  {
65  }
66 
67  /// <summary>
68  /// Gets a flag indicating when this indicator is ready and fully initialized
69  /// </summary>
70  public override bool IsReady
71  {
72  get { return Samples >= Period; }
73  }
74 
75  /// <summary>
76  /// Computes the next value of this indicator from the given state
77  /// </summary>
78  /// <param name="window">The window of data held in this indicator</param>
79  /// <param name="input">The input given to the indicator</param>
80  /// <returns>A new value for this indicator</returns>
81  protected override decimal ComputeNextValue(IReadOnlyWindow<IBaseDataBar> window, IBaseDataBar input)
82  {
83  if (!IsReady)
84  {
85  if (Samples >= Period - _nearAveragePeriod - 3 && Samples < Period - 3)
86  {
87  _nearPeriodTotal += GetCandleRange(CandleSettingType.Near, window[2]);
88  }
89 
90  else if (Samples >= Period - 3)
91  {
92  // copy here the pattern recognition code below
93  // 2nd: lower high and higher low than 1st
94  if (window[2].High < window[3].High && window[2].Low > window[3].Low &&
95  // 3rd: lower high and higher low than 2nd
96  window[1].High < window[2].High && window[1].Low > window[2].Low &&
97  // (bull) 4th: lower high and lower low
98  ((input.High < window[1].High && input.Low < window[1].Low &&
99  // (bull) 2nd: close near the low
100  window[2].Close <= window[2].Low + GetCandleAverage(CandleSettingType.Near, _nearPeriodTotal, window[2])
101  )
102  ||
103  // (bear) 4th: higher high and higher low
104  (input.High > window[1].High && input.Low > window[1].Low &&
105  // (bull) 2nd: close near the top
106  window[2].Close >= window[2].High - GetCandleAverage(CandleSettingType.Near, _nearPeriodTotal, window[2])
107  )
108  )
109  )
110  {
111  _patternResult = (input.High < window[1].High ? 1 : -1);
112  _patternIndex = (int) Samples - 1;
113  }
114  else
115  {
116  // search for confirmation if modified hikkake was no more than 3 bars ago
117  if (Samples <= _patternIndex + 4 &&
118  // close higher than the high of 3rd
119  ((_patternResult > 0 && input.Close > window[(int) Samples - _patternIndex].High)
120  ||
121  // close lower than the low of 3rd
122  (_patternResult < 0 && input.Close < window[(int) Samples - _patternIndex].Low))
123  )
124  _patternIndex = 0;
125  }
126 
127  // add the current range and subtract the first range: this is done after the pattern recognition
128  // when avgPeriod is not 0, that means "compare with the previous candles" (it excludes the current candle)
129 
130  _nearPeriodTotal += GetCandleRange(CandleSettingType.Near, window[2]) -
131  GetCandleRange(CandleSettingType.Near, window[(int)Samples - 1]);
132  }
133 
134  return 0m;
135  }
136 
137  decimal value;
138  // 2nd: lower high and higher low than 1st
139  if (window[2].High < window[3].High && window[2].Low > window[3].Low &&
140  // 3rd: lower high and higher low than 2nd
141  window[1].High < window[2].High && window[1].Low > window[2].Low &&
142  // (bull) 4th: lower high and lower low
143  ((input.High < window[1].High && input.Low < window[1].Low &&
144  // (bull) 2nd: close near the low
145  window[2].Close <= window[2].Low + GetCandleAverage(CandleSettingType.Near, _nearPeriodTotal, window[2])
146  )
147  ||
148  // (bear) 4th: higher high and higher low
149  (input.High > window[1].High && input.Low > window[1].Low &&
150  // (bull) 2nd: close near the top
151  window[2].Close >= window[2].High - GetCandleAverage(CandleSettingType.Near, _nearPeriodTotal, window[2])
152  )
153  )
154  )
155  {
156  _patternResult = (input.High < window[1].High ? 1 : -1);
157  _patternIndex = (int) Samples - 1;
158  value = _patternResult;
159  }
160  else
161  {
162  // search for confirmation if modified hikkake was no more than 3 bars ago
163  if (Samples <= _patternIndex + 4 &&
164  // close higher than the high of 3rd
165  ((_patternResult > 0 && input.Close > window[(int)Samples - _patternIndex].High)
166  ||
167  // close lower than the low of 3rd
168  (_patternResult < 0 && input.Close < window[(int)Samples - _patternIndex].Low))
169  )
170  {
171  value = _patternResult + (_patternResult > 0 ? 1 : -1);
172  _patternIndex = 0;
173  }
174  else
175  value = 0;
176  }
177 
178  // add the current range and subtract the first range: this is done after the pattern recognition
179  // when avgPeriod is not 0, that means "compare with the previous candles" (it excludes the current candle)
180 
181  _nearPeriodTotal += GetCandleRange(CandleSettingType.Near, window[2]) -
182  GetCandleRange(CandleSettingType.Near, window[_nearAveragePeriod + 5]);
183 
184  return value;
185  }
186 
187  /// <summary>
188  /// Resets this indicator to its initial state
189  /// </summary>
190  public override void Reset()
191  {
192  _nearPeriodTotal = 0;
193  _patternIndex = 0;
194  _patternResult = 0;
195  base.Reset();
196  }
197  }
198 }