Lean  $LEAN_TAG$
AdvanceDeclineIndicator.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 
17 using System;
18 using System.Collections.Generic;
19 using System.Linq;
20 
22 {
23  /// <summary>
24  /// The advance-decline indicator compares the number of stocks
25  /// that closed higher against the number of stocks
26  /// that closed lower than their previous day's closing prices.
27  /// </summary>
29  {
30  private IDictionary<SecurityIdentifier, TradeBar> _previousPeriod = new Dictionary<SecurityIdentifier, TradeBar>();
31  private IDictionary<SecurityIdentifier, TradeBar> _currentPeriod = new Dictionary<SecurityIdentifier, TradeBar>();
32  private readonly Func<IEnumerable<TradeBar>, decimal> _computeSubValue;
33  private readonly Func<decimal, decimal, decimal> _computeMainValue;
34  private DateTime? _currentPeriodTime = null;
35 
36  /// <summary>
37  /// Initializes a new instance of the <see cref="AdvanceDeclineRatio"/> class
38  /// </summary>
39  public AdvanceDeclineIndicator(string name, Func<IEnumerable<TradeBar>, decimal> computeSub, Func<decimal, decimal, decimal> computeMain)
40  : base(name)
41  {
42  _computeSubValue = computeSub;
43  _computeMainValue = computeMain;
44  }
45 
46  /// <summary>
47  /// Add tracking asset issue
48  /// </summary>
49  /// <param name="asset">tracking asset issue</param>
50  public virtual void Add(Symbol asset)
51  {
52  if (!_currentPeriod.ContainsKey(asset.ID))
53  {
54  _currentPeriod.Add(asset.ID, null);
55  }
56  }
57 
58  /// <summary>
59  /// Deprecated
60  /// </summary>
61  [Obsolete("Please use Add(asset)")]
62  public void AddStock(Symbol asset)
63  {
64  Add(asset);
65  }
66 
67  /// <summary>
68  /// Remove tracking asset issue
69  /// </summary>
70  /// <param name="asset">tracking asset issue</param>
71  public virtual void Remove(Symbol asset)
72  {
73  _currentPeriod.Remove(asset.ID);
74  }
75 
76  /// <summary>
77  /// Deprecated
78  /// </summary>
79  [Obsolete("Please use Remove(asset)")]
80  public void RemoveStock(Symbol asset)
81  {
82  Remove(asset);
83  }
84 
85  /// <summary>
86  /// Gets a flag indicating when this indicator is ready and fully initialized
87  /// </summary>
88  public override bool IsReady => _previousPeriod.Keys.Any();
89 
90  /// <summary>
91  /// Required period, in data points, for the indicator to be ready and fully initialized.
92  /// </summary>
93  public int WarmUpPeriod => 2;
94 
95  /// <summary>
96  /// Computes the next value of this indicator from the given state
97  /// </summary>
98  /// <param name="input">The input given to the indicator</param>
99  /// <returns>A new value for this indicator</returns>
100  protected override decimal ComputeNextValue(TradeBar input)
101  {
102  var advStocks = new List<TradeBar>();
103  var dclStocks = new List<TradeBar>();
104 
105  TradeBar tradeBar;
106  foreach (var stock in _currentPeriod)
107  {
108  if (!_previousPeriod.TryGetValue(stock.Key, out tradeBar) || tradeBar == null)
109  {
110  continue;
111  }
112  else if (stock.Value.Close < tradeBar.Close)
113  {
114  dclStocks.Add(stock.Value);
115  }
116  else if (stock.Value.Close > tradeBar.Close)
117  {
118  advStocks.Add(stock.Value);
119  }
120  }
121 
122  return _computeMainValue(_computeSubValue(advStocks), _computeSubValue(dclStocks));
123  }
124 
125  /// <summary>
126  /// Computes the next value of this indicator from the given state
127  /// </summary>
128  /// <param name="input">The input given to the indicator</param>
129  /// <returns>A new value for this indicator</returns>
131  {
132  Enqueue(input);
133 
134  if (!_previousPeriod.Keys.Any() || _currentPeriod.Any(p => p.Value == null))
135  {
136  return new IndicatorResult(0, IndicatorStatus.ValueNotReady);
137  }
138 
139  var vNext = ComputeNextValue(input);
140  return new IndicatorResult(vNext);
141  }
142 
143  /// <summary>
144  /// Resets this indicator to its initial state
145  /// </summary>
146  public override void Reset()
147  {
148  _previousPeriod.Clear();
149  foreach (var key in _currentPeriod.Keys.ToList())
150  {
151  _currentPeriod[key] = null;
152  }
153 
154  base.Reset();
155  }
156 
157  private void Enqueue(TradeBar input)
158  {
159  if (input.EndTime == _currentPeriodTime)
160  {
161  _previousPeriod[input.Symbol.ID] = input;
162  return;
163  }
164 
165  if (input.Time > _currentPeriodTime)
166  {
167  _previousPeriod.Clear();
168  foreach (var key in _currentPeriod.Keys.ToList())
169  {
170  _previousPeriod[key] = _currentPeriod[key];
171  _currentPeriod[key] = null;
172  }
173  _currentPeriodTime = input.Time;
174  }
175 
176  if (_currentPeriod.ContainsKey(input.Symbol.ID) && (!_currentPeriodTime.HasValue || input.Time == _currentPeriodTime))
177  {
178  _currentPeriod[input.Symbol.ID] = input;
179  if (!_currentPeriodTime.HasValue)
180  {
181  _currentPeriodTime = input.Time;
182  }
183  }
184  }
185  }
186 }