Lean  $LEAN_TAG$
AbandonedBaby.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  /// Abandoned Baby candlestick pattern
24  /// </summary>
25  /// <remarks>
26  /// Must have:
27  /// - first candle: long white (black) real body
28  /// - second candle: doji
29  /// - third candle: black(white) real body that moves well within the first candle's real body
30  /// - upside(downside) gap between the first candle and the doji(the shadows of the two candles don't touch)
31  /// - downside (upside) gap between the doji and the third candle(the shadows of the two candles don't touch)
32  /// The meaning of "doji" and "long" is specified with SetCandleSettings
33  /// The meaning of "moves well within" is specified with penetration and "moves" should mean the real body should
34  /// not be short ("short" is specified with SetCandleSettings) - Greg Morris wants it to be long, someone else want
35  /// it to be relatively long
36  /// The returned value is positive (+1) when it's an abandoned baby bottom or negative (-1) when it's
37  /// an abandoned baby top; the user should consider that an abandoned baby is significant when it appears in
38  /// an uptrend or downtrend, while this function does not consider the trend
39  /// </remarks>
41  {
42  private readonly decimal _penetration;
43 
44  private readonly int _bodyDojiAveragePeriod;
45  private readonly int _bodyLongAveragePeriod;
46  private readonly int _bodyShortAveragePeriod;
47 
48  private decimal _bodyDojiPeriodTotal;
49  private decimal _bodyLongPeriodTotal;
50  private decimal _bodyShortPeriodTotal;
51 
52  /// <summary>
53  /// Initializes a new instance of the <see cref="AbandonedBaby"/> class using the specified name.
54  /// </summary>
55  /// <param name="name">The name of this indicator</param>
56  /// <param name="penetration">Percentage of penetration of a candle within another candle</param>
57  public AbandonedBaby(string name, decimal penetration = 0.3m)
58  : base(name, Math.Max(Math.Max(CandleSettings.Get(CandleSettingType.BodyDoji).AveragePeriod, CandleSettings.Get(CandleSettingType.BodyLong).AveragePeriod),
59  CandleSettings.Get(CandleSettingType.BodyShort).AveragePeriod) + 2)
60  {
61  _penetration = penetration;
62 
63  _bodyDojiAveragePeriod = CandleSettings.Get(CandleSettingType.BodyDoji).AveragePeriod;
64  _bodyLongAveragePeriod = CandleSettings.Get(CandleSettingType.BodyLong).AveragePeriod;
65  _bodyShortAveragePeriod = CandleSettings.Get(CandleSettingType.BodyShort).AveragePeriod;
66  }
67 
68  /// <summary>
69  /// Initializes a new instance of the <see cref="AbandonedBaby"/> class.
70  /// </summary>
71  /// <param name="penetration">Percentage of penetration of a candle within another candle</param>
72  public AbandonedBaby(decimal penetration)
73  : this("ABANDONEDBABY", penetration)
74  {
75  }
76 
77  /// <summary>
78  /// Initializes a new instance of the <see cref="AbandonedBaby"/> class.
79  /// </summary>
80  public AbandonedBaby()
81  : this("ABANDONEDBABY")
82  {
83  }
84 
85  /// <summary>
86  /// Gets a flag indicating when this indicator is ready and fully initialized
87  /// </summary>
88  public override bool IsReady
89  {
90  get { return Samples > Period; }
91  }
92 
93  /// <summary>
94  /// Computes the next value of this indicator from the given state
95  /// </summary>
96  /// <param name="window">The window of data held in this indicator</param>
97  /// <param name="input">The input given to the indicator</param>
98  /// <returns>A new value for this indicator</returns>
99  protected override decimal ComputeNextValue(IReadOnlyWindow<IBaseDataBar> window, IBaseDataBar input)
100  {
101  if (!IsReady)
102  {
103  if (Samples > Period - _bodyLongAveragePeriod)
104  {
105  _bodyLongPeriodTotal += GetCandleRange(CandleSettingType.BodyLong, window[2]);
106  }
107  if (Samples > Period - _bodyDojiAveragePeriod)
108  {
109  _bodyDojiPeriodTotal += GetCandleRange(CandleSettingType.BodyDoji, window[1]);
110  }
111  if (Samples > Period - _bodyShortAveragePeriod)
112  {
113  _bodyShortPeriodTotal += GetCandleRange(CandleSettingType.BodyShort, input);
114  }
115 
116  return 0m;
117  }
118 
119  decimal value;
120  if (
121  // 1st: long
122  GetRealBody(window[2]) > GetCandleAverage(CandleSettingType.BodyLong, _bodyLongPeriodTotal, window[2]) &&
123  // 2nd: doji
124  GetRealBody(window[1]) <= GetCandleAverage(CandleSettingType.BodyDoji, _bodyDojiPeriodTotal, window[1]) &&
125  // 3rd: longer than short
126  GetRealBody(input) > GetCandleAverage(CandleSettingType.BodyShort, _bodyShortPeriodTotal, input) &&
127  ((
128  // 1st white
129  GetCandleColor(window[2]) == CandleColor.White &&
130  // 3rd black
131  GetCandleColor(input) == CandleColor.Black &&
132  // 3rd closes well within 1st rb
133  input.Close < window[2].Close - GetRealBody(window[2]) * _penetration &&
134  // upside gap between 1st and 2nd
135  GetCandleGapUp(window[1], window[2]) &&
136  // downside gap between 2nd and 3rd
137  GetCandleGapDown(input, window[1])
138  )
139  ||
140  (
141  // 1st black
142  GetCandleColor(window[2]) == CandleColor.Black &&
143  // 3rd white
144  GetCandleColor(input) == CandleColor.White &&
145  // 3rd closes well within 1st rb
146  input.Close > window[2].Close + GetRealBody(window[2]) * _penetration &&
147  // downside gap between 1st and 2nd
148  GetCandleGapDown(window[1], window[2]) &&
149  // upside gap between 2nd and 3rd
150  GetCandleGapUp(input, window[1])
151  )
152  )
153  )
154  value = (int)GetCandleColor(input);
155  else
156  value = 0m;
157 
158  // add the current range and subtract the first range: this is done after the pattern recognition
159  // when avgPeriod is not 0, that means "compare with the previous candles" (it excludes the current candle)
160 
161  _bodyLongPeriodTotal += GetCandleRange(CandleSettingType.BodyLong, window[2]) -
162  GetCandleRange(CandleSettingType.BodyLong, window[_bodyLongAveragePeriod - 1]);
163 
164  _bodyDojiPeriodTotal += GetCandleRange(CandleSettingType.BodyDoji, window[1]) -
165  GetCandleRange(CandleSettingType.BodyDoji, window[_bodyDojiAveragePeriod]);
166 
167  _bodyShortPeriodTotal += GetCandleRange(CandleSettingType.BodyShort, input) -
168  GetCandleRange(CandleSettingType.BodyShort, window[_bodyShortAveragePeriod + 1]);
169 
170  return value;
171  }
172 
173  /// <summary>
174  /// Resets this indicator to its initial state
175  /// </summary>
176  public override void Reset()
177  {
178  _bodyLongPeriodTotal = 0;
179  _bodyDojiPeriodTotal = 0;
180  _bodyShortPeriodTotal = 0;
181  base.Reset();
182  }
183  }
184 }