Lean  $LEAN_TAG$
WilderSwingIndex.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 using System;
17 using System.Linq;
19 
21 {
22  /// <summary>
23  /// This indicator calculates the Swing Index (SI) as defined by Welles Wilder
24  /// in his book 'New Concepts in Technical Trading Systems'.
25  /// <para>
26  /// SIₜ = 50 * ( N / R ) * ( K / T )
27  /// </para>
28  /// <para>
29  /// Where:
30  /// <list type="bullet">
31  /// <item>
32  /// <term>N</term>
33  /// <description>
34  /// Equals: Cₜ - Cₜ₋₁ + 0.5 * (Cₜ - Oₜ) + 0.25 * (Cₜ₋₁ - Oₜ₋₁)
35  /// <para>
36  /// <i>See <see cref="GetNValue"/></i>
37  /// </para>
38  /// </description>
39  /// </item>
40  /// <item>
41  /// <term>R</term>
42  /// <description>
43  /// Found by selecting the expression with the largest value and
44  /// then using the corresponding formula.
45  /// <para>
46  /// Expression =&gt; Formula
47  /// <list type="number">
48  /// <item>
49  /// <description>
50  /// |Hₜ - Cₜ₋₁| =&gt; |Hₜ - Cₜ| - 0.5 * |Lₜ - Cₜ₋₁| + 0.25 * |Cₜ₋₁ - Oₜ₋₁|
51  /// </description>
52  /// </item>
53  /// <item>
54  /// <description>
55  /// |Lₜ - Cₜ₋₁| =&gt; |Lₜ - Cₜ| - 0.5 * |Hₜ - Cₜ₋₁| + 0.25 * |Cₜ₋₁ - Oₜ₋₁|
56  /// </description>
57  /// </item>
58  /// <item>
59  /// <description>
60  /// |Hₜ - Lₜ| =&gt; |Hₜ - Lₜ₋₁| + 0.25 * |Cₜ₋₁ - Oₜ₋₁|
61  /// </description>
62  /// </item>
63  /// </list>
64  /// </para>
65  /// <para>
66  /// <i>See <see cref="GetRValue"/></i>
67  /// </para>
68  /// </description>
69  /// </item>
70  /// <item>
71  /// <term>K</term>
72  /// <description>
73  /// Found by selecting the larger of the two expressions:
74  /// |Hₜ - Cₜ₋₁|, |Lₜ - Cₜ₋₁|
75  /// <para>
76  /// <i>See <see cref="GetKValue"/></i>
77  /// </para>
78  /// </description>
79  /// </item>
80  /// <item>
81  /// <term>T</term>
82  /// <description>
83  /// The limit move, or the maximum change in price during the time
84  /// period for the bar. Passed as limitMove via the constructor.
85  /// <para>
86  /// <i>See <see cref="T"/></i>
87  /// </para>
88  /// </description>
89  /// </item>
90  /// </list>
91  /// </para>
92  /// </summary>
93  /// <seealso cref="WilderAccumulativeSwingIndex"/>
95  {
96  /// <summary>
97  /// Holds the bar for the current period.
98  /// </summary>
100 
101  /// <summary>
102  /// Holds the bar for the previous period.
103  /// </summary>
105 
106  /// <summary>
107  /// Gets the value for T (the limit move value) set in the constructor.
108  /// </summary>
109  private readonly decimal T;
110 
111  /// <summary>
112  /// Initializes a new instance of the <see cref="WilderSwingIndex"/> class using the specified name.
113  /// </summary>
114  /// <param name="name">A string for the name of this indicator.</param>
115  /// <param name="limitMove">A decimal representing the limit move value for the period.</param>
116  public WilderSwingIndex(string name, decimal limitMove)
117  : base(name)
118  {
119  T = Math.Abs(limitMove);
120  }
121 
122  /// <summary>
123  /// Initializes a new instance of the <see cref="WilderSwingIndex"/> class using the default name.
124  /// </summary>
125  /// <param name="limitMove">A decimal representing the limit move value for the period.</param>
126  public WilderSwingIndex(decimal limitMove)
127  : this("SI", limitMove)
128  {
129  }
130 
131  /// <summary>
132  /// Gets a flag indicating when this indicator is ready and fully initialized.
133  /// </summary>
134  public override bool IsReady => Samples > 1;
135 
136  /// <summary>
137  /// Required period, in data points, for the indicator to be ready and fully initialized.
138  /// </summary>
139  public int WarmUpPeriod => 2;
140 
141  /// <summary>
142  /// Computes the next value of this indicator from the given state.
143  /// </summary>
144  /// <param name="input">The input given to the indicator.</param>
145  /// <returns>A new value for this indicator.</returns>
146  protected override decimal ComputeNextValue(TradeBar input)
147  {
148  if (!IsReady)
149  {
150  _currentInput = input;
151  return 0m;
152  }
153 
155  _currentInput = input;
156 
157  var N = GetNValue();
158  var R = GetRValue();
159  var K = GetKValue();
160 
161  if (R == decimal.Zero || T == decimal.Zero)
162  {
163  return 0m;
164  }
165  return 50m * (N / R) * (K / T);
166  }
167 
168  /// <summary>
169  /// Gets the value for N.
170  /// <para>
171  /// N = Cₜ - Cₜ₋₁ + 0.5 * (Cₜ - Oₜ) + 0.25 * (Cₜ₋₁ - Oₜ₋₁)
172  /// </para>
173  /// </summary>
174  private decimal GetNValue()
175  {
177  + (0.5m * (_currentInput.Close - _currentInput.Open))
178  + (0.25m * (_previousInput.Close - _previousInput.Open));
179  }
180 
181  /// <summary>
182  /// Gets the value for R, determined by using the formula corresponding
183  /// to the expression with the largest value.
184  /// <para>
185  /// <i>Expressions:</i>
186  /// <list type="number">
187  /// <item>
188  /// <description>|Hₜ - Cₜ₋₁|</description>
189  /// </item>
190  /// <item>
191  /// <description>|Lₜ - Cₜ₋₁|</description>
192  /// </item>
193  /// <item>
194  /// <description>|Hₜ - Lₜ|</description>
195  /// </item>
196  /// </list>
197  /// </para>
198  /// <para>
199  /// <i>Formulas:</i>
200  /// <list type="number">
201  /// <item>
202  /// <description>|Hₜ - Cₜ₋₁| - 0.5 * |Lₜ - Cₜ₋₁| + 0.25 * |Cₜ₋₁ - Oₜ₋₁|</description>
203  /// </item>
204  /// <item>
205  /// <description>|Lₜ - Cₜ₋₁| - 0.5 * |Hₜ - Cₜ₋₁| + 0.25 * |Cₜ₋₁ - Oₜ₋₁|</description>
206  /// </item>
207  /// <item>
208  /// <description>|Hₜ - Lₜ| + 0.25 * |Cₜ₋₁ - Oₜ₋₁|</description>
209  /// </item>
210  /// </list>
211  /// </para>
212  /// </summary>
213  private decimal GetRValue()
214  {
215  var expressions = new decimal[]
216  {
219  Math.Abs(_currentInput.High - _currentInput.Low)
220  };
221 
222  int expressionIndex = Array.IndexOf(expressions, expressions.Max());
223 
224  decimal result;
225  switch (expressionIndex)
226  {
227  case 0:
228  result = Math.Abs(_currentInput.High - _previousInput.Close)
229  - Math.Abs(0.5m * (_currentInput.Low - _previousInput.Close))
230  + Math.Abs(0.25m * (_previousInput.Close - _previousInput.Open));
231  break;
232 
233  case 1:
234  result = Math.Abs(_currentInput.Low - _previousInput.Close)
235  - Math.Abs(0.5m * (_currentInput.High - _previousInput.Close))
236  + Math.Abs(0.25m * (_previousInput.Close - _previousInput.Open));
237  break;
238 
239  case 2:
240  result = Math.Abs(_currentInput.High - _currentInput.Low)
241  + Math.Abs(0.25m * (_previousInput.Close - _previousInput.Open));
242  break;
243 
244  default:
245  result = 0m;
246  break;
247  }
248 
249  return result;
250  }
251 
252  /// <summary>
253  /// Gets the value for K, which is equal to the larger of the two following expressions.
254  /// <para>
255  /// <i>Expressions:</i>
256  /// <list type="number">
257  /// <item>
258  /// <description>|Hₜ - Cₜ₋₁|</description>
259  /// </item>
260  /// <item>
261  /// <description>|Lₜ - Cₜ₋₁|</description>
262  /// </item>
263  /// </list>
264  /// </para>
265  /// </summary>
266  private decimal GetKValue()
267  {
268  var values = new decimal[]
269  {
272  };
273 
274  return values.Max(x => Math.Abs(x));
275  }
276  }
277 }