Lean  $LEAN_TAG$
ThreeStarsInSouth.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  /// Three Stars In The South candlestick pattern
24  /// </summary>
25  /// <remarks>
26  /// Must have:
27  /// - first candle: long black candle with long lower shadow
28  /// - second candle: smaller black candle that opens higher than prior close but within prior candle's range
29  /// and trades lower than prior close but not lower than prior low and closes off of its low(it has a shadow)
30  /// - third candle: small black marubozu(or candle with very short shadows) engulfed by prior candle's range
31  /// The meanings of "long body", "short body", "very short shadow" are specified with SetCandleSettings;
32  /// The returned value is positive (+1): 3 stars in the south is always bullish;
33  /// The user should consider that 3 stars in the south is significant when it appears in downtrend, while this function
34  /// does not consider it
35  /// </remarks>
37  {
38  private readonly int _bodyLongAveragePeriod;
39  private readonly int _shadowLongAveragePeriod;
40  private readonly int _shadowVeryShortAveragePeriod;
41  private readonly int _bodyShortAveragePeriod;
42 
43  private decimal _bodyLongPeriodTotal;
44  private decimal _shadowLongPeriodTotal;
45  private decimal[] _shadowVeryShortPeriodTotal = new decimal[2];
46  private decimal _bodyShortPeriodTotal;
47 
48  /// <summary>
49  /// Initializes a new instance of the <see cref="ThreeStarsInSouth"/> class using the specified name.
50  /// </summary>
51  /// <param name="name">The name of this indicator</param>
52  public ThreeStarsInSouth(string name)
53  : base(name, Math.Max(Math.Max(CandleSettings.Get(CandleSettingType.ShadowVeryShort).AveragePeriod, CandleSettings.Get(CandleSettingType.ShadowLong).AveragePeriod),
54  Math.Max(CandleSettings.Get(CandleSettingType.BodyLong).AveragePeriod, CandleSettings.Get(CandleSettingType.BodyShort).AveragePeriod)) + 2 + 1)
55  {
56  _bodyLongAveragePeriod = CandleSettings.Get(CandleSettingType.BodyLong).AveragePeriod;
57  _shadowLongAveragePeriod = CandleSettings.Get(CandleSettingType.ShadowLong).AveragePeriod;
58  _shadowVeryShortAveragePeriod = CandleSettings.Get(CandleSettingType.ShadowVeryShort).AveragePeriod;
59  _bodyShortAveragePeriod = CandleSettings.Get(CandleSettingType.BodyShort).AveragePeriod;
60  }
61 
62  /// <summary>
63  /// Initializes a new instance of the <see cref="ThreeStarsInSouth"/> class.
64  /// </summary>
66  : this("THREESTARSINSOUTH")
67  {
68  }
69 
70  /// <summary>
71  /// Gets a flag indicating when this indicator is ready and fully initialized
72  /// </summary>
73  public override bool IsReady
74  {
75  get { return Samples >= Period; }
76  }
77 
78  /// <summary>
79  /// Computes the next value of this indicator from the given state
80  /// </summary>
81  /// <param name="window">The window of data held in this indicator</param>
82  /// <param name="input">The input given to the indicator</param>
83  /// <returns>A new value for this indicator</returns>
84  protected override decimal ComputeNextValue(IReadOnlyWindow<IBaseDataBar> window, IBaseDataBar input)
85  {
86  if (!IsReady)
87  {
88  if (Samples >= Period - _bodyLongAveragePeriod)
89  {
90  _bodyLongPeriodTotal += GetCandleRange(CandleSettingType.BodyLong, window[2]);
91  }
92 
93  if (Samples >= Period - _shadowLongAveragePeriod)
94  {
95  _shadowLongPeriodTotal += GetCandleRange(CandleSettingType.ShadowLong, window[2]);
96  }
97 
98  if (Samples >= Period - _shadowVeryShortAveragePeriod)
99  {
100  _shadowVeryShortPeriodTotal[1] += GetCandleRange(CandleSettingType.ShadowVeryShort, window[1]);
101  _shadowVeryShortPeriodTotal[0] += GetCandleRange(CandleSettingType.ShadowVeryShort, input);
102  }
103 
104  if (Samples >= Period - _bodyShortAveragePeriod)
105  {
106  _bodyShortPeriodTotal += GetCandleRange(CandleSettingType.BodyShort, input);
107  }
108 
109  return 0m;
110  }
111 
112  decimal value;
113  if (
114  // 1st black
115  GetCandleColor(window[2]) == CandleColor.Black &&
116  // 2nd black
117  GetCandleColor(window[1]) == CandleColor.Black &&
118  // 3rd black
119  GetCandleColor(input) == CandleColor.Black &&
120  // 1st: long
121  GetRealBody(window[2]) > GetCandleAverage(CandleSettingType.BodyLong, _bodyLongPeriodTotal, window[2]) &&
122  // with long lower shadow
123  GetLowerShadow(window[2]) > GetCandleAverage(CandleSettingType.ShadowLong, _shadowLongPeriodTotal, window[2]) &&
124  // 2nd: smaller candle
125  GetRealBody(window[1]) < GetRealBody(window[2]) &&
126  // that opens higher but within 1st range
127  window[1].Open > window[2].Close && window[1].Open <= window[2].High &&
128  // and trades lower than 1st close
129  window[1].Low < window[2].Close &&
130  // but not lower than 1st low
131  window[1].Low >= window[2].Low &&
132  // and has a lower shadow
133  GetLowerShadow(window[1]) > GetCandleAverage(CandleSettingType.ShadowVeryShort, _shadowVeryShortPeriodTotal[1], window[1]) &&
134  // 3rd: small marubozu
135  GetRealBody(input) < GetCandleAverage(CandleSettingType.BodyShort, _bodyShortPeriodTotal, input) &&
136  GetLowerShadow(input) < GetCandleAverage(CandleSettingType.ShadowVeryShort, _shadowVeryShortPeriodTotal[0], input) &&
137  GetUpperShadow(input) < GetCandleAverage(CandleSettingType.ShadowVeryShort, _shadowVeryShortPeriodTotal[0], input) &&
138  // engulfed by prior candle's range
139  input.Low > window[1].Low && input.High < window[1].High
140  )
141  value = 1m;
142  else
143  value = 0m;
144 
145  // add the current range and subtract the first range: this is done after the pattern recognition
146  // when avgPeriod is not 0, that means "compare with the previous candles" (it excludes the current candle)
147 
148  _bodyLongPeriodTotal += GetCandleRange(CandleSettingType.BodyLong, window[2]) -
149  GetCandleRange(CandleSettingType.BodyLong, window[2 + _bodyLongAveragePeriod]);
150 
151  _shadowLongPeriodTotal += GetCandleRange(CandleSettingType.ShadowLong, window[2]) -
152  GetCandleRange(CandleSettingType.ShadowLong, window[2 + _shadowLongAveragePeriod]);
153 
154  for (var i = 1; i >= 0; i--)
155  {
156  _shadowVeryShortPeriodTotal[i] += GetCandleRange(CandleSettingType.ShadowVeryShort, window[i]) -
157  GetCandleRange(CandleSettingType.ShadowVeryShort, window[i + _shadowVeryShortAveragePeriod]);
158  }
159 
160  _bodyShortPeriodTotal += GetCandleRange(CandleSettingType.BodyShort, input) -
161  GetCandleRange(CandleSettingType.BodyShort, window[_bodyShortAveragePeriod]);
162 
163  return value;
164  }
165 
166  /// <summary>
167  /// Resets this indicator to its initial state
168  /// </summary>
169  public override void Reset()
170  {
171  _bodyLongPeriodTotal = 0;
172  _shadowLongPeriodTotal = 0;
173  _shadowVeryShortPeriodTotal = new decimal[2];
174  _bodyShortPeriodTotal = 0;
175  base.Reset();
176  }
177  }
178 }