Lean  $LEAN_TAG$
QCAlgorithm.Indicators.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 QuantConnect.Data;
20 using System;
21 using System.Collections.Generic;
22 using System.Linq;
23 using Python.Runtime;
24 using QuantConnect.Util;
25 using static QuantConnect.StringExtensions;
28 
29 namespace QuantConnect.Algorithm
30 {
31  public partial class QCAlgorithm
32  {
33  private readonly List<Func<IBaseData, decimal>> _quoteRequiredFields = new() {
34  Field.BidPrice,
35  Field.AskPrice,
36  Field.BidClose,
37  Field.BidOpen,
38  Field.BidLow,
39  Field.BidHigh,
40  Field.AskClose,
41  Field.AskOpen,
42  Field.AskLow,
43  Field.AskHigh,
44  };
45 
46  /// <summary>
47  /// Gets whether or not WarmUpIndicator is allowed to warm up indicators
48  /// </summary>
49  [Obsolete("Please use Settings.AutomaticIndicatorWarmUp")]
51  {
52  get
53  {
55  }
56  set
57  {
59  }
60  }
61 
62  /// <summary>
63  /// Creates a new Acceleration Bands indicator.
64  /// </summary>
65  /// <param name="symbol">The symbol whose Acceleration Bands we want.</param>
66  /// <param name="period">The period of the three moving average (middle, upper and lower band).</param>
67  /// <param name="width">A coefficient specifying the distance between the middle band and upper or lower bands.</param>
68  /// <param name="movingAverageType">Type of the moving average.</param>
69  /// <param name="resolution">The resolution.</param>
70  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to casting the input value to a TradeBar.</param>
71  /// <returns></returns>
72  [DocumentationAttribute(Indicators)]
73  public AccelerationBands ABANDS(Symbol symbol, int period, decimal width = 4, MovingAverageType movingAverageType = MovingAverageType.Simple,
74  Resolution? resolution = null, Func<IBaseData, TradeBar> selector = null)
75  {
76  var name = CreateIndicatorName(symbol, $"ABANDS({period},{width})", resolution);
77  var accelerationBands = new AccelerationBands(name, period, width, movingAverageType);
78  InitializeIndicator(accelerationBands, resolution, selector, symbol);
79 
80  return accelerationBands;
81  }
82 
83  /// <summary>
84  /// Creates a new AccumulationDistribution indicator.
85  /// </summary>
86  /// <param name="symbol">The symbol whose AD we want</param>
87  /// <param name="resolution">The resolution</param>
88  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
89  /// <returns>The AccumulationDistribution indicator for the requested symbol over the specified period</returns>
90  [DocumentationAttribute(Indicators)]
91  public AccumulationDistribution AD(Symbol symbol, Resolution? resolution = null, Func<IBaseData, TradeBar> selector = null)
92  {
93  var name = CreateIndicatorName(symbol, "AD", resolution);
94  var accumulationDistribution = new AccumulationDistribution(name);
95  InitializeIndicator(accumulationDistribution, resolution, selector, symbol);
96 
97  return accumulationDistribution;
98  }
99 
100  /// <summary>
101  /// Creates a new AccumulationDistributionOscillator indicator.
102  /// </summary>
103  /// <param name="symbol">The symbol whose ADOSC we want</param>
104  /// <param name="fastPeriod">The fast moving average period</param>
105  /// <param name="slowPeriod">The slow moving average period</param>
106  /// <param name="resolution">The resolution</param>
107  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
108  /// <returns>The AccumulationDistributionOscillator indicator for the requested symbol over the specified period</returns>
109  [DocumentationAttribute(Indicators)]
110  public AccumulationDistributionOscillator ADOSC(Symbol symbol, int fastPeriod, int slowPeriod, Resolution? resolution = null, Func<IBaseData, TradeBar> selector = null)
111  {
112  var name = CreateIndicatorName(symbol, $"ADOSC({fastPeriod},{slowPeriod})", resolution);
113  var accumulationDistributionOscillator = new AccumulationDistributionOscillator(name, fastPeriod, slowPeriod);
114  InitializeIndicator(accumulationDistributionOscillator, resolution, selector, symbol);
115 
116  return accumulationDistributionOscillator;
117  }
118 
119  /// <summary>
120  /// Creates a Alpha indicator for the given target symbol in relation with the reference used.
121  /// The indicator will be automatically updated on the given resolution.
122  /// </summary>
123  /// <param name="target">The target symbol whose Alpha value we want</param>
124  /// <param name="reference">The reference symbol to compare with the target symbol</param>
125  /// <param name="alphaPeriod">The period of the Alpha indicator</param>
126  /// <param name="betaPeriod">The period of the Beta indicator</param>
127  /// <param name="resolution">The resolution</param>
128  /// <param name="riskFreeRate">The risk free rate</param>
129  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to casting the input value to a TradeBar</param>
130  /// <returns>The Alpha indicator for the given parameters</returns>
131  [DocumentationAttribute(Indicators)]
132  public Alpha A(Symbol target, Symbol reference, int alphaPeriod = 1, int betaPeriod = 252, Resolution? resolution = null, decimal? riskFreeRate = null, Func<IBaseData, IBaseDataBar> selector = null)
133  {
134  var baseBame = riskFreeRate.HasValue ? $"A({alphaPeriod},{betaPeriod},{riskFreeRate})" : $"A({alphaPeriod},{betaPeriod})";
135  var name = CreateIndicatorName(target, baseBame, resolution);
136 
137  // If risk free rate is not specified, use the default risk free rate model
138  IRiskFreeInterestRateModel riskFreeRateModel = riskFreeRate.HasValue
139  ? new ConstantRiskFreeRateInterestRateModel(riskFreeRate.Value)
141 
142  var alpha = new Alpha(name, target, reference, alphaPeriod, betaPeriod, riskFreeRateModel);
143  InitializeIndicator(alpha, resolution, selector, target, reference);
144 
145  return alpha;
146  }
147 
148  /// <summary>
149  /// Creates a new Average Range (AR) indicator.
150  /// </summary>
151  /// <param name="symbol">The symbol whose Average Range we want to calculate</param>
152  /// <param name="period">The period over which to compute the Average Range</param>
153  /// <param name="resolution">The resolution</param>
154  /// <param name="selector">Selects a value from the BaseData to send into the indicator. If null, defaults to the Value property of BaseData (x => x.Value).</param>
155  /// <returns>The Average Range indicator for the requested symbol over the specified period</returns>
156  [DocumentationAttribute(Indicators)]
157  public AverageRange AR(Symbol symbol, int period, Resolution? resolution = null, Func<IBaseData, IBaseDataBar> selector = null)
158  {
159  var name = CreateIndicatorName(symbol, $"AR({period})", resolution);
160  var averageRange = new AverageRange(name, period);
161  InitializeIndicator(averageRange, resolution, selector, symbol);
162  return averageRange;
163  }
164 
165  /// <summary>
166  /// Creates a new ARIMA indicator.
167  /// </summary>
168  /// <param name="symbol">The symbol whose ARIMA indicator we want</param>
169  /// <param name="arOrder">AR order (p) -- defines the number of past values to consider in the AR component of the model.</param>
170  /// <param name="diffOrder">Difference order (d) -- defines how many times to difference the model before fitting parameters.</param>
171  /// <param name="maOrder">MA order (q) -- defines the number of past values to consider in the MA component of the model.</param>
172  /// <param name="period">Size of the rolling series to fit onto</param>
173  /// <param name="resolution">The resolution</param>
174  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
175  /// <returns>The ARIMA indicator for the requested symbol over the specified period</returns>
176  [DocumentationAttribute(Indicators)]
177  public AutoRegressiveIntegratedMovingAverage ARIMA(Symbol symbol, int arOrder, int diffOrder, int maOrder, int period,
178  Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
179  {
180  var name = CreateIndicatorName(symbol, $"ARIMA({arOrder},{diffOrder},{maOrder},{period})", resolution);
181  var arimaIndicator = new AutoRegressiveIntegratedMovingAverage(name, arOrder, diffOrder, maOrder, period);
182  InitializeIndicator(arimaIndicator, resolution, selector, symbol);
183 
184  return arimaIndicator;
185  }
186 
187  /// <summary>
188  /// Creates a new Average Directional Index indicator.
189  /// The indicator will be automatically updated on the given resolution.
190  /// </summary>
191  /// <param name="symbol">The symbol whose Average Directional Index we seek</param>
192  /// <param name="resolution">The resolution.</param>
193  /// <param name="period">The period over which to compute the Average Directional Index</param>
194  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to casting the input value to a TradeBar</param>
195  /// <returns>The Average Directional Index indicator for the requested symbol.</returns>
196  [DocumentationAttribute(Indicators)]
197  public AverageDirectionalIndex ADX(Symbol symbol, int period, Resolution? resolution = null, Func<IBaseData, IBaseDataBar> selector = null)
198  {
199  var name = CreateIndicatorName(symbol, $"ADX({period})", resolution);
200  var averageDirectionalIndex = new AverageDirectionalIndex(name, period);
201  InitializeIndicator(averageDirectionalIndex, resolution, selector, symbol);
202 
203  return averageDirectionalIndex;
204  }
205 
206  /// <summary>
207  /// Creates a new Awesome Oscillator from the specified periods.
208  /// </summary>
209  /// <param name="symbol">The symbol whose Awesome Oscillator we seek</param>
210  /// <param name="resolution">The resolution.</param>
211  /// <param name="fastPeriod">The period of the fast moving average associated with the AO</param>
212  /// <param name="slowPeriod">The period of the slow moving average associated with the AO</param>
213  /// <param name="type">The type of moving average used when computing the fast and slow term. Defaults to simple moving average.</param>
214  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to casting the input value to a TradeBar</param>
215  [DocumentationAttribute(Indicators)]
216  public AwesomeOscillator AO(Symbol symbol, int fastPeriod, int slowPeriod, MovingAverageType type, Resolution? resolution = null, Func<IBaseData, IBaseDataBar> selector = null)
217  {
218  var name = CreateIndicatorName(symbol, $"AO({fastPeriod},{slowPeriod},{type})", resolution);
219  var awesomeOscillator = new AwesomeOscillator(name, fastPeriod, slowPeriod, type);
220  InitializeIndicator(awesomeOscillator, resolution, selector, symbol);
221 
222  return awesomeOscillator;
223  }
224 
225  /// <summary>
226  /// Creates a new AverageDirectionalMovementIndexRating indicator.
227  /// </summary>
228  /// <param name="symbol">The symbol whose ADXR we want</param>
229  /// <param name="period">The period over which to compute the ADXR</param>
230  /// <param name="resolution">The resolution.</param>
231  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
232  /// <returns>The AverageDirectionalMovementIndexRating indicator for the requested symbol over the specified period</returns>
233  [DocumentationAttribute(Indicators)]
234  public AverageDirectionalMovementIndexRating ADXR(Symbol symbol, int period, Resolution? resolution = null, Func<IBaseData, IBaseDataBar> selector = null)
235  {
236  var name = CreateIndicatorName(symbol, $"ADXR({period})", resolution);
237  var averageDirectionalMovementIndexRating = new AverageDirectionalMovementIndexRating(name, period);
238  InitializeIndicator(averageDirectionalMovementIndexRating, resolution, selector, symbol);
239 
240  return averageDirectionalMovementIndexRating;
241  }
242 
243  /// <summary>
244  /// Creates a new ArnaudLegouxMovingAverage indicator.
245  /// </summary>
246  /// <param name="symbol">The symbol whose ALMA we want</param>
247  /// <param name="period">int - the number of periods to calculate the ALMA</param>
248  /// <param name="sigma"> int - this parameter is responsible for the shape of the curve coefficients.
249  /// </param>
250  /// <param name="offset">
251  /// decimal - This parameter allows regulating the smoothness and high sensitivity of the
252  /// Moving Average. The range for this parameter is [0, 1].
253  /// </param>
254  /// <param name="resolution">The resolution</param>
255  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
256  /// <returns>The ArnaudLegouxMovingAverage indicator for the requested symbol over the specified period</returns>
257  [DocumentationAttribute(Indicators)]
258  public ArnaudLegouxMovingAverage ALMA(Symbol symbol, int period, int sigma = 6, decimal offset = 0.85m, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
259  {
260  var name = CreateIndicatorName(symbol, $"ALMA({period},{sigma},{offset})", resolution);
261  var arnaudLegouxMovingAverage = new ArnaudLegouxMovingAverage(name, period, sigma, offset);
262  InitializeIndicator(arnaudLegouxMovingAverage, resolution, selector, symbol);
263 
264  return arnaudLegouxMovingAverage;
265  }
266 
267  /// <summary>
268  /// Creates a new AbsolutePriceOscillator indicator.
269  /// </summary>
270  /// <param name="symbol">The symbol whose APO we want</param>
271  /// <param name="fastPeriod">The fast moving average period</param>
272  /// <param name="slowPeriod">The slow moving average period</param>
273  /// <param name="movingAverageType">The type of moving average to use</param>
274  /// <param name="resolution">The resolution</param>
275  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
276  /// <returns>The AbsolutePriceOscillator indicator for the requested symbol over the specified period</returns>
277  [DocumentationAttribute(Indicators)]
278  public AbsolutePriceOscillator APO(Symbol symbol, int fastPeriod, int slowPeriod, MovingAverageType movingAverageType, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
279  {
280  var name = CreateIndicatorName(symbol, $"APO({fastPeriod},{slowPeriod})", resolution);
281  var absolutePriceOscillator = new AbsolutePriceOscillator(name, fastPeriod, slowPeriod, movingAverageType);
282  InitializeIndicator(absolutePriceOscillator, resolution, selector, symbol);
283 
284  return absolutePriceOscillator;
285  }
286 
287  /// <summary>
288  /// Creates a new AroonOscillator indicator which will compute the AroonUp and AroonDown (as well as the delta)
289  /// </summary>
290  /// <param name="symbol">The symbol whose Aroon we seek</param>
291  /// <param name="period">The look back period for computing number of periods since maximum and minimum</param>
292  /// <param name="resolution">The resolution</param>
293  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to casting the input value to a TradeBar</param>
294  /// <returns>An AroonOscillator configured with the specified periods</returns>
295  [DocumentationAttribute(Indicators)]
296  public AroonOscillator AROON(Symbol symbol, int period, Resolution? resolution = null, Func<IBaseData, IBaseDataBar> selector = null)
297  {
298  return AROON(symbol, period, period, resolution, selector);
299  }
300 
301  /// <summary>
302  /// Creates a new AroonOscillator indicator which will compute the AroonUp and AroonDown (as well as the delta)
303  /// </summary>
304  /// <param name="symbol">The symbol whose Aroon we seek</param>
305  /// <param name="upPeriod">The look back period for computing number of periods since maximum</param>
306  /// <param name="downPeriod">The look back period for computing number of periods since minimum</param>
307  /// <param name="resolution">The resolution</param>
308  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to casting the input value to a TradeBar</param>
309  /// <returns>An AroonOscillator configured with the specified periods</returns>
310  [DocumentationAttribute(Indicators)]
311  public AroonOscillator AROON(Symbol symbol, int upPeriod, int downPeriod, Resolution? resolution = null, Func<IBaseData, IBaseDataBar> selector = null)
312  {
313  var name = CreateIndicatorName(symbol, $"AROON({upPeriod},{downPeriod})", resolution);
314  var aroonOscillator = new AroonOscillator(name, upPeriod, downPeriod);
315  InitializeIndicator(aroonOscillator, resolution, selector, symbol);
316 
317  return aroonOscillator;
318  }
319 
320  /// <summary>
321  /// Creates a new AverageTrueRange indicator for the symbol. The indicator will be automatically
322  /// updated on the given resolution.
323  /// </summary>
324  /// <param name="symbol">The symbol whose ATR we want</param>
325  /// <param name="period">The smoothing period used to smooth the computed TrueRange values</param>
326  /// <param name="type">The type of smoothing to use</param>
327  /// <param name="resolution">The resolution</param>
328  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to casting the input value to a TradeBar</param>
329  /// <returns>A new AverageTrueRange indicator with the specified smoothing type and period</returns>
330  [DocumentationAttribute(Indicators)]
331  public AverageTrueRange ATR(Symbol symbol, int period, MovingAverageType type = MovingAverageType.Simple, Resolution? resolution = null, Func<IBaseData, IBaseDataBar> selector = null)
332  {
333  var name = CreateIndicatorName(symbol, $"ATR({period})", resolution);
334  var averageTrueRange = new AverageTrueRange(name, period, type);
335  InitializeIndicator(averageTrueRange, resolution, selector, symbol);
336 
337  return averageTrueRange;
338  }
339 
340  /// <summary>
341  /// Creates an AugenPriceSpike indicator for the symbol. The indicator will be automatically
342  /// updated on the given resolution.
343  /// </summary>
344  /// <param name="symbol">The symbol whose APS we want</param>
345  /// <param name="period">The period of the APS</param>
346  /// <param name="resolution">The resolution</param>
347  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
348  /// <returns>The AugenPriceSpike indicator for the given parameters</returns>
349  [DocumentationAttribute(Indicators)]
350  public AugenPriceSpike APS(Symbol symbol, int period = 3, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
351  {
352  var name = CreateIndicatorName(symbol, $"APS({period})", resolution);
353  var augenPriceSpike = new AugenPriceSpike(name, period);
354  InitializeIndicator(augenPriceSpike, resolution, selector, symbol);
355 
356  return augenPriceSpike;
357  }
358 
359  /// <summary>
360  /// Creates a new BollingerBands indicator which will compute the MiddleBand, UpperBand, LowerBand, and StandardDeviation
361  /// </summary>
362  /// <param name="symbol">The symbol whose BollingerBands we seek</param>
363  /// <param name="period">The period of the standard deviation and moving average (middle band)</param>
364  /// <param name="k">The number of standard deviations specifying the distance between the middle band and upper or lower bands</param>
365  /// <param name="movingAverageType">The type of moving average to be used</param>
366  /// <param name="resolution">The resolution</param>
367  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
368  /// <returns>A BollingerBands configured with the specified period</returns>
369  [DocumentationAttribute(Indicators)]
370  public BollingerBands BB(Symbol symbol, int period, decimal k, MovingAverageType movingAverageType = MovingAverageType.Simple,
371  Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
372  {
373  var name = CreateIndicatorName(symbol, $"BB({period},{k})", resolution);
374  var bollingerBands = new BollingerBands(name, period, k, movingAverageType);
375  InitializeIndicator(bollingerBands, resolution, selector, symbol);
376 
377  return bollingerBands;
378  }
379 
380  /// <summary>
381  /// Creates a Beta indicator for the given target symbol in relation with the reference used.
382  /// The indicator will be automatically updated on the given resolution.
383  /// </summary>
384  /// <param name="target">The target symbol whose Beta value we want</param>
385  /// <param name="reference">The reference symbol to compare with the target symbol</param>
386  /// <param name="period">The period of the Beta indicator</param>
387  /// <param name="resolution">The resolution</param>
388  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to casting the input value to a TradeBar</param>
389  /// <returns>The Beta indicator for the given parameters</returns>
390  [DocumentationAttribute(Indicators)]
391  public Beta B(Symbol target, Symbol reference, int period, Resolution? resolution = null, Func<IBaseData, IBaseDataBar> selector = null)
392  {
393  var name = CreateIndicatorName(QuantConnect.Symbol.None, $"B({period})", resolution);
394  var beta = new Beta(name, target, reference, period);
395  InitializeIndicator(beta, resolution, selector, target, reference);
396 
397  return beta;
398  }
399 
400  /// <summary>
401  /// Creates a new Balance Of Power indicator.
402  /// The indicator will be automatically updated on the given resolution.
403  /// </summary>
404  /// <param name="symbol">The symbol whose Balance Of Power we seek</param>
405  /// <param name="resolution">The resolution.</param>
406  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to casting the input value to a TradeBar</param>
407  /// <returns>The Balance Of Power indicator for the requested symbol.</returns>
408  [DocumentationAttribute(Indicators)]
409  public BalanceOfPower BOP(Symbol symbol, Resolution? resolution = null, Func<IBaseData, IBaseDataBar> selector = null)
410  {
411  var name = CreateIndicatorName(symbol, "BOP", resolution);
412  var balanceOfPower = new BalanceOfPower(name);
413  InitializeIndicator(balanceOfPower, resolution, selector, symbol);
414 
415  return balanceOfPower;
416  }
417 
418  /// <summary>
419  /// Initializes a new instance of the <see cref="CoppockCurve"/> indicator
420  /// </summary>
421  /// <param name="symbol">The symbol whose Coppock Curve we want</param>
422  /// <param name="shortRocPeriod">The period for the short ROC</param>
423  /// <param name="longRocPeriod">The period for the long ROC</param>
424  /// <param name="lwmaPeriod">The period for the LWMA</param>
425  /// <param name="resolution">The resolution</param>
426  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to casting the input value to a TradeBar</param>
427  /// <returns>The Coppock Curve indicator for the requested symbol over the specified period</returns>
428  [DocumentationAttribute(Indicators)]
429  public CoppockCurve CC(Symbol symbol, int shortRocPeriod = 11, int longRocPeriod = 14, int lwmaPeriod = 10, Resolution? resolution = null,
430  Func<IBaseData, decimal> selector = null)
431  {
432  var name = CreateIndicatorName(symbol, $"CC({shortRocPeriod},{longRocPeriod},{lwmaPeriod})", resolution);
433  var coppockCurve = new CoppockCurve(name, shortRocPeriod, longRocPeriod, lwmaPeriod);
434  InitializeIndicator(coppockCurve, resolution, selector, symbol);
435 
436  return coppockCurve;
437  }
438 
439  /// <summary>
440  /// Creates a Correlation indicator for the given target symbol in relation with the reference used.
441  /// The indicator will be automatically updated on the given resolution.
442  /// </summary>
443  /// <param name="target">The target symbol of this indicator</param>
444  /// <param name="reference">The reference symbol of this indicator</param>
445  /// <param name="period">The period of this indicator</param>
446  /// <param name="correlationType">Correlation type</param>
447  /// <param name="resolution">The resolution</param>
448  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to casting the input value to a TradeBar</param>
449  /// <returns>The Correlation indicator for the given parameters</returns>
450  [DocumentationAttribute(Indicators)]
451  public Correlation C(Symbol target, Symbol reference, int period, CorrelationType correlationType = CorrelationType.Pearson, Resolution? resolution = null, Func<IBaseData, IBaseDataBar> selector = null)
452  {
453  var name = CreateIndicatorName(QuantConnect.Symbol.None, $"C({period})", resolution);
454  var correlation = new Correlation(name, target, reference, period);
455  InitializeIndicator(correlation, resolution, selector, target, reference);
456 
457  return correlation;
458  }
459 
460  /// <summary>
461  /// Creates a new CommodityChannelIndex indicator. The indicator will be automatically
462  /// updated on the given resolution.
463  /// </summary>
464  /// <param name="symbol">The symbol whose CCI we want</param>
465  /// <param name="period">The period over which to compute the CCI</param>
466  /// <param name="movingAverageType">The type of moving average to use in computing the typical price average</param>
467  /// <param name="resolution">The resolution</param>
468  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to casting the input value to a TradeBar</param>
469  /// <returns>The CommodityChannelIndex indicator for the requested symbol over the specified period</returns>
470  [DocumentationAttribute(Indicators)]
471  public CommodityChannelIndex CCI(Symbol symbol, int period, MovingAverageType movingAverageType = MovingAverageType.Simple, Resolution? resolution = null, Func<IBaseData, IBaseDataBar> selector = null)
472  {
473  var name = CreateIndicatorName(symbol, $"CCI({period})", resolution);
474  var commodityChannelIndex = new CommodityChannelIndex(name, period, movingAverageType);
475  InitializeIndicator(commodityChannelIndex, resolution, selector, symbol);
476 
477  return commodityChannelIndex;
478  }
479 
480  /// <summary>
481  /// Creates a new ChoppinessIndex indicator for the symbol. The indicator will be automatically
482  /// updated on the given resolution.
483  /// </summary>
484  /// <param name="symbol">The symbol whose CHOP we want</param>
485  /// <param name="period">The input window period used to calculate max high and min low</param>
486  /// <param name="resolution">The resolution</param>
487  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to casting the input value to a TradeBar</param>
488  /// <returns>A new ChoppinessIndex indicator with the window period</returns>
489  [DocumentationAttribute(Indicators)]
490  public ChoppinessIndex CHOP(Symbol symbol, int period, Resolution? resolution = null, Func<IBaseData, IBaseDataBar> selector = null)
491  {
492  var name = CreateIndicatorName(symbol, $"CHOP({period})", resolution);
493  var indicator = new ChoppinessIndex(name, period);
494  InitializeIndicator(indicator, resolution, selector, symbol);
495  return indicator;
496  }
497 
498  /// <summary>
499  /// Creates a new Chande Kroll Stop indicator which will compute the short and lower stop.
500  /// The indicator will be automatically updated on the given resolution.
501  /// </summary>
502  /// <param name="symbol">The symbol whose Chande Kroll Stop we seek.</param>
503  /// <param name="atrPeriod">The period over which to compute the average true range.</param>
504  /// <param name="atrMult">The ATR multiplier to be used to compute stops distance.</param>
505  /// <param name="period">The period over which to compute the max of high stop and min of low stop.</param>
506  /// <param name="resolution">The resolution.</param>
507  /// <param name="movingAverageType">The type of smoothing used to smooth the true range values</param>
508  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to casting the input value to a TradeBar</param>
509  /// <returns>The Chande Kroll Stop indicator for the requested symbol.</returns>
510  [DocumentationAttribute(Indicators)]
511  public ChandeKrollStop CKS(Symbol symbol, int atrPeriod, decimal atrMult, int period, MovingAverageType movingAverageType = MovingAverageType.Wilders, Resolution? resolution = null, Func<IBaseData, IBaseDataBar> selector = null)
512  {
513  var name = CreateIndicatorName(symbol, $"CKS({atrPeriod},{atrMult},{period})", resolution);
514  var indicator = new ChandeKrollStop(name, atrPeriod, atrMult, period, movingAverageType);
515  InitializeIndicator(indicator, resolution, selector, symbol);
516  return indicator;
517  }
518 
519  /// <summary>
520  /// Creates a new ChaikinMoneyFlow indicator.
521  /// </summary>
522  /// <param name="symbol">The symbol whose CMF we want</param>
523  /// <param name="period">The period over which to compute the CMF</param>
524  /// <param name="resolution">The resolution</param>
525  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to casting the input value to a TradeBar</param>
526  /// <returns>The ChaikinMoneyFlow indicator for the requested symbol over the specified period</returns>
527  [DocumentationAttribute(Indicators)]
528  public ChaikinMoneyFlow CMF(Symbol symbol, int period, Resolution? resolution = null, Func<IBaseData, TradeBar> selector = null)
529  {
530  var name = CreateIndicatorName(symbol, $"CMF({period})", resolution);
531  var chaikinMoneyFlow = new ChaikinMoneyFlow(name, period);
532  InitializeIndicator(chaikinMoneyFlow, resolution, selector, symbol);
533 
534  return chaikinMoneyFlow;
535 
536  }
537 
538  /// <summary>
539  /// Creates a new ChandeMomentumOscillator indicator.
540  /// </summary>
541  /// <param name="symbol">The symbol whose CMO we want</param>
542  /// <param name="period">The period over which to compute the CMO</param>
543  /// <param name="resolution">The resolution</param>
544  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
545  /// <returns>The ChandeMomentumOscillator indicator for the requested symbol over the specified period</returns>
546  [DocumentationAttribute(Indicators)]
547  public ChandeMomentumOscillator CMO(Symbol symbol, int period, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
548  {
549  var name = CreateIndicatorName(symbol, $"CMO({period})", resolution);
550  var chandeMomentumOscillator = new ChandeMomentumOscillator(name, period);
551  InitializeIndicator(chandeMomentumOscillator, resolution, selector, symbol);
552 
553  return chandeMomentumOscillator;
554  }
555 
556  ///<summary>
557  /// Creates a new DeMarker Indicator (DEM), an oscillator-type indicator measuring changes in terms of an asset's
558  /// High and Low tradebar values.
559  ///</summary>
560  /// <param name="symbol">The symbol whose DEM we seek.</param>
561  /// <param name="period">The period of the moving average implemented</param>
562  /// <param name="type">Specifies the type of moving average to be used</param>
563  /// <param name="resolution">The resolution.</param>
564  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to casting the input value to a TradeBar</param>
565  /// <returns>The DeMarker indicator for the requested symbol.</returns>
566  [DocumentationAttribute(Indicators)]
567  public DeMarkerIndicator DEM(Symbol symbol, int period, MovingAverageType type, Resolution? resolution = null, Func<IBaseData, TradeBar> selector = null)
568  {
569  var name = CreateIndicatorName(symbol, $"DEM({period},{type})", resolution);
570  var deMarkerIndicator = new DeMarkerIndicator(name, period, type);
571  InitializeIndicator(deMarkerIndicator, resolution, selector, symbol);
572  return deMarkerIndicator;
573  }
574 
575  /// <summary>
576  /// Creates a new Donchian Channel indicator which will compute the Upper Band and Lower Band.
577  /// The indicator will be automatically updated on the given resolution.
578  /// </summary>
579  /// <param name="symbol">The symbol whose Donchian Channel we seek.</param>
580  /// <param name="upperPeriod">The period over which to compute the upper Donchian Channel.</param>
581  /// <param name="lowerPeriod">The period over which to compute the lower Donchian Channel.</param>
582  /// <param name="resolution">The resolution.</param>
583  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to casting the input value to a TradeBar</param>
584  /// <returns>The Donchian Channel indicator for the requested symbol.</returns>
585  [DocumentationAttribute(Indicators)]
586  public DonchianChannel DCH(Symbol symbol, int upperPeriod, int lowerPeriod, Resolution? resolution = null, Func<IBaseData, IBaseDataBar> selector = null)
587  {
588  var name = CreateIndicatorName(symbol, $"DCH({upperPeriod},{lowerPeriod})", resolution);
589  var donchianChannel = new DonchianChannel(name, upperPeriod, lowerPeriod);
590  InitializeIndicator(donchianChannel, resolution, selector, symbol);
591 
592  return donchianChannel;
593  }
594 
595  /// <summary>
596  /// Overload shorthand to create a new symmetric Donchian Channel indicator which
597  /// has the upper and lower channels set to the same period length.
598  /// </summary>
599  /// <param name="symbol">The symbol whose Donchian Channel we seek.</param>
600  /// <param name="period">The period over which to compute the Donchian Channel.</param>
601  /// <param name="resolution">The resolution.</param>
602  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to casting the input value to a TradeBar</param>
603  /// <returns>The Donchian Channel indicator for the requested symbol.</returns>
604  [DocumentationAttribute(Indicators)]
605  public DonchianChannel DCH(Symbol symbol, int period, Resolution? resolution = null, Func<IBaseData, IBaseDataBar> selector = null)
606  {
607  return DCH(symbol, period, period, resolution, selector);
608  }
609 
610  /// <summary>
611  /// Creates a new Delta indicator for the symbol The indicator will be automatically
612  /// updated on the symbol's subscription resolution
613  /// </summary>
614  /// <param name="symbol">The option symbol whose values we want as an indicator</param>
615  /// <param name="mirrorOption">The mirror option for parity calculation</param>
616  /// <param name="riskFreeRate">The risk free rate</param>
617  /// <param name="dividendYield">The dividend yield</param>
618  /// <param name="optionModel">The option pricing model used to estimate Delta</param>
619  /// <param name="ivModel">The option pricing model used to estimate IV</param>
620  /// <param name="resolution">The desired resolution of the data</param>
621  /// <returns>A new Delta indicator for the specified symbol</returns>
622  [DocumentationAttribute(Indicators)]
623  public Delta D(Symbol symbol, Symbol mirrorOption = null, decimal? riskFreeRate = null, decimal? dividendYield = null,
624  OptionPricingModelType? optionModel = null, OptionPricingModelType? ivModel = null, Resolution? resolution = null)
625  {
626  var name = InitializeOptionIndicator<Delta>(symbol, out var riskFreeRateModel, out var dividendYieldModel, riskFreeRate, dividendYield, optionModel, resolution);
627 
628  var delta = new Delta(name, symbol, riskFreeRateModel, dividendYieldModel, mirrorOption, optionModel, ivModel);
629  InitializeOptionIndicator(delta, resolution, symbol, mirrorOption);
630  return delta;
631  }
632 
633  /// <summary>
634  /// Creates a new Delta indicator for the symbol The indicator will be automatically
635  /// updated on the symbol's subscription resolution
636  /// </summary>
637  /// <param name="symbol">The option symbol whose values we want as an indicator</param>
638  /// <param name="mirrorOption">The mirror option for parity calculation</param>
639  /// <param name="riskFreeRate">The risk free rate</param>
640  /// <param name="dividendYield">The dividend yield</param>
641  /// <param name="optionModel">The option pricing model used to estimate Delta</param>
642  /// <param name="ivModel">The option pricing model used to estimate IV</param>
643  /// <param name="resolution">The desired resolution of the data</param>
644  /// <returns>A new Delta indicator for the specified symbol</returns>
645  [DocumentationAttribute(Indicators)]
646  public Delta Δ(Symbol symbol, Symbol mirrorOption = null, decimal? riskFreeRate = null, decimal? dividendYield = null, OptionPricingModelType optionModel = OptionPricingModelType.BlackScholes,
647  OptionPricingModelType? ivModel = null, Resolution? resolution = null)
648  {
649  return D(symbol, mirrorOption, riskFreeRate, dividendYield, optionModel, ivModel, resolution);
650  }
651 
652  /// <summary>
653  /// Creates a new DoubleExponentialMovingAverage indicator.
654  /// </summary>
655  /// <param name="symbol">The symbol whose DEMA we want</param>
656  /// <param name="period">The period over which to compute the DEMA</param>
657  /// <param name="resolution">The resolution</param>
658  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
659  /// <returns>The DoubleExponentialMovingAverage indicator for the requested symbol over the specified period</returns>
660  [DocumentationAttribute(Indicators)]
661  public DoubleExponentialMovingAverage DEMA(Symbol symbol, int period, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
662  {
663  var name = CreateIndicatorName(symbol, $"DEMA({period})", resolution);
664  var doubleExponentialMovingAverage = new DoubleExponentialMovingAverage(name, period);
665  InitializeIndicator(doubleExponentialMovingAverage, resolution, selector, symbol);
666 
667  return doubleExponentialMovingAverage;
668  }
669 
670  /// <summary>
671  /// Creates a new DerivativeOscillator indicator.
672  /// </summary>
673  /// <param name="symbol">The symbol whose DO we want</param>
674  /// <param name="rsiPeriod">The period over which to compute the RSI</param>
675  /// <param name="smoothingRsiPeriod">The period over which to compute the smoothing RSI</param>
676  /// <param name="doubleSmoothingRsiPeriod">The period over which to compute the double smoothing RSI</param>
677  /// <param name="signalLinePeriod">The period over which to compute the signal line</param>
678  /// <param name="resolution">The resolution</param>
679  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x =&gt; x.Value)</param>
680  /// <returns>The DerivativeOscillator indicator for the requested symbol over the specified period</returns>
681  [DocumentationAttribute(Indicators)]
682  public DerivativeOscillator DO(Symbol symbol, int rsiPeriod, int smoothingRsiPeriod, int doubleSmoothingRsiPeriod, int signalLinePeriod, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
683  {
684  var name = CreateIndicatorName(symbol, $"DO({rsiPeriod},{smoothingRsiPeriod},{doubleSmoothingRsiPeriod},{signalLinePeriod})", resolution);
685  var derivativeOscillator = new DerivativeOscillator(name, rsiPeriod, smoothingRsiPeriod, doubleSmoothingRsiPeriod, signalLinePeriod);
686  InitializeIndicator(derivativeOscillator, resolution, selector, symbol);
687 
688  return derivativeOscillator;
689  }
690 
691  /// <summary>
692  /// Creates a new <see cref="DetrendedPriceOscillator"/> indicator.
693  /// </summary>
694  /// <param name="symbol">The symbol whose DPO we want</param>
695  /// <param name="period">The period over which to compute the DPO</param>
696  /// <param name="resolution">The resolution</param>
697  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
698  /// <returns>A new registered DetrendedPriceOscillator indicator for the requested symbol over the specified period</returns>
699  [DocumentationAttribute(Indicators)]
700  public DetrendedPriceOscillator DPO(Symbol symbol, int period, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
701  {
702  var name = CreateIndicatorName(symbol, $"DPO({period})", resolution);
703  var detrendedPriceOscillator = new DetrendedPriceOscillator(name, period);
704  InitializeIndicator(detrendedPriceOscillator, resolution, selector, symbol);
705 
706  return detrendedPriceOscillator;
707  }
708 
709  /// <summary>
710  /// Creates an ExponentialMovingAverage indicator for the symbol. The indicator will be automatically
711  /// updated on the given resolution.
712  /// </summary>
713  /// <param name="symbol">The symbol whose EMA we want</param>
714  /// <param name="period">The period of the EMA</param>
715  /// <param name="resolution">The resolution</param>
716  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
717  /// <returns>The ExponentialMovingAverage for the given parameters</returns>
718  [DocumentationAttribute(Indicators)]
719  public ExponentialMovingAverage EMA(Symbol symbol, int period, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
720  {
721  return EMA(symbol, period, ExponentialMovingAverage.SmoothingFactorDefault(period), resolution, selector);
722  }
723 
724  /// <summary>
725  /// Creates an ExponentialMovingAverage indicator for the symbol. The indicator will be automatically
726  /// updated on the given resolution.
727  /// </summary>
728  /// <param name="symbol">The symbol whose EMA we want</param>
729  /// <param name="period">The period of the EMA</param>
730  /// <param name="smoothingFactor">The percentage of data from the previous value to be carried into the next value</param>
731  /// <param name="resolution">The resolution</param>
732  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
733  /// <returns>The ExponentialMovingAverage for the given parameters</returns>
734  [DocumentationAttribute(Indicators)]
735  public ExponentialMovingAverage EMA(Symbol symbol, int period, decimal smoothingFactor, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
736  {
737  var name = CreateIndicatorName(symbol, $"EMA({period})", resolution);
738  var exponentialMovingAverage = new ExponentialMovingAverage(name, period, smoothingFactor);
739  InitializeIndicator(exponentialMovingAverage, resolution, selector, symbol);
740 
741  return exponentialMovingAverage;
742  }
743 
744  /// <summary>
745  /// Creates an EaseOfMovementValue indicator for the symbol. The indicator will be automatically
746  /// updated on the given resolution.
747  /// </summary>
748  /// <param name="symbol">The symbol whose EMV we want</param>
749  /// <param name="period">The period of the EMV</param>
750  /// <param name="scale">The length of the outputed value</param>
751  /// <param name="resolution">The resolution</param>
752  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to casting the input value to a TradeBar</param>
753  /// <returns>The EaseOfMovementValue indicator for the given parameters</returns>
754  [DocumentationAttribute(Indicators)]
755  public EaseOfMovementValue EMV(Symbol symbol, int period = 1, int scale = 10000, Resolution? resolution = null, Func<IBaseData, TradeBar> selector = null)
756  {
757  var name = CreateIndicatorName(symbol, $"EMV({period}, {scale})", resolution);
758  var easeOfMovementValue = new EaseOfMovementValue(name, period, scale);
759  InitializeIndicator(easeOfMovementValue, resolution, selector, symbol);
760 
761  return easeOfMovementValue;
762  }
763 
764  /// <summary>
765  /// Creates a new FilteredIdentity indicator for the symbol The indicator will be automatically
766  /// updated on the symbol's subscription resolution
767  /// </summary>
768  /// <param name="symbol">The symbol whose values we want as an indicator</param>
769  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to casting the input value to a TradeBar</param>
770  /// <param name="filter">Filters the IBaseData send into the indicator, if null defaults to true (x => true) which means no filter</param>
771  /// <param name="fieldName">The name of the field being selected</param>
772  /// <returns>A new FilteredIdentity indicator for the specified symbol and selector</returns>
773  [DocumentationAttribute(Indicators)]
774  public FilteredIdentity FilteredIdentity(Symbol symbol, Func<IBaseData, IBaseDataBar> selector = null, Func<IBaseData, bool> filter = null, string fieldName = null)
775  {
776  var resolution = GetSubscription(symbol).Resolution;
777  return FilteredIdentity(symbol, resolution, selector, filter, fieldName);
778  }
779 
780  /// <summary>
781  /// Creates a new FilteredIdentity indicator for the symbol The indicator will be automatically
782  /// updated on the symbol's subscription resolution
783  /// </summary>
784  /// <param name="symbol">The symbol whose values we want as an indicator</param>
785  /// <param name="resolution">The desired resolution of the data</param>
786  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to casting the input value to a TradeBar</param>
787  /// <param name="filter">Filters the IBaseData send into the indicator, if null defaults to true (x => true) which means no filter</param>
788  /// <param name="fieldName">The name of the field being selected</param>
789  /// <returns>A new FilteredIdentity indicator for the specified symbol and selector</returns>
790  [DocumentationAttribute(Indicators)]
791  public FilteredIdentity FilteredIdentity(Symbol symbol, Resolution resolution, Func<IBaseData, IBaseDataBar> selector = null, Func<IBaseData, bool> filter = null, string fieldName = null)
792  {
793  var name = CreateIndicatorName(symbol, fieldName ?? "close", resolution);
794  var filteredIdentity = new FilteredIdentity(name, filter);
795  RegisterIndicator<IBaseData>(symbol, filteredIdentity, resolution, selector);
796  return filteredIdentity;
797  }
798 
799  /// <summary>
800  /// Creates a new FilteredIdentity indicator for the symbol The indicator will be automatically
801  /// updated on the symbol's subscription resolution
802  /// </summary>
803  /// <param name="symbol">The symbol whose values we want as an indicator</param>
804  /// <param name="resolution">The desired resolution of the data</param>
805  /// <param name="selector">Selects a value from the BaseData, if null defaults to the .Value property (x => x.Value)</param>
806  /// <param name="filter">Filters the IBaseData send into the indicator, if null defaults to true (x => true) which means no filter</param>
807  /// <param name="fieldName">The name of the field being selected</param>
808  /// <returns>A new FilteredIdentity indicator for the specified symbol and selector</returns>
809  [DocumentationAttribute(Indicators)]
810  public FilteredIdentity FilteredIdentity(Symbol symbol, TimeSpan resolution, Func<IBaseData, IBaseDataBar> selector = null, Func<IBaseData, bool> filter = null, string fieldName = null)
811  {
812  var name = Invariant($"{symbol}({fieldName ?? "close"}_{resolution})");
813  var filteredIdentity = new FilteredIdentity(name, filter);
814  RegisterIndicator<IBaseData>(symbol, filteredIdentity, ResolveConsolidator(symbol, resolution), selector);
815  return filteredIdentity;
816  }
817 
818  /// <summary>
819  /// Creates a new ForceIndex indicator for the symbol. The indicator will be automatically
820  /// updated on the given resolution.
821  /// </summary>
822  /// <param name="symbol">The symbol whose ForceIndex we want</param>
823  /// <param name="period">The smoothing period used to smooth the computed ForceIndex values</param>
824  /// <param name="type">The type of smoothing to use</param>
825  /// <param name="resolution">The resolution</param>
826  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to casting the input value to a TradeBar</param>
827  /// <returns>A new ForceIndex indicator with the specified smoothing type and period</returns>
828  [DocumentationAttribute(Indicators)]
829  public ForceIndex FI(Symbol symbol, int period, MovingAverageType type = MovingAverageType.Exponential, Resolution? resolution = null, Func<IBaseData, TradeBar> selector = null)
830  {
831  var name = CreateIndicatorName(symbol, $"FI({period})", resolution);
832  var indicator = new ForceIndex(name, period, type);
833  InitializeIndicator(indicator, resolution, selector, symbol);
834 
835  return indicator;
836  }
837 
838  /// <summary>
839  /// Creates an FisherTransform indicator for the symbol.
840  /// The indicator will be automatically updated on the given resolution.
841  /// </summary>
842  /// <param name="symbol">The symbol whose FisherTransform we want</param>
843  /// <param name="period">The period of the FisherTransform</param>
844  /// <param name="resolution">The resolution</param>
845  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to casting the input value to a TradeBar</param>
846  /// <returns>The FisherTransform for the given parameters</returns>
847  [DocumentationAttribute(Indicators)]
848  public FisherTransform FISH(Symbol symbol, int period, Resolution? resolution = null, Func<IBaseData, TradeBar> selector = null)
849  {
850  var name = CreateIndicatorName(symbol, $"FISH({period})", resolution);
851  var fisherTransform = new FisherTransform(name, period);
852  InitializeIndicator(fisherTransform, resolution, selector, symbol);
853 
854  return fisherTransform;
855  }
856 
857 
858  /// <summary>
859  /// Creates an FractalAdaptiveMovingAverage (FRAMA) indicator for the symbol. The indicator will be automatically
860  /// updated on the given resolution.
861  /// </summary>
862  /// <param name="symbol">The symbol whose FRAMA we want</param>
863  /// <param name="period">The period of the FRAMA</param>
864  /// <param name="longPeriod">The long period of the FRAMA</param>
865  /// <param name="resolution">The resolution</param>
866  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to casting the input value to a TradeBar</param>
867  /// <returns>The FRAMA for the given parameters</returns>
868  [DocumentationAttribute(Indicators)]
869  public FractalAdaptiveMovingAverage FRAMA(Symbol symbol, int period, int longPeriod = 198, Resolution? resolution = null, Func<IBaseData, IBaseDataBar> selector = null)
870  {
871  var name = CreateIndicatorName(symbol, $"FRAMA({period},{longPeriod})", resolution);
872  var fractalAdaptiveMovingAverage = new FractalAdaptiveMovingAverage(name, period, longPeriod);
873  InitializeIndicator(fractalAdaptiveMovingAverage, resolution, selector, symbol);
874 
875  return fractalAdaptiveMovingAverage;
876  }
877 
878  /// <summary>
879  /// Creates a new Gamma indicator for the symbol The indicator will be automatically
880  /// updated on the symbol's subscription resolution
881  /// </summary>
882  /// <param name="symbol">The option symbol whose values we want as an indicator</param>
883  /// <param name="mirrorOption">The mirror option for parity calculation</param>
884  /// <param name="riskFreeRate">The risk free rate</param>
885  /// <param name="dividendYield">The dividend yield</param>
886  /// <param name="optionModel">The option pricing model used to estimate Gamma</param>
887  /// <param name="ivModel">The option pricing model used to estimate IV</param>
888  /// <param name="resolution">The desired resolution of the data</param>
889  /// <returns>A new Gamma indicator for the specified symbol</returns>
890  [DocumentationAttribute(Indicators)]
891  public Gamma G(Symbol symbol, Symbol mirrorOption = null, decimal? riskFreeRate = null, decimal? dividendYield = null,
892  OptionPricingModelType? optionModel = null, OptionPricingModelType? ivModel = null, Resolution? resolution = null)
893  {
894  var name = InitializeOptionIndicator<Gamma>(symbol, out var riskFreeRateModel, out var dividendYieldModel, riskFreeRate, dividendYield, optionModel, resolution);
895 
896  var gamma = new Gamma(name, symbol, riskFreeRateModel, dividendYieldModel, mirrorOption, optionModel, ivModel);
897  InitializeOptionIndicator(gamma, resolution, symbol, mirrorOption);
898  return gamma;
899  }
900 
901  /// <summary>
902  /// Creates a new Gamma indicator for the symbol The indicator will be automatically
903  /// updated on the symbol's subscription resolution
904  /// </summary>
905  /// <param name="symbol">The option symbol whose values we want as an indicator</param>
906  /// <param name="mirrorOption">The mirror option for parity calculation</param>
907  /// <param name="riskFreeRate">The risk free rate</param>
908  /// <param name="dividendYield">The dividend yield</param>
909  /// <param name="optionModel">The option pricing model used to estimate Gamma</param>
910  /// <param name="ivModel">The option pricing model used to estimate IV</param>
911  /// <param name="resolution">The desired resolution of the data</param>
912  /// <returns>A new Gamma indicator for the specified symbol</returns>
913  [DocumentationAttribute(Indicators)]
914  public Gamma Γ(Symbol symbol, Symbol mirrorOption = null, decimal? riskFreeRate = null, decimal? dividendYield = null, OptionPricingModelType optionModel = OptionPricingModelType.BlackScholes,
915  OptionPricingModelType? ivModel = null, Resolution? resolution = null)
916  {
917  return G(symbol, mirrorOption, riskFreeRate, dividendYield, optionModel, ivModel, resolution);
918  }
919 
920  /// <summary>
921  /// Creates a new Heikin-Ashi indicator.
922  /// </summary>
923  /// <param name="symbol">The symbol whose Heikin-Ashi we want</param>
924  /// <param name="resolution">The resolution</param>
925  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to casting the input value to a TradeBar</param>
926  /// <returns>The Heikin-Ashi indicator for the requested symbol over the specified period</returns>
927  [DocumentationAttribute(Indicators)]
928  public HeikinAshi HeikinAshi(Symbol symbol, Resolution? resolution = null, Func<IBaseData, TradeBar> selector = null)
929  {
930  var name = CreateIndicatorName(symbol, "HA", resolution);
931  var heikinAshi = new HeikinAshi(name);
932  InitializeIndicator(heikinAshi, resolution, selector, symbol);
933 
934  return heikinAshi;
935  }
936 
937  /// <summary>
938  /// Creates a new Hilbert Transform indicator
939  /// </summary>
940  /// <param name="symbol">The symbol whose Hilbert transform we want</param>
941  /// <param name="length">The length of the FIR filter used in the calculation of the Hilbert Transform.
942  /// This parameter determines the number of filter coefficients in the FIR filter.</param>
943  /// <param name="inPhaseMultiplicationFactor">The multiplication factor used in the calculation of the in-phase component
944  /// of the Hilbert Transform. This parameter adjusts the sensitivity and responsiveness of
945  /// the transform to changes in the input signal.</param>
946  /// <param name="quadratureMultiplicationFactor">The multiplication factor used in the calculation of the quadrature component of
947  /// the Hilbert Transform. This parameter also adjusts the sensitivity and responsiveness of the
948  /// transform to changes in the input signal.</param>
949  /// <param name="resolution">The resolution</param>
950  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
951  [DocumentationAttribute(Indicators)]
952  public HilbertTransform HT(Symbol symbol, int length, decimal inPhaseMultiplicationFactor, decimal quadratureMultiplicationFactor, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
953  {
954  var name = CreateIndicatorName(symbol, $"HT({length}, {inPhaseMultiplicationFactor}, {quadratureMultiplicationFactor})", resolution);
955  var hilbertTransform = new HilbertTransform(length, inPhaseMultiplicationFactor, quadratureMultiplicationFactor);
956  InitializeIndicator(hilbertTransform, resolution, selector, symbol);
957 
958  return hilbertTransform;
959  }
960 
961  /// <summary>
962  /// Creates a new HullMovingAverage indicator. The Hull moving average is a series of nested weighted moving averages, is fast and smooth.
963  /// </summary>
964  /// <param name="symbol">The symbol whose Hull moving average we want</param>
965  /// <param name="period">The period over which to compute the Hull moving average</param>
966  /// <param name="resolution">The resolution</param>
967  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
968  /// <returns></returns>
969  [DocumentationAttribute(Indicators)]
970  public HullMovingAverage HMA(Symbol symbol, int period, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
971  {
972  var name = CreateIndicatorName(symbol, $"HMA({period})", resolution);
973  var hullMovingAverage = new HullMovingAverage(name, period);
974  InitializeIndicator(hullMovingAverage, resolution, selector, symbol);
975 
976  return hullMovingAverage;
977  }
978 
979  /// <summary>
980  /// Creates a new InternalBarStrength indicator for the symbol. The indicator will be automatically
981  /// updated on the given resolution.
982  /// </summary>
983  /// <param name="symbol">The symbol whose IBS we want</param>
984  /// <param name="resolution">The resolution</param>
985  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to casting the input value to a TradeBar</param>
986  /// <returns>A new InternalBarStrength indicator</returns>
987  [DocumentationAttribute(Indicators)]
988  public InternalBarStrength IBS(Symbol symbol, Resolution? resolution = null, Func<IBaseData, TradeBar> selector = null)
989  {
990  var name = CreateIndicatorName(symbol, "IBS", resolution);
991  var indicator = new InternalBarStrength(name);
992  InitializeIndicator(indicator, resolution, selector, symbol);
993 
994  return indicator;
995  }
996 
997  /// <summary>
998  /// Creates a new IchimokuKinkoHyo indicator for the symbol. The indicator will be automatically
999  /// updated on the given resolution.
1000  /// </summary>
1001  /// <param name="symbol">The symbol whose ICHIMOKU we want</param>
1002  /// <param name="tenkanPeriod">The period to calculate the Tenkan-sen period</param>
1003  /// <param name="kijunPeriod">The period to calculate the Kijun-sen period</param>
1004  /// <param name="senkouAPeriod">The period to calculate the Tenkan-sen period</param>
1005  /// <param name="senkouBPeriod">The period to calculate the Tenkan-sen period</param>
1006  /// <param name="senkouADelayPeriod">The period to calculate the Tenkan-sen period</param>
1007  /// <param name="senkouBDelayPeriod">The period to calculate the Tenkan-sen period</param>
1008  /// <param name="resolution">The resolution</param>
1009  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to casting the input value to a TradeBar</param>
1010  /// <returns>A new IchimokuKinkoHyo indicator with the specified periods and delays</returns>
1011  [DocumentationAttribute(Indicators)]
1012  public IchimokuKinkoHyo ICHIMOKU(Symbol symbol, int tenkanPeriod, int kijunPeriod, int senkouAPeriod, int senkouBPeriod,
1013  int senkouADelayPeriod, int senkouBDelayPeriod, Resolution? resolution = null, Func<IBaseData, TradeBar> selector = null)
1014  {
1015  var name = CreateIndicatorName(symbol, $"ICHIMOKU({tenkanPeriod},{kijunPeriod},{senkouAPeriod},{senkouBPeriod},{senkouADelayPeriod},{senkouBDelayPeriod})", resolution);
1016  var ichimokuKinkoHyo = new IchimokuKinkoHyo(name, tenkanPeriod, kijunPeriod, senkouAPeriod, senkouBPeriod, senkouADelayPeriod, senkouBDelayPeriod);
1017  InitializeIndicator(ichimokuKinkoHyo, resolution, selector, symbol);
1018 
1019  return ichimokuKinkoHyo;
1020  }
1021 
1022  /// <summary>
1023  /// Creates a new Identity indicator for the symbol The indicator will be automatically
1024  /// updated on the symbol's subscription resolution
1025  /// </summary>
1026  /// <param name="symbol">The symbol whose values we want as an indicator</param>
1027  /// <param name="selector">Selects a value from the BaseData, if null defaults to the .Value property (x => x.Value)</param>
1028  /// <param name="fieldName">The name of the field being selected</param>
1029  /// <returns>A new Identity indicator for the specified symbol and selector</returns>
1030  [DocumentationAttribute(Indicators)]
1031  public Identity Identity(Symbol symbol, Func<IBaseData, decimal> selector = null, string fieldName = null)
1032  {
1033  var resolution = GetSubscription(symbol).Resolution;
1034  return Identity(symbol, resolution, selector, fieldName);
1035  }
1036 
1037  /// <summary>
1038  /// Creates a new Identity indicator for the symbol The indicator will be automatically
1039  /// updated on the symbol's subscription resolution
1040  /// </summary>
1041  /// <param name="symbol">The symbol whose values we want as an indicator</param>
1042  /// <param name="resolution">The desired resolution of the data</param>
1043  /// <param name="selector">Selects a value from the BaseData, if null defaults to the .Value property (x => x.Value)</param>
1044  /// <param name="fieldName">The name of the field being selected</param>
1045  /// <returns>A new Identity indicator for the specified symbol and selector</returns>
1046  [DocumentationAttribute(Indicators)]
1047  public Identity Identity(Symbol symbol, Resolution resolution, Func<IBaseData, decimal> selector = null, string fieldName = null)
1048  {
1049  var name = CreateIndicatorName(symbol, fieldName ?? "close", resolution);
1050  var identity = new Identity(name);
1051  InitializeIndicator(identity, resolution, selector, symbol);
1052  return identity;
1053  }
1054 
1055  /// <summary>
1056  /// Creates a new Identity indicator for the symbol The indicator will be automatically
1057  /// updated on the symbol's subscription resolution
1058  /// </summary>
1059  /// <param name="symbol">The symbol whose values we want as an indicator</param>
1060  /// <param name="resolution">The desired resolution of the data</param>
1061  /// <param name="selector">Selects a value from the BaseData, if null defaults to the .Value property (x => x.Value)</param>
1062  /// <param name="fieldName">The name of the field being selected</param>
1063  /// <returns>A new Identity indicator for the specified symbol and selector</returns>
1064  [DocumentationAttribute(Indicators)]
1065  public Identity Identity(Symbol symbol, TimeSpan resolution, Func<IBaseData, decimal> selector = null, string fieldName = null)
1066  {
1067  var name = Invariant($"{symbol}({fieldName ?? "close"},{resolution})");
1068  var identity = new Identity(name);
1069  RegisterIndicator(symbol, identity, ResolveConsolidator(symbol, resolution), selector);
1070  return identity;
1071  }
1072 
1073  /// <summary>
1074  /// Creates a new ImpliedVolatility indicator for the symbol The indicator will be automatically
1075  /// updated on the symbol's subscription resolution
1076  /// </summary>
1077  /// <param name="symbol">The option symbol whose values we want as an indicator</param>
1078  /// <param name="mirrorOption">The mirror option contract used for parity type calculation</param>
1079  /// <param name="riskFreeRate">The risk free rate</param>
1080  /// <param name="dividendYield">The dividend yield</param>
1081  /// <param name="optionModel">The option pricing model used to estimate IV</param>
1082  /// <param name="resolution">The desired resolution of the data</param>
1083  /// <returns>A new ImpliedVolatility indicator for the specified symbol</returns>
1084  [DocumentationAttribute(Indicators)]
1085  public ImpliedVolatility IV(Symbol symbol, Symbol mirrorOption = null, decimal? riskFreeRate = null, decimal? dividendYield = null,
1086  OptionPricingModelType? optionModel = null, Resolution? resolution = null)
1087  {
1088  var name = InitializeOptionIndicator<ImpliedVolatility>(symbol, out var riskFreeRateModel, out var dividendYieldModel, riskFreeRate, dividendYield, optionModel, resolution);
1089 
1090  var iv = new ImpliedVolatility(name, symbol, riskFreeRateModel, dividendYieldModel, mirrorOption, optionModel);
1091  InitializeOptionIndicator(iv, resolution, symbol, mirrorOption);
1092  return iv;
1093  }
1094 
1095  /// <summary>
1096  /// Creates a new KaufmanAdaptiveMovingAverage indicator.
1097  /// </summary>
1098  /// <param name="symbol">The symbol whose KAMA we want</param>
1099  /// <param name="period">The period of the Efficiency Ratio (ER) of KAMA</param>
1100  /// <param name="resolution">The resolution</param>
1101  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
1102  /// <returns>The KaufmanAdaptiveMovingAverage indicator for the requested symbol over the specified period</returns>
1103  [DocumentationAttribute(Indicators)]
1104  public KaufmanAdaptiveMovingAverage KAMA(Symbol symbol, int period, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
1105  {
1106  return KAMA(symbol, period, 2, 30, resolution, selector);
1107  }
1108 
1109  /// <summary>
1110  /// Creates a new KaufmanAdaptiveMovingAverage indicator.
1111  /// </summary>
1112  /// <param name="symbol">The symbol whose KAMA we want</param>
1113  /// <param name="period">The period of the Efficiency Ratio (ER)</param>
1114  /// <param name="fastEmaPeriod">The period of the fast EMA used to calculate the Smoothing Constant (SC)</param>
1115  /// <param name="slowEmaPeriod">The period of the slow EMA used to calculate the Smoothing Constant (SC)</param>
1116  /// <param name="resolution">The resolution</param>
1117  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
1118  /// <returns>The KaufmanAdaptiveMovingAverage indicator for the requested symbol over the specified period</returns>
1119  [DocumentationAttribute(Indicators)]
1120  public KaufmanAdaptiveMovingAverage KAMA(Symbol symbol, int period, int fastEmaPeriod, int slowEmaPeriod, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
1121  {
1122  var name = CreateIndicatorName(symbol, $"KAMA({period},{fastEmaPeriod},{slowEmaPeriod})", resolution);
1123  var kaufmanAdaptiveMovingAverage = new KaufmanAdaptiveMovingAverage(name, period, fastEmaPeriod, slowEmaPeriod);
1124  InitializeIndicator(kaufmanAdaptiveMovingAverage, resolution, selector, symbol);
1125 
1126  return kaufmanAdaptiveMovingAverage;
1127  }
1128 
1129  /// <summary>
1130  /// Creates an KaufmanEfficiencyRatio indicator for the symbol. The indicator will be automatically
1131  /// updated on the given resolution.
1132  /// </summary>
1133  /// <param name="symbol">The symbol whose EF we want</param>
1134  /// <param name="period">The period of the EF</param>
1135  /// <param name="resolution">The resolution</param>
1136  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
1137  /// <returns>The KaufmanEfficiencyRatio indicator for the given parameters</returns>
1138  [DocumentationAttribute(Indicators)]
1139  public KaufmanEfficiencyRatio KER(Symbol symbol, int period = 2, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
1140  {
1141  var name = CreateIndicatorName(symbol, $"KER({period})", resolution);
1142  var kaufmanEfficiencyRatio = new KaufmanEfficiencyRatio(name, period);
1143  InitializeIndicator(kaufmanEfficiencyRatio, resolution, selector, symbol);
1144 
1145  return kaufmanEfficiencyRatio;
1146  }
1147 
1148  /// <summary>
1149  /// Creates a new Keltner Channels indicator.
1150  /// The indicator will be automatically updated on the given resolution.
1151  /// </summary>
1152  /// <param name="symbol">The symbol whose Keltner Channel we seek</param>
1153  /// <param name="period">The period over which to compute the Keltner Channels</param>
1154  /// <param name="k">The number of multiples of the <see cref="AverageTrueRange"/> from the middle band of the Keltner Channels</param>
1155  /// <param name="movingAverageType">Specifies the type of moving average to be used as the middle line of the Keltner Channel</param>
1156  /// <param name="resolution">The resolution.</param>
1157  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to casting the input value to a TradeBar</param>
1158  /// <returns>The Keltner Channel indicator for the requested symbol.</returns>
1159  [DocumentationAttribute(Indicators)]
1160  public KeltnerChannels KCH(Symbol symbol, int period, decimal k, MovingAverageType movingAverageType = MovingAverageType.Simple, Resolution? resolution = null, Func<IBaseData, IBaseDataBar> selector = null)
1161  {
1162  var name = CreateIndicatorName(symbol, $"KCH({period},{k})", resolution);
1163  var keltnerChannels = new KeltnerChannels(name, period, k, movingAverageType);
1164  InitializeIndicator(keltnerChannels, resolution, selector, symbol);
1165 
1166  return keltnerChannels;
1167  }
1168 
1169  /// <summary>
1170  /// Creates a new LogReturn indicator.
1171  /// </summary>
1172  /// <param name="symbol">The symbol whose log return we seek</param>
1173  /// <param name="period">The period of the log return.</param>
1174  /// <param name="resolution">The resolution.</param>
1175  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to casting the input value to a TradeBar.</param>
1176  /// <returns>log return indicator for the requested symbol.</returns>
1177  [DocumentationAttribute(Indicators)]
1178  public LogReturn LOGR(Symbol symbol, int period, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
1179  {
1180  var name = CreateIndicatorName(symbol, $"LOGR({period})", resolution);
1181  var logReturn = new LogReturn(name, period);
1182  InitializeIndicator(logReturn, resolution, selector, symbol);
1183 
1184  return logReturn;
1185  }
1186 
1187  /// <summary>
1188  /// Creates and registers a new Least Squares Moving Average instance.
1189  /// </summary>
1190  /// <param name="symbol">The symbol whose LSMA we seek.</param>
1191  /// <param name="period">The LSMA period. Normally 14.</param>
1192  /// <param name="resolution">The resolution.</param>
1193  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to casting the input value to a TradeBar.</param>
1194  /// <returns>A LeastSquaredMovingAverage configured with the specified period</returns>
1195  [DocumentationAttribute(Indicators)]
1196  public LeastSquaresMovingAverage LSMA(Symbol symbol, int period, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
1197  {
1198  var name = CreateIndicatorName(symbol, $"LSMA({period})", resolution);
1199  var leastSquaresMovingAverage = new LeastSquaresMovingAverage(name, period);
1200  InitializeIndicator(leastSquaresMovingAverage, resolution, selector, symbol);
1201 
1202  return leastSquaresMovingAverage;
1203  }
1204 
1205  /// <summary>
1206  /// Creates a new LinearWeightedMovingAverage indicator. This indicator will linearly distribute
1207  /// the weights across the periods.
1208  /// </summary>
1209  /// <param name="symbol">The symbol whose LWMA we want</param>
1210  /// <param name="period">The period over which to compute the LWMA</param>
1211  /// <param name="resolution">The resolution</param>
1212  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
1213  /// <returns></returns>
1214  [DocumentationAttribute(Indicators)]
1215  public LinearWeightedMovingAverage LWMA(Symbol symbol, int period, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
1216  {
1217  var name = CreateIndicatorName(symbol, $"LWMA({period})", resolution);
1218  var linearWeightedMovingAverage = new LinearWeightedMovingAverage(name, period);
1219  InitializeIndicator(linearWeightedMovingAverage, resolution, selector, symbol);
1220 
1221  return linearWeightedMovingAverage;
1222  }
1223 
1224  /// <summary>
1225  /// Creates a MACD indicator for the symbol. The indicator will be automatically updated on the given resolution.
1226  /// </summary>
1227  /// <param name="symbol">The symbol whose MACD we want</param>
1228  /// <param name="fastPeriod">The period for the fast moving average</param>
1229  /// <param name="slowPeriod">The period for the slow moving average</param>
1230  /// <param name="signalPeriod">The period for the signal moving average</param>
1231  /// <param name="type">The type of moving average to use for the MACD</param>
1232  /// <param name="resolution">The resolution</param>
1233  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
1234  /// <returns>The moving average convergence divergence between the fast and slow averages</returns>
1235  [DocumentationAttribute(Indicators)]
1236  public MovingAverageConvergenceDivergence MACD(Symbol symbol, int fastPeriod, int slowPeriod, int signalPeriod, MovingAverageType type = MovingAverageType.Exponential, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
1237  {
1238  var name = CreateIndicatorName(symbol, $"MACD({fastPeriod},{slowPeriod},{signalPeriod})", resolution);
1239  var movingAverageConvergenceDivergence = new MovingAverageConvergenceDivergence(name, fastPeriod, slowPeriod, signalPeriod, type);
1240  InitializeIndicator(movingAverageConvergenceDivergence, resolution, selector, symbol);
1241 
1242  return movingAverageConvergenceDivergence;
1243  }
1244 
1245  /// <summary>
1246  /// Creates a new MeanAbsoluteDeviation indicator.
1247  /// </summary>
1248  /// <param name="symbol">The symbol whose MeanAbsoluteDeviation we want</param>
1249  /// <param name="period">The period over which to compute the MeanAbsoluteDeviation</param>
1250  /// <param name="resolution">The resolution</param>
1251  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
1252  /// <returns>The MeanAbsoluteDeviation indicator for the requested symbol over the specified period</returns>
1253  [DocumentationAttribute(Indicators)]
1254  public MeanAbsoluteDeviation MAD(Symbol symbol, int period, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
1255  {
1256  var name = CreateIndicatorName(symbol, $"MAD({period})", resolution);
1257  var meanAbsoluteDeviation = new MeanAbsoluteDeviation(name, period);
1258  InitializeIndicator(meanAbsoluteDeviation, resolution, selector, symbol);
1259 
1260  return meanAbsoluteDeviation;
1261  }
1262 
1263  /// <summary>
1264  /// Creates an Market Profile indicator for the symbol with Volume Profile (VOL) mode. The indicator will be automatically
1265  /// updated on the given resolution.
1266  /// </summary>
1267  /// <param name="symbol">The symbol whose VP we want</param>
1268  /// <param name="period">The period of the VP</param>
1269  /// <param name="valueAreaVolumePercentage">The percentage of volume contained in the value area</param>
1270  /// <param name="priceRangeRoundOff">How many digits you want to round and the precision. i.e 0.01 round to two digits exactly.</param>
1271  /// <param name="resolution">The resolution</param>
1272  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to casting the input value to a TradeBar</param>
1273  /// <returns>The Volume Profile indicator for the given parameters</returns>
1274  [DocumentationAttribute(Indicators)]
1275  public VolumeProfile VP(Symbol symbol, int period = 2, decimal valueAreaVolumePercentage = 0.70m, decimal priceRangeRoundOff = 0.05m, Resolution resolution = Resolution.Daily, Func<IBaseData, TradeBar> selector = null)
1276  {
1277  var name = CreateIndicatorName(symbol, $"VP({period})", resolution);
1278  var marketProfile = new VolumeProfile(name, period, valueAreaVolumePercentage, priceRangeRoundOff);
1279  InitializeIndicator(marketProfile, resolution, selector, symbol);
1280 
1281  return marketProfile;
1282  }
1283 
1284  /// <summary>
1285  /// Creates an Market Profile indicator for the symbol with Time Price Opportunity (TPO) mode. The indicator will be automatically
1286  /// updated on the given resolution.
1287  /// </summary>
1288  /// <param name="symbol">The symbol whose TP we want</param>
1289  /// <param name="period">The period of the TP</param>
1290  /// <param name="valueAreaVolumePercentage">The percentage of volume contained in the value area</param>
1291  /// <param name="priceRangeRoundOff">How many digits you want to round and the precision. i.e 0.01 round to two digits exactly.</param>
1292  /// <param name="resolution">The resolution</param>
1293  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to casting the input value to a TradeBar</param>
1294  /// <returns>The Time Profile indicator for the given parameters</returns>
1295  [DocumentationAttribute(Indicators)]
1296  public TimeProfile TP(Symbol symbol, int period = 2, decimal valueAreaVolumePercentage = 0.70m, decimal priceRangeRoundOff = 0.05m, Resolution resolution = Resolution.Daily, Func<IBaseData, TradeBar> selector = null)
1297  {
1298  var name = CreateIndicatorName(symbol, $"TP({period})", resolution);
1299  var marketProfile = new TimeProfile(name, period, valueAreaVolumePercentage, priceRangeRoundOff);
1300  InitializeIndicator(marketProfile, resolution, selector, symbol);
1301 
1302  return marketProfile;
1303  }
1304 
1305  /// <summary>
1306  /// Creates a new Time Series Forecast indicator
1307  /// </summary>
1308  /// <param name="symbol">The symbol whose TSF we want</param>
1309  /// <param name="period">The period of the TSF</param>
1310  /// <param name="resolution">The resolution</param>
1311  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to Value property of BaseData (x => x.Value)</param>
1312  /// <returns>The TimeSeriesForecast indicator for the requested symbol over the specified period</returns>
1313  [DocumentationAttribute(Indicators)]
1314  public TimeSeriesForecast TSF(Symbol symbol, int period, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
1315  {
1316  var name = CreateIndicatorName(symbol, $"TSF({period})", resolution);
1317  var timeSeriesForecast = new TimeSeriesForecast(name, period);
1318  InitializeIndicator(timeSeriesForecast, resolution, selector, symbol);
1319 
1320  return timeSeriesForecast;
1321  }
1322 
1323  /// <summary>
1324  /// Creates a new Maximum indicator to compute the maximum value
1325  /// </summary>
1326  /// <param name="symbol">The symbol whose max we want</param>
1327  /// <param name="period">The look back period over which to compute the max value</param>
1328  /// <param name="resolution">The resolution</param>
1329  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null and the symbol is of type TradeBar defaults to the High property,
1330  /// otherwise it defaults to Value property of BaseData (x => x.Value)</param>
1331  /// <returns>A Maximum indicator that compute the max value and the periods since the max value</returns>
1332  [DocumentationAttribute(Indicators)]
1333  public Maximum MAX(Symbol symbol, int period, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
1334  {
1335  var name = CreateIndicatorName(symbol, $"MAX({period})", resolution);
1336  var maximum = new Maximum(name, period);
1337 
1338  // assign a default value for the selector function
1339  if (selector == null)
1340  {
1341  var subscription = GetSubscription(symbol);
1342  if (typeof(TradeBar).IsAssignableFrom(subscription.Type))
1343  {
1344  // if we have trade bar data we'll use the High property, if not x => x.Value will be set in RegisterIndicator
1345  selector = x => ((TradeBar)x).High;
1346  }
1347  }
1348 
1349  InitializeIndicator(maximum, resolution, selector, symbol);
1350  return maximum;
1351  }
1352 
1353  /// <summary>
1354  /// Creates a new MoneyFlowIndex indicator. The indicator will be automatically
1355  /// updated on the given resolution.
1356  /// </summary>
1357  /// <param name="symbol">The symbol whose MFI we want</param>
1358  /// <param name="period">The period over which to compute the MFI</param>
1359  /// <param name="resolution">The resolution</param>
1360  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to casting the input value to a TradeBar</param>
1361  /// <returns>The MoneyFlowIndex indicator for the requested symbol over the specified period</returns>
1362  [DocumentationAttribute(Indicators)]
1363  public MoneyFlowIndex MFI(Symbol symbol, int period, Resolution? resolution = null, Func<IBaseData, TradeBar> selector = null)
1364  {
1365  var name = CreateIndicatorName(symbol, $"MFI({period})", resolution);
1366  var moneyFlowIndex = new MoneyFlowIndex(name, period);
1367  InitializeIndicator(moneyFlowIndex, resolution, selector, symbol);
1368 
1369  return moneyFlowIndex;
1370  }
1371 
1372  /// <summary>
1373  /// Creates a new Mass Index indicator. The indicator will be automatically
1374  /// updated on the given resolution.
1375  /// </summary>
1376  /// <param name="symbol">The symbol whose Mass Index we want.</param>
1377  /// <param name="emaPeriod">The period used by both EMA.</param>
1378  /// <param name="sumPeriod">The sum period.</param>
1379  /// <param name="resolution">The resolution.</param>
1380  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to casting the input value to a TradeBar</param>
1381  /// <returns>The Mass Index indicator for the requested symbol over the specified period</returns>
1382  [DocumentationAttribute(Indicators)]
1383  public MassIndex MASS(Symbol symbol, int emaPeriod = 9, int sumPeriod = 25, Resolution? resolution = null, Func<IBaseData, TradeBar> selector = null)
1384  {
1385  var name = CreateIndicatorName(symbol, $"MASS({emaPeriod},{sumPeriod})", resolution);
1386  var massIndex = new MassIndex(name, emaPeriod, sumPeriod);
1387  InitializeIndicator(massIndex, resolution, selector, symbol);
1388 
1389  return massIndex;
1390  }
1391 
1392  /// <summary>
1393  /// Creates a new MidPoint indicator.
1394  /// </summary>
1395  /// <param name="symbol">The symbol whose MIDPOINT we want</param>
1396  /// <param name="period">The period over which to compute the MIDPOINT</param>
1397  /// <param name="resolution">The resolution</param>
1398  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
1399  /// <returns>The MidPoint indicator for the requested symbol over the specified period</returns>
1400  [DocumentationAttribute(Indicators)]
1401  public MidPoint MIDPOINT(Symbol symbol, int period, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
1402  {
1403  var name = CreateIndicatorName(symbol, $"MIDPOINT({period})", resolution);
1404  var midPoint = new MidPoint(name, period);
1405  InitializeIndicator(midPoint, resolution, selector, symbol);
1406 
1407  return midPoint;
1408  }
1409 
1410  /// <summary>
1411  /// Creates a new MidPrice indicator.
1412  /// </summary>
1413  /// <param name="symbol">The symbol whose MIDPRICE we want</param>
1414  /// <param name="period">The period over which to compute the MIDPRICE</param>
1415  /// <param name="resolution">The resolution</param>
1416  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to casting the input value to a TradeBar</param>
1417  /// <returns>The MidPrice indicator for the requested symbol over the specified period</returns>
1418  [DocumentationAttribute(Indicators)]
1419  public MidPrice MIDPRICE(Symbol symbol, int period, Resolution? resolution = null, Func<IBaseData, IBaseDataBar> selector = null)
1420  {
1421  var name = CreateIndicatorName(symbol, $"MIDPRICE({period})", resolution);
1422  var midPrice = new MidPrice(name, period);
1423  InitializeIndicator(midPrice, resolution, selector, symbol);
1424 
1425  return midPrice;
1426  }
1427 
1428  /// <summary>
1429  /// Creates a new Minimum indicator to compute the minimum value
1430  /// </summary>
1431  /// <param name="symbol">The symbol whose min we want</param>
1432  /// <param name="period">The look back period over which to compute the min value</param>
1433  /// <param name="resolution">The resolution</param>
1434  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null and the symbol is of type TradeBar defaults to the Low property,
1435  /// otherwise it defaults to Value property of BaseData (x => x.Value)</param>
1436  /// <returns>A Minimum indicator that compute the in value and the periods since the min value</returns>
1437  [DocumentationAttribute(Indicators)]
1438  public Minimum MIN(Symbol symbol, int period, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
1439  {
1440  var name = CreateIndicatorName(symbol, $"MIN({period})", resolution);
1441  var minimum = new Minimum(name, period);
1442 
1443  // assign a default value for the selector function
1444  if (selector == null)
1445  {
1446  var subscription = GetSubscription(symbol);
1447  if (typeof(TradeBar).IsAssignableFrom(subscription.Type))
1448  {
1449  // if we have trade bar data we'll use the Low property, if not x => x.Value will be set in RegisterIndicator
1450  selector = x => ((TradeBar)x).Low;
1451  }
1452  }
1453 
1454  InitializeIndicator(minimum, resolution, selector, symbol);
1455  return minimum;
1456  }
1457 
1458  /// <summary>
1459  /// Creates a new Momentum indicator. This will compute the absolute n-period change in the security.
1460  /// The indicator will be automatically updated on the given resolution.
1461  /// </summary>
1462  /// <param name="symbol">The symbol whose momentum we want</param>
1463  /// <param name="period">The period over which to compute the momentum</param>
1464  /// <param name="resolution">The resolution</param>
1465  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
1466  /// <returns>The momentum indicator for the requested symbol over the specified period</returns>
1467  [DocumentationAttribute(Indicators)]
1468  public Momentum MOM(Symbol symbol, int period, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
1469  {
1470  var name = CreateIndicatorName(symbol, $"MOM({period})", resolution);
1471  var momentum = new Momentum(name, period);
1472  InitializeIndicator(momentum, resolution, selector, symbol);
1473 
1474  return momentum;
1475  }
1476 
1477  /// <summary>
1478  /// Creates a new Momersion indicator.
1479  /// </summary>
1480  /// <param name="symbol">The symbol whose Momersion we want</param>
1481  /// <param name="minPeriod">The minimum period over which to compute the Momersion. Must be greater than 3. If null, only full period will be used in computations.</param>
1482  /// <param name="fullPeriod">The full period over which to compute the Momersion</param>
1483  /// <param name="resolution">The resolution</param>
1484  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
1485  /// <returns>The Momersion indicator for the requested symbol over the specified period</returns>
1486  [DocumentationAttribute(Indicators)]
1487  public MomersionIndicator MOMERSION(Symbol symbol, int? minPeriod, int fullPeriod, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
1488  {
1489  var name = CreateIndicatorName(symbol, $"MOMERSION({minPeriod},{fullPeriod})", resolution);
1490  var momersion = new MomersionIndicator(name, minPeriod, fullPeriod);
1491  InitializeIndicator(momersion, resolution, selector, symbol);
1492 
1493  return momersion;
1494  }
1495 
1496  /// <summary>
1497  /// Creates a new MomentumPercent indicator. This will compute the n-period percent change in the security.
1498  /// The indicator will be automatically updated on the given resolution.
1499  /// </summary>
1500  /// <param name="symbol">The symbol whose momentum we want</param>
1501  /// <param name="period">The period over which to compute the momentum</param>
1502  /// <param name="resolution">The resolution</param>
1503  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
1504  /// <returns>The momentum indicator for the requested symbol over the specified period</returns>
1505  [DocumentationAttribute(Indicators)]
1506  public MomentumPercent MOMP(Symbol symbol, int period, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
1507  {
1508  var name = CreateIndicatorName(symbol, $"MOMP({period})", resolution);
1509  var momentumPercent = new MomentumPercent(name, period);
1510  InitializeIndicator(momentumPercent, resolution, selector, symbol);
1511 
1512  return momentumPercent;
1513  }
1514 
1515  /// <summary>
1516  /// Creates a new NormalizedAverageTrueRange indicator.
1517  /// </summary>
1518  /// <param name="symbol">The symbol whose NATR we want</param>
1519  /// <param name="period">The period over which to compute the NATR</param>
1520  /// <param name="resolution">The resolution</param>
1521  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to casting the input value to a TradeBar</param>
1522  /// <returns>The NormalizedAverageTrueRange indicator for the requested symbol over the specified period</returns>
1523  [DocumentationAttribute(Indicators)]
1524  public NormalizedAverageTrueRange NATR(Symbol symbol, int period, Resolution? resolution = null, Func<IBaseData, IBaseDataBar> selector = null)
1525  {
1526  var name = CreateIndicatorName(symbol, $"NATR({period})", resolution);
1527  var normalizedAverageTrueRange = new NormalizedAverageTrueRange(name, period);
1528  InitializeIndicator(normalizedAverageTrueRange, resolution, selector, symbol);
1529 
1530  return normalizedAverageTrueRange;
1531  }
1532 
1533  /// <summary>
1534  /// Creates a new On Balance Volume indicator. This will compute the cumulative total volume
1535  /// based on whether the close price being higher or lower than the previous period.
1536  /// The indicator will be automatically updated on the given resolution.
1537  /// </summary>
1538  /// <param name="symbol">The symbol whose On Balance Volume we seek</param>
1539  /// <param name="resolution">The resolution.</param>
1540  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to casting the input value to a TradeBar</param>
1541  /// <returns>The On Balance Volume indicator for the requested symbol.</returns>
1542  [DocumentationAttribute(Indicators)]
1543  public OnBalanceVolume OBV(Symbol symbol, Resolution? resolution = null, Func<IBaseData, TradeBar> selector = null)
1544  {
1545  var name = CreateIndicatorName(symbol, "OBV", resolution);
1546  var onBalanceVolume = new OnBalanceVolume(name);
1547  InitializeIndicator(onBalanceVolume, resolution, selector, symbol);
1548 
1549  return onBalanceVolume;
1550  }
1551 
1552  /// <summary>
1553  /// Creates a new PivotPointsHighLow indicator
1554  /// </summary>
1555  /// <param name="symbol">The symbol whose PPHL we seek</param>
1556  /// <param name="lengthHigh">The number of surrounding bars whose high values should be less than the current bar's for the bar high to be marked as high pivot point</param>
1557  /// <param name="lengthLow">The number of surrounding bars whose low values should be more than the current bar's for the bar low to be marked as low pivot point</param>
1558  /// <param name="lastStoredValues">The number of last stored indicator values</param>
1559  /// <param name="resolution">The resolution</param>
1560  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to casting the input value to a TradeBar</param>
1561  /// <returns>The PivotPointsHighLow indicator for the requested symbol.</returns>
1562  [DocumentationAttribute(Indicators)]
1563  public PivotPointsHighLow PPHL(Symbol symbol, int lengthHigh, int lengthLow, int lastStoredValues = 100, Resolution? resolution = null, Func<IBaseData, IBaseDataBar> selector = null)
1564  {
1565  var name = CreateIndicatorName(symbol, $"PPHL({lengthHigh},{lengthLow})", resolution);
1566  var pivotPointsHighLow = new PivotPointsHighLow(name, lengthHigh, lengthLow, lastStoredValues);
1567  InitializeIndicator(pivotPointsHighLow, resolution, selector, symbol);
1568 
1569  return pivotPointsHighLow;
1570  }
1571 
1572  /// <summary>
1573  /// Creates a new PercentagePriceOscillator indicator.
1574  /// </summary>
1575  /// <param name="symbol">The symbol whose PPO we want</param>
1576  /// <param name="fastPeriod">The fast moving average period</param>
1577  /// <param name="slowPeriod">The slow moving average period</param>
1578  /// <param name="movingAverageType">The type of moving average to use</param>
1579  /// <param name="resolution">The resolution</param>
1580  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
1581  /// <returns>The PercentagePriceOscillator indicator for the requested symbol over the specified period</returns>
1582  [DocumentationAttribute(Indicators)]
1583  public PercentagePriceOscillator PPO(Symbol symbol, int fastPeriod, int slowPeriod, MovingAverageType movingAverageType, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
1584  {
1585  var name = CreateIndicatorName(symbol, $"PPO({fastPeriod},{slowPeriod})", resolution);
1586  var percentagePriceOscillator = new PercentagePriceOscillator(name, fastPeriod, slowPeriod, movingAverageType);
1587  InitializeIndicator(percentagePriceOscillator, resolution, selector, symbol);
1588 
1589  return percentagePriceOscillator;
1590  }
1591 
1592  /// <summary>
1593  /// Creates a new Parabolic SAR indicator
1594  /// </summary>
1595  /// <param name="symbol">The symbol whose PSAR we seek</param>
1596  /// <param name="afStart">Acceleration factor start value. Normally 0.02</param>
1597  /// <param name="afIncrement">Acceleration factor increment value. Normally 0.02</param>
1598  /// <param name="afMax">Acceleration factor max value. Normally 0.2</param>
1599  /// <param name="resolution">The resolution</param>
1600  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to casting the input value to a TradeBar</param>
1601  /// <returns>A ParabolicStopAndReverse configured with the specified periods</returns>
1602  [DocumentationAttribute(Indicators)]
1603  public ParabolicStopAndReverse PSAR(Symbol symbol, decimal afStart = 0.02m, decimal afIncrement = 0.02m, decimal afMax = 0.2m, Resolution? resolution = null, Func<IBaseData, IBaseDataBar> selector = null)
1604  {
1605  var name = CreateIndicatorName(symbol, $"PSAR({afStart},{afIncrement},{afMax})", resolution);
1606  var parabolicStopAndReverse = new ParabolicStopAndReverse(name, afStart, afIncrement, afMax);
1607  InitializeIndicator(parabolicStopAndReverse, resolution, selector, symbol);
1608 
1609  return parabolicStopAndReverse;
1610  }
1611 
1612  /// <summary>
1613  /// Creates a new RegressionChannel indicator which will compute the LinearRegression, UpperChannel and LowerChannel lines, the intercept and slope
1614  /// </summary>
1615  /// <param name="symbol">The symbol whose RegressionChannel we seek</param>
1616  /// <param name="period">The period of the standard deviation and least square moving average (linear regression line)</param>
1617  /// <param name="k">The number of standard deviations specifying the distance between the linear regression and upper or lower channel lines</param>
1618  /// <param name="resolution">The resolution</param>
1619  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
1620  /// <returns>A Regression Channel configured with the specified period and number of standard deviation</returns>
1621  [DocumentationAttribute(Indicators)]
1622  public RegressionChannel RC(Symbol symbol, int period, decimal k, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
1623  {
1624  var name = CreateIndicatorName(symbol, $"RC({period},{k})", resolution);
1625  var regressionChannel = new RegressionChannel(name, period, k);
1626  InitializeIndicator(regressionChannel, resolution, selector, symbol);
1627 
1628  return regressionChannel;
1629  }
1630 
1631  /// <summary>
1632  /// Creates a new Relative Moving Average indicator for the symbol. The indicator will be automatically updated on the given resolution.
1633  /// </summary>
1634  /// <param name="symbol">The symbol whose relative moving average we seek</param>
1635  /// <param name="period">The period of the relative moving average</param>
1636  /// <param name="resolution">The resolution</param>
1637  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
1638  /// <returns>A relative moving average configured with the specified period and number of standard deviation</returns>
1639  [DocumentationAttribute(Indicators)]
1640  public RelativeMovingAverage RMA(Symbol symbol, int period, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
1641  {
1642  var name = CreateIndicatorName(symbol, $"RMA({period})", resolution);
1643  var relativeMovingAverage = new RelativeMovingAverage(name, period);
1644  InitializeIndicator(relativeMovingAverage, resolution, selector, symbol);
1645 
1646  return relativeMovingAverage;
1647  }
1648 
1649 
1650  /// <summary>
1651  /// Creates a new RateOfChange indicator. This will compute the n-period rate of change in the security.
1652  /// The indicator will be automatically updated on the given resolution.
1653  /// </summary>
1654  /// <param name="symbol">The symbol whose RateOfChange we want</param>
1655  /// <param name="period">The period over which to compute the RateOfChange</param>
1656  /// <param name="resolution">The resolution</param>
1657  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
1658  /// <returns>The RateOfChange indicator for the requested symbol over the specified period</returns>
1659  [DocumentationAttribute(Indicators)]
1660  public RateOfChange ROC(Symbol symbol, int period, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
1661  {
1662  var name = CreateIndicatorName(symbol, $"ROC({period})", resolution);
1663  var rateOfChange = new RateOfChange(name, period);
1664  InitializeIndicator(rateOfChange, resolution, selector, symbol);
1665 
1666  return rateOfChange;
1667  }
1668 
1669  /// <summary>
1670  /// Creates a new RateOfChangePercent indicator. This will compute the n-period percentage rate of change in the security.
1671  /// The indicator will be automatically updated on the given resolution.
1672  /// </summary>
1673  /// <param name="symbol">The symbol whose RateOfChangePercent we want</param>
1674  /// <param name="period">The period over which to compute the RateOfChangePercent</param>
1675  /// <param name="resolution">The resolution</param>
1676  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
1677  /// <returns>The RateOfChangePercent indicator for the requested symbol over the specified period</returns>
1678  [DocumentationAttribute(Indicators)]
1679  public RateOfChangePercent ROCP(Symbol symbol, int period, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
1680  {
1681  var name = CreateIndicatorName(symbol, $"ROCP({period})", resolution);
1682  var rateOfChangePercent = new RateOfChangePercent(name, period);
1683  InitializeIndicator(rateOfChangePercent, resolution, selector, symbol);
1684 
1685  return rateOfChangePercent;
1686  }
1687 
1688  /// <summary>
1689  /// Creates a new RateOfChangeRatio indicator.
1690  /// </summary>
1691  /// <param name="symbol">The symbol whose ROCR we want</param>
1692  /// <param name="period">The period over which to compute the ROCR</param>
1693  /// <param name="resolution">The resolution</param>
1694  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
1695  /// <returns>The RateOfChangeRatio indicator for the requested symbol over the specified period</returns>
1696  [DocumentationAttribute(Indicators)]
1697  public RateOfChangeRatio ROCR(Symbol symbol, int period, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
1698  {
1699  var name = CreateIndicatorName(symbol, $"ROCR({period})", resolution);
1700  var rateOfChangeRatio = new RateOfChangeRatio(name, period);
1701  InitializeIndicator(rateOfChangeRatio, resolution, selector, symbol);
1702 
1703  return rateOfChangeRatio;
1704  }
1705 
1706  /// <summary>
1707  /// Creates a new RelativeStrengthIndex indicator. This will produce an oscillator that ranges from 0 to 100 based
1708  /// on the ratio of average gains to average losses over the specified period.
1709  /// </summary>
1710  /// <param name="symbol">The symbol whose RSI we want</param>
1711  /// <param name="period">The period over which to compute the RSI</param>
1712  /// <param name="movingAverageType">The type of moving average to use in computing the average gain/loss values</param>
1713  /// <param name="resolution">The resolution</param>
1714  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
1715  /// <returns>The RelativeStrengthIndex indicator for the requested symbol over the specified period</returns>
1716  [DocumentationAttribute(Indicators)]
1717  public RelativeStrengthIndex RSI(Symbol symbol, int period, MovingAverageType movingAverageType = MovingAverageType.Wilders, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
1718  {
1719  var name = CreateIndicatorName(symbol, $"RSI({period},{movingAverageType})", resolution);
1720  var relativeStrengthIndex = new RelativeStrengthIndex(name, period, movingAverageType);
1721  InitializeIndicator(relativeStrengthIndex, resolution, selector, symbol);
1722 
1723  return relativeStrengthIndex;
1724  }
1725 
1726  /// <summary>
1727  /// Creates a new RelativeVigorIndex indicator.
1728  /// </summary>
1729  /// <param name="symbol">The symbol whose RVI we want</param>
1730  /// <param name="period">The period over which to compute the RVI</param>
1731  /// <param name="movingAverageType">The type of moving average to use</param>
1732  /// <param name="resolution">The resolution</param>
1733  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to casting the input value to a TradeBar</param>
1734  /// <returns>The RelativeVigorIndex indicator for the requested symbol over the specified period</returns>
1735  [DocumentationAttribute(Indicators)]
1736  public RelativeVigorIndex RVI(Symbol symbol, int period, MovingAverageType movingAverageType = MovingAverageType.Simple, Resolution? resolution = null, Func<IBaseData, TradeBar> selector = null)
1737  {
1738  var name = CreateIndicatorName(symbol, $"RVI({period},{movingAverageType})", resolution);
1739  var relativeVigorIndex = new RelativeVigorIndex(name, period, movingAverageType);
1740  InitializeIndicator(relativeVigorIndex, resolution, selector, symbol);
1741 
1742  return relativeVigorIndex;
1743  }
1744 
1745  /// <summary>
1746  /// Creates an RelativeDailyVolume indicator for the symbol. The indicator will be automatically
1747  /// updated on the given resolution.
1748  /// </summary>
1749  /// <param name="symbol">The symbol whose RDV we want</param>
1750  /// <param name="period">The period of the RDV</param>
1751  /// <param name="resolution">The resolution</param>
1752  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to casting the input value to a TradeBar</param>
1753  /// <returns>The Relative Volume indicator for the given parameters</returns>
1754  [DocumentationAttribute(Indicators)]
1755  public RelativeDailyVolume RDV(Symbol symbol, int period = 2, Resolution resolution = Resolution.Daily, Func<IBaseData, TradeBar> selector = null)
1756  {
1757  var name = CreateIndicatorName(symbol, $"RDV({period})", resolution);
1758  var relativeDailyVolume = new RelativeDailyVolume(name, period);
1759  RegisterIndicator(symbol, relativeDailyVolume, resolution, selector);
1760 
1761  return relativeDailyVolume;
1762  }
1763 
1764  /// <summary>
1765  /// Creates a new Rho indicator for the symbol The indicator will be automatically
1766  /// updated on the symbol's subscription resolution
1767  /// </summary>
1768  /// <param name="symbol">The option symbol whose values we want as an indicator</param>
1769  /// <param name="mirrorOption">The mirror option for parity calculation</param>
1770  /// <param name="riskFreeRate">The risk free rate</param>
1771  /// <param name="dividendYield">The dividend yield</param>
1772  /// <param name="optionModel">The option pricing model used to estimate Rho</param>
1773  /// <param name="ivModel">The option pricing model used to estimate IV</param>
1774  /// <param name="resolution">The desired resolution of the data</param>
1775  /// <returns>A new Rho indicator for the specified symbol</returns>
1776  [DocumentationAttribute(Indicators)]
1777  public Rho R(Symbol symbol, Symbol mirrorOption = null, decimal? riskFreeRate = null, decimal? dividendYield = null,
1778  OptionPricingModelType? optionModel = null, OptionPricingModelType? ivModel = null, Resolution? resolution = null)
1779  {
1780  var name = InitializeOptionIndicator<Rho>(symbol, out var riskFreeRateModel, out var dividendYieldModel, riskFreeRate, dividendYield, optionModel, resolution);
1781 
1782  var rho = new Rho(name, symbol, riskFreeRateModel, dividendYieldModel, mirrorOption, optionModel, ivModel);
1783  InitializeOptionIndicator(rho, resolution, symbol, mirrorOption);
1784  return rho;
1785  }
1786 
1787  /// <summary>
1788  /// Creates a new Rho indicator for the symbol The indicator will be automatically
1789  /// updated on the symbol's subscription resolution
1790  /// </summary>
1791  /// <param name="symbol">The option symbol whose values we want as an indicator</param>
1792  /// <param name="mirrorOption">The mirror option for parity calculation</param>
1793  /// <param name="riskFreeRate">The risk free rate</param>
1794  /// <param name="dividendYield">The dividend yield</param>
1795  /// <param name="optionModel">The option pricing model used to estimate Rho</param>
1796  /// <param name="ivModel">The option pricing model used to estimate IV</param>
1797  /// <param name="resolution">The desired resolution of the data</param>
1798  /// <returns>A new Rho indicator for the specified symbol</returns>
1799  [DocumentationAttribute(Indicators)]
1800  public Rho ρ(Symbol symbol, Symbol mirrorOption = null, decimal? riskFreeRate = null, decimal? dividendYield = null, OptionPricingModelType optionModel = OptionPricingModelType.BlackScholes,
1801  OptionPricingModelType? ivModel = null, Resolution? resolution = null)
1802  {
1803  return R(symbol, mirrorOption, riskFreeRate, dividendYield, optionModel, ivModel, resolution);
1804  }
1805 
1806 
1807  /// <summary>
1808  /// Creates a new Stochastic RSI indicator which will compute the %K and %D
1809  /// </summary>
1810  /// <param name="symbol">The symbol whose Stochastic RSI we seek</param>
1811  /// <param name="rsiPeriod">The period of the relative strength index</param>
1812  /// <param name="stochPeriod">The period of the stochastic indicator</param>
1813  /// <param name="kSmoothingPeriod">The smoothing period of K output</param>
1814  /// <param name="dSmoothingPeriod">The smoothing period of D output</param>
1815  /// <param name="movingAverageType">The type of moving average to be used</param>
1816  /// <param name="resolution">The resolution</param>
1817  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
1818  /// <returns>A StochasticRelativeStrengthIndex configured with the specified periods and moving average type</returns>
1819  [DocumentationAttribute(Indicators)]
1820  public StochasticRelativeStrengthIndex SRSI(Symbol symbol, int rsiPeriod, int stochPeriod, int kSmoothingPeriod, int dSmoothingPeriod, MovingAverageType movingAverageType = MovingAverageType.Simple,
1821  Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
1822  {
1823  var name = CreateIndicatorName(symbol, $"SRSI({rsiPeriod},{stochPeriod},{kSmoothingPeriod},{dSmoothingPeriod})", resolution);
1824  var indicator = new StochasticRelativeStrengthIndex(name, rsiPeriod, stochPeriod, kSmoothingPeriod, dSmoothingPeriod, movingAverageType);
1825  InitializeIndicator(indicator, resolution, selector, symbol);
1826  return indicator;
1827  }
1828 
1829  /// <summary>
1830  /// Creates a new SuperTrend indicator.
1831  /// </summary>
1832  /// <param name="symbol">The symbol whose SuperTrend indicator we want.</param>
1833  /// <param name="period">The smoothing period for average true range.</param>
1834  /// <param name="multiplier">Multiplier to calculate basic upper and lower bands width.</param>
1835  /// <param name="movingAverageType">Smoother type for average true range, defaults to Wilders.</param>
1836  /// <param name="resolution">The resolution.</param>
1837  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to casting the input value to a TradeBar</param>
1838  [DocumentationAttribute(Indicators)]
1839  public SuperTrend STR(Symbol symbol, int period, decimal multiplier, MovingAverageType movingAverageType = MovingAverageType.Wilders,
1840  Resolution? resolution = null, Func<IBaseData, IBaseDataBar> selector = null)
1841  {
1842  var name = CreateIndicatorName(symbol, $"STR({period},{multiplier})", resolution);
1843  var strend = new SuperTrend(name, period, multiplier, movingAverageType);
1844  InitializeIndicator(strend, resolution, selector, symbol);
1845 
1846  return strend;
1847  }
1848 
1849  /// <summary>
1850  /// Creates a new SharpeRatio indicator.
1851  /// </summary>
1852  /// <param name="symbol">The symbol whose RSR we want</param>
1853  /// <param name="sharpePeriod">Period of historical observation for sharpe ratio calculation</param>
1854  /// <param name="riskFreeRate">
1855  /// Risk-free rate for sharpe ratio calculation. If not specified, it will use the algorithms' <see cref="RiskFreeInterestRateModel"/>
1856  /// </param>
1857  /// <param name="resolution">The resolution</param>
1858  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
1859  /// <returns>The SharpeRatio indicator for the requested symbol over the specified period</returns>
1860  [DocumentationAttribute(Indicators)]
1861  public SharpeRatio SR(Symbol symbol, int sharpePeriod, decimal? riskFreeRate = null, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
1862  {
1863  var baseBame = riskFreeRate.HasValue ? $"SR({sharpePeriod},{riskFreeRate})" : $"SR({sharpePeriod})";
1864  var name = CreateIndicatorName(symbol, baseBame, resolution);
1865  IRiskFreeInterestRateModel riskFreeRateModel = riskFreeRate.HasValue
1866  ? new ConstantRiskFreeRateInterestRateModel(riskFreeRate.Value)
1867  // Make it a function so it's lazily evaluated: SetRiskFreeInterestRateModel can be called after this method
1869  var sharpeRatio = new SharpeRatio(name, sharpePeriod, riskFreeRateModel);
1870  InitializeIndicator(sharpeRatio, resolution, selector, symbol);
1871 
1872  return sharpeRatio;
1873  }
1874 
1875  /// <summary>
1876  /// Creates a new Sortino indicator.
1877  /// </summary>
1878  /// <param name="symbol">The symbol whose Sortino we want</param>
1879  /// <param name="sortinoPeriod">Period of historical observation for Sortino ratio calculation</param>
1880  /// <param name="minimumAcceptableReturn">Minimum acceptable return (eg risk-free rate) for the Sortino ratio calculation</param>
1881  /// <param name="resolution">The resolution</param>
1882  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
1883  /// <returns>The SortinoRatio indicator for the requested symbol over the specified period</returns>
1884  [DocumentationAttribute(Indicators)]
1885  public SortinoRatio SORTINO(Symbol symbol, int sortinoPeriod, double minimumAcceptableReturn = 0.0, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
1886  {
1887  var name = CreateIndicatorName(symbol, $"SORTINO({sortinoPeriod},{minimumAcceptableReturn})", resolution);
1888  var sortinoRatio = new SortinoRatio(name, sortinoPeriod, minimumAcceptableReturn);
1889  InitializeIndicator(sortinoRatio, resolution, selector, symbol);
1890 
1891  return sortinoRatio;
1892  }
1893 
1894 
1895  /// <summary>
1896  /// Creates an SimpleMovingAverage indicator for the symbol. The indicator will be automatically
1897  /// updated on the given resolution.
1898  /// </summary>
1899  /// <param name="symbol">The symbol whose SMA we want</param>
1900  /// <param name="period">The period of the SMA</param>
1901  /// <param name="resolution">The resolution</param>
1902  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
1903  /// <returns>The SimpleMovingAverage for the given parameters</returns>
1904  [DocumentationAttribute(Indicators)]
1905  public SimpleMovingAverage SMA(Symbol symbol, int period, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
1906  {
1907  var name = CreateIndicatorName(symbol, $"SMA({period})", resolution);
1908  var simpleMovingAverage = new SimpleMovingAverage(name, period);
1909  InitializeIndicator(simpleMovingAverage, resolution, selector, symbol);
1910 
1911  return simpleMovingAverage;
1912  }
1913 
1914 
1915  /// <summary>
1916  /// Creates a new Schaff Trend Cycle indicator
1917  /// </summary>
1918  /// <param name="symbol">The symbol for the indicator to track</param>
1919  /// <param name="fastPeriod">The fast moving average period</param>
1920  /// <param name="slowPeriod">The slow moving average period</param>
1921  /// <param name="cyclePeriod">The signal period</param>
1922  /// <param name="movingAverageType">The type of moving average to use</param>
1923  /// <param name="resolution">The resolution</param>
1924  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
1925  /// <returns>The SchaffTrendCycle indicator for the requested symbol over the specified period</returns>
1926  [DocumentationAttribute(Indicators)]
1927  public SchaffTrendCycle STC(Symbol symbol, int cyclePeriod, int fastPeriod, int slowPeriod, MovingAverageType movingAverageType = MovingAverageType.Exponential, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
1928  {
1929  var name = CreateIndicatorName(symbol, $"STC({cyclePeriod},{fastPeriod},{slowPeriod})", resolution);
1930  var schaffTrendCycle = new SchaffTrendCycle(name, cyclePeriod, fastPeriod, slowPeriod, movingAverageType);
1931  InitializeIndicator(schaffTrendCycle, resolution, selector, symbol);
1932 
1933  return schaffTrendCycle;
1934  }
1935 
1936  /// <summary>
1937  /// Creates a new SmoothedOnBalanceVolume indicator for the symbol. The indicator will be automatically
1938  /// updated on the given resolution.
1939  /// </summary>
1940  /// <param name="symbol">The symbol whose SmoothedOnBalanceVolume we want</param>
1941  /// <param name="period">The smoothing period used to smooth the computed OnBalanceVolume values</param>
1942  /// <param name="type">The type of smoothing to use</param>
1943  /// <param name="resolution">The resolution</param>
1944  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to casting the input value to a TradeBar</param>
1945  /// <returns>A new SmoothedOnBalanceVolume indicator with the specified smoothing type and period</returns>
1946  [DocumentationAttribute(Indicators)]
1947  public SmoothedOnBalanceVolume SOBV(Symbol symbol, int period, MovingAverageType type = MovingAverageType.Simple, Resolution? resolution = null, Func<IBaseData, IBaseDataBar> selector = null)
1948  {
1949  var name = CreateIndicatorName(symbol, $"SOBV({period})", resolution);
1950  var indicator = new SmoothedOnBalanceVolume(name, period, type);
1951  InitializeIndicator(indicator, resolution, selector, symbol);
1952  return indicator;
1953  }
1954 
1955  /// <summary>
1956  /// Creates a new StandardDeviation indicator. This will return the population standard deviation of samples over the specified period.
1957  /// </summary>
1958  /// <param name="symbol">The symbol whose STD we want</param>
1959  /// <param name="period">The period over which to compute the STD</param>
1960  /// <param name="resolution">The resolution</param>
1961  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
1962  /// <returns>The StandardDeviation indicator for the requested symbol over the specified period</returns>
1963  [DocumentationAttribute(Indicators)]
1964  public StandardDeviation STD(Symbol symbol, int period, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
1965  {
1966  var name = CreateIndicatorName(symbol, $"STD({period})", resolution);
1967  var standardDeviation = new StandardDeviation(name, period);
1968  InitializeIndicator(standardDeviation, resolution, selector, symbol);
1969 
1970  return standardDeviation;
1971  }
1972 
1973  /// <summary>
1974  /// Creates a new TargetDownsideDeviation indicator. The target downside deviation is defined as the root-mean-square, or RMS, of the deviations of the
1975  /// realized return’s underperformance from the target return where all returns above the target return are treated as underperformance of 0.
1976  /// </summary>
1977  /// <param name="symbol">The symbol whose TDD we want</param>
1978  /// <param name="period">The period over which to compute the TDD</param>
1979  /// <param name="resolution">The resolution</param>
1980  /// <param name="minimumAcceptableReturn">Minimum acceptable return (MAR) for the target downside deviation calculation</param>
1981  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
1982  /// <returns>The TargetDownsideDeviation indicator for the requested symbol over the specified period</returns>
1983  [DocumentationAttribute(Indicators)]
1984  public TargetDownsideDeviation TDD(Symbol symbol, int period, double minimumAcceptableReturn = 0, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
1985  {
1986  var name = CreateIndicatorName(symbol, $"TDD({period},{minimumAcceptableReturn})", resolution);
1987  var targetDownsideDeviation = new TargetDownsideDeviation(name, period, minimumAcceptableReturn);
1988  InitializeIndicator(targetDownsideDeviation, resolution, selector, symbol);
1989 
1990  return targetDownsideDeviation;
1991  }
1992 
1993  /// <summary>
1994  /// Creates a new Stochastic indicator.
1995  /// </summary>
1996  /// <param name="symbol">The symbol whose stochastic we seek</param>
1997  /// <param name="period">The period of the stochastic. Normally 14</param>
1998  /// <param name="kPeriod">The sum period of the stochastic. Normally 14</param>
1999  /// <param name="dPeriod">The sum period of the stochastic. Normally 3</param>
2000  /// <param name="resolution">The resolution.</param>
2001  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to casting the input value to a TradeBar</param>
2002  /// <returns>Stochastic indicator for the requested symbol.</returns>
2003  [DocumentationAttribute(Indicators)]
2004  public Stochastic STO(Symbol symbol, int period, int kPeriod, int dPeriod, Resolution? resolution = null,
2005  Func<IBaseData, TradeBar> selector = null)
2006  {
2007  var name = CreateIndicatorName(symbol, $"STO({period},{kPeriod},{dPeriod})", resolution);
2008  var stochastic = new Stochastic(name, period, kPeriod, dPeriod);
2009  InitializeIndicator(stochastic, resolution, selector, symbol);
2010 
2011  return stochastic;
2012  }
2013 
2014  /// <summary>
2015  /// Overload short hand to create a new Stochastic indicator; defaulting to the 3 period for dStoch
2016  /// </summary>
2017  /// <param name="symbol">The symbol whose stochastic we seek</param>
2018  /// <param name="resolution">The resolution.</param>
2019  /// <param name="period">The period of the stochastic. Normally 14</param>
2020  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to casting the input value to a TradeBar</param>
2021  /// <returns>Stochastic indicator for the requested symbol.</returns>
2022  [DocumentationAttribute(Indicators)]
2023  public Stochastic STO(Symbol symbol, int period, Resolution? resolution = null, Func<IBaseData, TradeBar> selector = null)
2024  {
2025  return STO(symbol, period, period, 3, resolution, selector);
2026  }
2027 
2028  /// <summary>
2029  /// Creates a new instance of the Premier Stochastic Oscillator for the specified symbol.
2030  /// </summary>
2031  /// <param name="symbol">The symbol for which the stochastic indicator is being calculated.</param>
2032  /// <param name="period">The period for calculating the Stochastic K value.</param>
2033  /// <param name="emaPeriod">The period for the Exponential Moving Average (EMA) used to smooth the Stochastic K.</param>
2034  /// <param name="resolution">The data resolution (e.g., daily, hourly) for the indicator</param>
2035  /// <param name="selector">Optional function to select a value from the BaseData. Defaults to casting the input to a TradeBar.</param>
2036  /// <returns>A PremierStochasticOscillator instance for the specified symbol.</returns>
2037  [DocumentationAttribute(Indicators)]
2038  public PremierStochasticOscillator PSO(Symbol symbol, int period, int emaPeriod, Resolution? resolution = null, Func<IBaseData, TradeBar> selector = null)
2039  {
2040  var name = CreateIndicatorName(symbol, $"PSO({period},{emaPeriod})", resolution);
2041  var premierStochasticOscillator = new PremierStochasticOscillator(name, period, emaPeriod);
2042  InitializeIndicator(premierStochasticOscillator, resolution, selector, symbol);
2043  return premierStochasticOscillator;
2044  }
2045 
2046  /// <summary>
2047  /// Creates a new Sum indicator.
2048  /// </summary>
2049  /// <param name="symbol">The symbol whose Sum we want</param>
2050  /// <param name="period">The period over which to compute the Sum</param>
2051  /// <param name="resolution">The resolution</param>
2052  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
2053  /// <returns>The Sum indicator for the requested symbol over the specified period</returns>
2054  [DocumentationAttribute(Indicators)]
2055  public Sum SUM(Symbol symbol, int period, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
2056  {
2057  var name = CreateIndicatorName(symbol, $"SUM({period})", resolution);
2058  var sum = new Sum(name, period);
2059  InitializeIndicator(sum, resolution, selector, symbol);
2060 
2061  return sum;
2062  }
2063 
2064  /// <summary>
2065  /// Creates Swiss Army Knife transformation for the symbol. The indicator will be automatically
2066  /// updated on the given resolution.
2067  /// </summary>
2068  /// <param name="symbol">The symbol to use for calculations</param>
2069  /// <param name="period">The period of the calculation</param>
2070  /// <param name="delta">The delta scale of the BandStop or BandPass</param>
2071  /// <param name="tool">The tool os the Swiss Army Knife</param>
2072  /// <param name="resolution">The resolution</param>
2073  /// <param name="selector">elects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
2074  /// <returns>The calculation using the given tool</returns>
2075  [DocumentationAttribute(Indicators)]
2076  public SwissArmyKnife SWISS(Symbol symbol, int period, double delta, SwissArmyKnifeTool tool, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
2077  {
2078  var name = CreateIndicatorName(symbol, $"SWISS({period},{delta},{tool})", resolution);
2079  var swissArmyKnife = new SwissArmyKnife(name, period, delta, tool);
2080  InitializeIndicator(swissArmyKnife, resolution, selector, symbol);
2081 
2082  return swissArmyKnife;
2083  }
2084 
2085  /// <summary>
2086  /// Creates a new Theta indicator for the symbol The indicator will be automatically
2087  /// updated on the symbol's subscription resolution
2088  /// </summary>
2089  /// <param name="symbol">The option symbol whose values we want as an indicator</param>
2090  /// <param name="mirrorOption">The mirror option for parity calculation</param>
2091  /// <param name="riskFreeRate">The risk free rate</param>
2092  /// <param name="dividendYield">The dividend yield</param>
2093  /// <param name="optionModel">The option pricing model used to estimate Theta</param>
2094  /// <param name="ivModel">The option pricing model used to estimate IV</param>
2095  /// <param name="resolution">The desired resolution of the data</param>
2096  /// <returns>A new Theta indicator for the specified symbol</returns>
2097  [DocumentationAttribute(Indicators)]
2098  public Theta T(Symbol symbol, Symbol mirrorOption = null, decimal? riskFreeRate = null, decimal? dividendYield = null,
2099  OptionPricingModelType? optionModel = null, OptionPricingModelType? ivModel = null, Resolution? resolution = null)
2100  {
2101  var name = InitializeOptionIndicator<Theta>(symbol, out var riskFreeRateModel, out var dividendYieldModel, riskFreeRate, dividendYield, optionModel, resolution);
2102 
2103  var theta = new Theta(name, symbol, riskFreeRateModel, dividendYieldModel, mirrorOption, optionModel, ivModel);
2104  InitializeOptionIndicator(theta, resolution, symbol, mirrorOption);
2105  return theta;
2106  }
2107 
2108  /// <summary>
2109  /// Creates a new Theta indicator for the symbol The indicator will be automatically
2110  /// updated on the symbol's subscription resolution
2111  /// </summary>
2112  /// <param name="symbol">The option symbol whose values we want as an indicator</param>
2113  /// <param name="mirrorOption">The mirror option for parity calculation</param>
2114  /// <param name="riskFreeRate">The risk free rate</param>
2115  /// <param name="dividendYield">The dividend yield</param>
2116  /// <param name="optionModel">The option pricing model used to estimate Theta</param>
2117  /// <param name="ivModel">The option pricing model used to estimate IV</param>
2118  /// <param name="resolution">The desired resolution of the data</param>
2119  /// <returns>A new Theta indicator for the specified symbol</returns>
2120  [DocumentationAttribute(Indicators)]
2121  public Theta Θ(Symbol symbol, Symbol mirrorOption = null, decimal? riskFreeRate = null, decimal? dividendYield = null, OptionPricingModelType optionModel = OptionPricingModelType.BlackScholes,
2122  OptionPricingModelType? ivModel = null, Resolution? resolution = null)
2123  {
2124  return T(symbol, mirrorOption, riskFreeRate, dividendYield, optionModel, ivModel, resolution);
2125  }
2126 
2127  /// <summary>
2128  /// Creates a new T3MovingAverage indicator.
2129  /// </summary>
2130  /// <param name="symbol">The symbol whose T3 we want</param>
2131  /// <param name="period">The period over which to compute the T3</param>
2132  /// <param name="volumeFactor">The volume factor to be used for the T3 (value must be in the [0,1] range, defaults to 0.7)</param>
2133  /// <param name="resolution">The resolution</param>
2134  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
2135  /// <returns>The T3MovingAverage indicator for the requested symbol over the specified period</returns>
2136  [DocumentationAttribute(Indicators)]
2137  public T3MovingAverage T3(Symbol symbol, int period, decimal volumeFactor = 0.7m, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
2138  {
2139  var name = CreateIndicatorName(symbol, $"T3({period},{volumeFactor})", resolution);
2140  var t3MovingAverage = new T3MovingAverage(name, period, volumeFactor);
2141  InitializeIndicator(t3MovingAverage, resolution, selector, symbol);
2142 
2143  return t3MovingAverage;
2144  }
2145 
2146  /// <summary>
2147  /// Creates a new TripleExponentialMovingAverage indicator.
2148  /// </summary>
2149  /// <param name="symbol">The symbol whose TEMA we want</param>
2150  /// <param name="period">The period over which to compute the TEMA</param>
2151  /// <param name="resolution">The resolution</param>
2152  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
2153  /// <returns>The TripleExponentialMovingAverage indicator for the requested symbol over the specified period</returns>
2154  [DocumentationAttribute(Indicators)]
2155  public TripleExponentialMovingAverage TEMA(Symbol symbol, int period, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
2156  {
2157  var name = CreateIndicatorName(symbol, $"TEMA({period})", resolution);
2158  var tripleExponentialMovingAverage = new TripleExponentialMovingAverage(name, period);
2159  InitializeIndicator(tripleExponentialMovingAverage, resolution, selector, symbol);
2160 
2161  return tripleExponentialMovingAverage;
2162  }
2163 
2164  /// <summary>
2165  /// Creates a TrueStrengthIndex indicator for the symbol. The indicator will be automatically
2166  /// updated on the given resolution.
2167  /// </summary>
2168  /// <param name="symbol">The symbol whose TSI we want</param>
2169  /// <param name="shortTermPeriod">Period used for the first price change smoothing</param>
2170  /// <param name="longTermPeriod">Period used for the second (double) price change smoothing</param>
2171  /// <param name="signalPeriod">The signal period</param>
2172  /// <param name="signalType">The type of moving average to use for the signal</param>
2173  /// <param name="resolution">The resolution</param>
2174  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
2175  /// <returns>The TrueStrengthIndex indicator for the given parameters</returns>
2176  [DocumentationAttribute(Indicators)]
2177  public TrueStrengthIndex TSI(Symbol symbol, int longTermPeriod = 25, int shortTermPeriod = 13, int signalPeriod = 7,
2178  MovingAverageType signalType = MovingAverageType.Exponential, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
2179  {
2180  var name = CreateIndicatorName(symbol, $"TSI({longTermPeriod},{shortTermPeriod},{signalPeriod})", resolution);
2181  var trueStrengthIndex = new TrueStrengthIndex(name, longTermPeriod, shortTermPeriod, signalPeriod, signalType);
2182  InitializeIndicator(trueStrengthIndex, resolution, selector, symbol);
2183 
2184  return trueStrengthIndex;
2185  }
2186 
2187  /// <summary>
2188  /// Creates a new TrueRange indicator.
2189  /// </summary>
2190  /// <param name="symbol">The symbol whose TR we want</param>
2191  /// <param name="resolution">The resolution</param>
2192  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to casting the input value to a TradeBar</param>
2193  /// <returns>The TrueRange indicator for the requested symbol.</returns>
2194  [DocumentationAttribute(Indicators)]
2195  public TrueRange TR(Symbol symbol, Resolution? resolution = null, Func<IBaseData, IBaseDataBar> selector = null)
2196  {
2197  var name = CreateIndicatorName(symbol, "TR", resolution);
2198  var trueRange = new TrueRange(name);
2199  InitializeIndicator(trueRange, resolution, selector, symbol);
2200 
2201  return trueRange;
2202  }
2203 
2204  /// <summary>
2205  /// Creates a new TriangularMovingAverage indicator.
2206  /// </summary>
2207  /// <param name="symbol">The symbol whose TRIMA we want</param>
2208  /// <param name="period">The period over which to compute the TRIMA</param>
2209  /// <param name="resolution">The resolution</param>
2210  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
2211  /// <returns>The TriangularMovingAverage indicator for the requested symbol over the specified period</returns>
2212  [DocumentationAttribute(Indicators)]
2213  public TriangularMovingAverage TRIMA(Symbol symbol, int period, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
2214  {
2215  var name = CreateIndicatorName(symbol, $"TRIMA({period})", resolution);
2216  var triangularMovingAverage = new TriangularMovingAverage(name, period);
2217  InitializeIndicator(triangularMovingAverage, resolution, selector, symbol);
2218 
2219  return triangularMovingAverage;
2220  }
2221 
2222  /// <summary>
2223  /// Creates a new Trix indicator.
2224  /// </summary>
2225  /// <param name="symbol">The symbol whose TRIX we want</param>
2226  /// <param name="period">The period over which to compute the TRIX</param>
2227  /// <param name="resolution">The resolution</param>
2228  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
2229  /// <returns>The Trix indicator for the requested symbol over the specified period</returns>
2230  [DocumentationAttribute(Indicators)]
2231  public Trix TRIX(Symbol symbol, int period, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
2232  {
2233  var name = CreateIndicatorName(symbol, $"TRIX({period})", resolution);
2234  var trix = new Trix(name, period);
2235  InitializeIndicator(trix, resolution, selector, symbol);
2236 
2237  return trix;
2238  }
2239 
2240  /// <summary>
2241  /// Creates a new UltimateOscillator indicator.
2242  /// </summary>
2243  /// <param name="symbol">The symbol whose ULTOSC we want</param>
2244  /// <param name="period1">The first period over which to compute the ULTOSC</param>
2245  /// <param name="period2">The second period over which to compute the ULTOSC</param>
2246  /// <param name="period3">The third period over which to compute the ULTOSC</param>
2247  /// <param name="resolution">The resolution</param>
2248  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to casting the input value to a TradeBar</param>
2249  /// <returns>The UltimateOscillator indicator for the requested symbol over the specified period</returns>
2250  [DocumentationAttribute(Indicators)]
2251  public UltimateOscillator ULTOSC(Symbol symbol, int period1, int period2, int period3, Resolution? resolution = null, Func<IBaseData, IBaseDataBar> selector = null)
2252  {
2253  var name = CreateIndicatorName(symbol, $"ULTOSC({period1},{period2},{period3})", resolution);
2254  var ultimateOscillator = new UltimateOscillator(name, period1, period2, period3);
2255  InitializeIndicator(ultimateOscillator, resolution, selector, symbol);
2256 
2257  return ultimateOscillator;
2258  }
2259 
2260  /// <summary>
2261  /// Creates a new Vega indicator for the symbol The indicator will be automatically
2262  /// updated on the symbol's subscription resolution
2263  /// </summary>
2264  /// <param name="symbol">The option symbol whose values we want as an indicator</param>
2265  /// <param name="mirrorOption">The mirror option for parity calculation</param>
2266  /// <param name="riskFreeRate">The risk free rate</param>
2267  /// <param name="dividendYield">The dividend yield</param>
2268  /// <param name="optionModel">The option pricing model used to estimate Vega</param>
2269  /// <param name="ivModel">The option pricing model used to estimate IV</param>
2270  /// <param name="resolution">The desired resolution of the data</param>
2271  /// <returns>A new Vega indicator for the specified symbol</returns>
2272  [DocumentationAttribute(Indicators)]
2273  public Vega V(Symbol symbol, Symbol mirrorOption = null, decimal? riskFreeRate = null, decimal? dividendYield = null,
2274  OptionPricingModelType? optionModel = null, OptionPricingModelType? ivModel = null, Resolution? resolution = null)
2275  {
2276  var name = InitializeOptionIndicator<Vega>(symbol, out var riskFreeRateModel, out var dividendYieldModel, riskFreeRate, dividendYield, optionModel, resolution);
2277 
2278  var vega = new Vega(name, symbol, riskFreeRateModel, dividendYieldModel, mirrorOption, optionModel, ivModel);
2279  InitializeOptionIndicator(vega, resolution, symbol, mirrorOption);
2280  return vega;
2281  }
2282 
2283  /// <summary>
2284  /// Creates a new Chande's Variable Index Dynamic Average indicator.
2285  /// </summary>
2286  /// <param name="symbol">The symbol whose VIDYA we want</param>
2287  /// <param name="period">The period over which to compute the VIDYA</param>
2288  /// <param name="resolution">The resolution</param>
2289  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
2290  /// <returns>The VariableIndexDynamicAverage indicator for the requested symbol over the specified period</returns>
2291  [DocumentationAttribute(Indicators)]
2292  public VariableIndexDynamicAverage VIDYA(Symbol symbol, int period, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
2293  {
2294  var name = CreateIndicatorName(symbol, $"VIDYA({period})", resolution);
2295  var variableIndexDynamicAverage = new VariableIndexDynamicAverage(name, period);
2296  InitializeIndicator(variableIndexDynamicAverage, resolution, selector, symbol);
2297 
2298  return variableIndexDynamicAverage;
2299  }
2300 
2301  /// <summary>
2302  /// Creates a new Variance indicator. This will return the population variance of samples over the specified period.
2303  /// </summary>
2304  /// <param name="symbol">The symbol whose VAR we want</param>
2305  /// <param name="period">The period over which to compute the VAR</param>
2306  /// <param name="resolution">The resolution</param>
2307  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
2308  /// <returns>The Variance indicator for the requested symbol over the specified period</returns>
2309  [DocumentationAttribute(Indicators)]
2310  [Obsolete("'VAR' is obsolete please use 'V' instead")]
2311  public Variance VAR(Symbol symbol, int period, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
2312  {
2313  return V(symbol, period, resolution, selector);
2314  }
2315 
2316  /// <summary>
2317  /// Creates a new Variance indicator. This will return the population variance of samples over the specified period.
2318  /// </summary>
2319  /// <param name="symbol">The symbol whose variance we want</param>
2320  /// <param name="period">The period over which to compute the variance</param>
2321  /// <param name="resolution">The resolution</param>
2322  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
2323  /// <returns>The Variance indicator for the requested symbol over the specified period</returns>
2324  [DocumentationAttribute(Indicators)]
2325  public Variance V(Symbol symbol, int period, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
2326  {
2327  var name = CreateIndicatorName(symbol, $"V({period})", resolution);
2328  var variance = new Variance(name, period);
2329  InitializeIndicator(variance, resolution, selector, symbol);
2330 
2331  return variance;
2332  }
2333 
2334  /// <summary>
2335  /// Creates a new ValueAtRisk indicator.
2336  /// </summary>
2337  /// <param name="symbol">The symbol whose VAR we want</param>
2338  /// <param name="period">The period over which to compute the VAR</param>
2339  /// <param name="confidenceLevel">The confidence level for Value at risk calculation</param>
2340  /// <param name="resolution">The resolution</param>
2341  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
2342  /// <returns>The ValueAtRisk indicator for the requested Symbol, lookback period, and confidence level</returns>
2343  public ValueAtRisk VAR(Symbol symbol, int period, double confidenceLevel, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
2344  {
2345  var name = CreateIndicatorName(symbol, $"VAR({period},{confidenceLevel})", resolution);
2346  var valueAtRisk = new ValueAtRisk(name, period, confidenceLevel);
2347  InitializeIndicator(valueAtRisk, resolution, selector, symbol);
2348 
2349  return valueAtRisk;
2350  }
2351 
2352  /// <summary>
2353  /// Creates an VolumeWeightedAveragePrice (VWAP) indicator for the symbol. The indicator will be automatically
2354  /// updated on the given resolution.
2355  /// </summary>
2356  /// <param name="symbol">The symbol whose VWAP we want</param>
2357  /// <param name="period">The period of the VWAP</param>
2358  /// <param name="resolution">The resolution</param>
2359  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to casting the input value to a TradeBar</param>
2360  /// <returns>The VolumeWeightedAveragePrice for the given parameters</returns>
2361  [DocumentationAttribute(Indicators)]
2362  public VolumeWeightedAveragePriceIndicator VWAP(Symbol symbol, int period, Resolution? resolution = null, Func<IBaseData, TradeBar> selector = null)
2363  {
2364  var name = CreateIndicatorName(symbol, $"VWAP({period})", resolution);
2365  var volumeWeightedAveragePriceIndicator = new VolumeWeightedAveragePriceIndicator(name, period);
2366  InitializeIndicator(volumeWeightedAveragePriceIndicator, resolution, selector, symbol);
2367 
2368  return volumeWeightedAveragePriceIndicator;
2369  }
2370 
2371  /// <summary>
2372  /// Creates the canonical VWAP indicator that resets each day. The indicator will be automatically
2373  /// updated on the security's configured resolution.
2374  /// </summary>
2375  /// <param name="symbol">The symbol whose VWAP we want</param>
2376  /// <returns>The IntradayVWAP for the specified symbol</returns>
2377  [DocumentationAttribute(Indicators)]
2378  public IntradayVwap VWAP(Symbol symbol)
2379  {
2380  var name = CreateIndicatorName(symbol, "VWAP", null);
2381  var intradayVwap = new IntradayVwap(name);
2382  RegisterIndicator(symbol, intradayVwap);
2383  return intradayVwap;
2384  }
2385 
2386  /// <summary>
2387  /// Creates a new VolumeWeightedMovingAverage indicator for the symbol. The indicator will be automatically
2388  /// updated on the given resolution.
2389  /// </summary>
2390  /// <param name="symbol">The symbol whose VWMA we want</param>
2391  /// <param name="period">The smoothing period used to smooth the computed VWMA values</param>
2392  /// <param name="resolution">The resolution</param>
2393  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to casting the input value to a TradeBar</param>
2394  /// <returns>A new VolumeWeightedMovingAverage indicator with the specified smoothing period</returns>
2395  [DocumentationAttribute(Indicators)]
2396  public VolumeWeightedMovingAverage VWMA(Symbol symbol, int period, Resolution? resolution = null, Func<IBaseData, TradeBar> selector = null)
2397  {
2398  var name = CreateIndicatorName(symbol, $"VWMA({period})", resolution);
2399  var indicator = new VolumeWeightedMovingAverage(name, period);
2400  InitializeIndicator(indicator, resolution, selector, symbol);
2401  return indicator;
2402  }
2403 
2404  /// <summary>
2405  /// Creates a new Vortex indicator for the symbol. The indicator will be automatically
2406  /// updated on the given resolution.
2407  /// </summary>
2408  /// <param name="symbol">The symbol whose VWMA we want</param>
2409  /// <param name="period">The smoothing period used to smooth the computed VWMA values</param>
2410  /// <param name="resolution">The resolution</param>
2411  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to casting the input value to a TradeBar</param>
2412  /// <returns>A new Vortex indicator with the specified smoothing period</returns>
2413  [DocumentationAttribute(Indicators)]
2414  public Vortex VTX(Symbol symbol, int period, Resolution? resolution = null, Func<IBaseData, IBaseDataBar> selector = null)
2415  {
2416  var name = CreateIndicatorName(symbol, $"VTX({period})", resolution);
2417  var indicator = new Vortex(name, period);
2418  InitializeIndicator(indicator, resolution, selector, symbol);
2419  return indicator;
2420  }
2421 
2422  /// <summary>
2423  /// Creates a new Williams %R indicator. This will compute the percentage change of
2424  /// the current closing price in relation to the high and low of the past N periods.
2425  /// The indicator will be automatically updated on the given resolution.
2426  /// </summary>
2427  /// <param name="symbol">The symbol whose Williams %R we want</param>
2428  /// <param name="period">The period over which to compute the Williams %R</param>
2429  /// <param name="resolution">The resolution</param>
2430  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to casting the input value to a TradeBar</param>
2431  /// <returns>The Williams %R indicator for the requested symbol over the specified period</returns>
2432  [DocumentationAttribute(Indicators)]
2433  public WilliamsPercentR WILR(Symbol symbol, int period, Resolution? resolution = null, Func<IBaseData, IBaseDataBar> selector = null)
2434  {
2435  var name = CreateIndicatorName(symbol, $"WILR({period})", resolution);
2436  var williamsPercentR = new WilliamsPercentR(name, period);
2437  InitializeIndicator(williamsPercentR, resolution, selector, symbol);
2438 
2439  return williamsPercentR;
2440  }
2441 
2442  /// <summary>
2443  /// Creates a WilderMovingAverage indicator for the symbol.
2444  /// The indicator will be automatically updated on the given resolution.
2445  /// </summary>
2446  /// <param name="symbol">The symbol whose WMA we want</param>
2447  /// <param name="period">The period of the WMA</param>
2448  /// <param name="resolution">The resolution</param>
2449  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
2450  /// <returns>The WilderMovingAverage for the given parameters</returns>
2451  /// <remarks>WWMA for Welles Wilder Moving Average</remarks>
2452  [DocumentationAttribute(Indicators)]
2453  public WilderMovingAverage WWMA(Symbol symbol, int period, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
2454  {
2455  var name = CreateIndicatorName(symbol, $"WWMA({period})", resolution);
2456  var wilderMovingAverage = new WilderMovingAverage(name, period);
2457  InitializeIndicator(wilderMovingAverage, resolution, selector, symbol);
2458 
2459  return wilderMovingAverage;
2460  }
2461 
2462  /// <summary>
2463  /// Creates a Wilder Swing Index (SI) indicator for the symbol.
2464  /// The indicator will be automatically updated on the given resolution.
2465  /// </summary>
2466  /// <param name="symbol">The symbol whose SI we want</param>
2467  /// <param name="limitMove">The maximum daily change in price for the SI</param>
2468  /// <param name="resolution">The resolution</param>
2469  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to casting the input value to a TradeBar</param>
2470  /// <returns>The WilderSwingIndex for the given parameters</returns>
2471  /// <remarks>SI for Wilder Swing Index</remarks>
2472  [DocumentationAttribute(Indicators)]
2473  public WilderSwingIndex SI(Symbol symbol, decimal limitMove, Resolution? resolution = Resolution.Daily,
2474  Func<IBaseData, TradeBar> selector = null)
2475  {
2476  var name = CreateIndicatorName(symbol, "SI", resolution);
2477  var si = new WilderSwingIndex(name, limitMove);
2478  InitializeIndicator(si, resolution, selector, symbol);
2479 
2480  return si;
2481  }
2482 
2483  /// <summary>
2484  /// Creates a Wilder Accumulative Swing Index (ASI) indicator for the symbol.
2485  /// The indicator will be automatically updated on the given resolution.
2486  /// </summary>
2487  /// <param name="symbol">The symbol whose ASI we want</param>
2488  /// <param name="limitMove">The maximum daily change in price for the ASI</param>
2489  /// <param name="resolution">The resolution</param>
2490  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to casting the input value to a TradeBar</param>
2491  /// <returns>The WilderAccumulativeSwingIndex for the given parameters</returns>
2492  /// <remarks>ASI for Wilder Accumulative Swing Index</remarks>
2493  [DocumentationAttribute(Indicators)]
2494  public WilderAccumulativeSwingIndex ASI(Symbol symbol, decimal limitMove, Resolution? resolution = Resolution.Daily,
2495  Func<IBaseData, TradeBar> selector = null)
2496  {
2497  var name = CreateIndicatorName(symbol, "ASI", resolution);
2498  var asi = new WilderAccumulativeSwingIndex(name, limitMove);
2499  InitializeIndicator(asi, resolution, selector, symbol);
2500 
2501  return asi;
2502  }
2503 
2504  /// <summary>
2505  /// Creates a new Arms Index indicator
2506  /// </summary>
2507  /// <param name="symbols">The symbols whose Arms Index we want</param>
2508  /// <param name="resolution">The resolution</param>
2509  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to casting the input value to a TradeBar</param>
2510  /// <returns>The Arms Index indicator for the requested symbol over the specified period</returns>
2511  [DocumentationAttribute(Indicators)]
2512  public ArmsIndex TRIN(IEnumerable<Symbol> symbols, Resolution? resolution = null, Func<IBaseData, TradeBar> selector = null)
2513  {
2514  return TRIN(symbols.ToArray(), resolution, selector);
2515  }
2516 
2517  /// <summary>
2518  /// Creates a new Arms Index indicator
2519  /// </summary>
2520  /// <param name="symbols">The symbols whose Arms Index we want</param>
2521  /// <param name="resolution">The resolution</param>
2522  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to casting the input value to a TradeBar</param>
2523  /// <returns>The Arms Index indicator for the requested symbol over the specified period</returns>
2524  [DocumentationAttribute(Indicators)]
2525  public ArmsIndex TRIN(Symbol[] symbols, Resolution? resolution = null, Func<IBaseData, TradeBar> selector = null)
2526  {
2527  var name = CreateIndicatorName(QuantConnect.Symbol.None, "TRIN", resolution ?? GetSubscription(symbols.First()).Resolution);
2528  var trin = new ArmsIndex(name);
2529  foreach (var symbol in symbols)
2530  {
2531  trin.Add(symbol);
2532  }
2533  InitializeIndicator(trin, resolution, selector, symbols);
2534 
2535  return trin;
2536  }
2537 
2538  /// <summary>
2539  /// Creates a new Advance/Decline Ratio indicator
2540  /// </summary>
2541  /// <param name="symbols">The symbols whose A/D Ratio we want</param>
2542  /// <param name="resolution">The resolution</param>
2543  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to casting the input value to a TradeBar</param>
2544  /// <returns>The Advance/Decline Ratio indicator for the requested symbol over the specified period</returns>
2545  [DocumentationAttribute(Indicators)]
2546  public AdvanceDeclineRatio ADR(IEnumerable<Symbol> symbols, Resolution? resolution = null, Func<IBaseData, TradeBar> selector = null)
2547  {
2548  var name = CreateIndicatorName(QuantConnect.Symbol.None, "A/D Ratio", resolution ?? GetSubscription(symbols.First()).Resolution);
2549  var adr = new AdvanceDeclineRatio(name);
2550  foreach (var symbol in symbols)
2551  {
2552  adr.Add(symbol);
2553  }
2554  InitializeIndicator(adr, resolution, selector, symbols.ToArray());
2555 
2556  return adr;
2557  }
2558 
2559  /// <summary>
2560  /// Creates a new Advance/Decline Volume Ratio indicator
2561  /// </summary>
2562  /// <param name="symbols">The symbol whose A/D Volume Rate we want</param>
2563  /// <param name="resolution">The resolution</param>
2564  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to casting the input value to a TradeBar</param>
2565  /// <returns>The Advance/Decline Volume Ratio indicator for the requested symbol over the specified period</returns>
2566  [DocumentationAttribute(Indicators)]
2567  public AdvanceDeclineVolumeRatio ADVR(IEnumerable<Symbol> symbols, Resolution? resolution = null, Func<IBaseData, TradeBar> selector = null)
2568  {
2569  var name = CreateIndicatorName(QuantConnect.Symbol.None, "A/D Volume Rate", resolution ?? GetSubscription(symbols.First()).Resolution);
2570  var advr = new AdvanceDeclineVolumeRatio(name);
2571  foreach (var symbol in symbols)
2572  {
2573  advr.Add(symbol);
2574  }
2575  InitializeIndicator(advr, resolution, selector, symbols.ToArray());
2576 
2577  return advr;
2578  }
2579 
2580  /// <summary>
2581  /// Creates a new Advance/Decline Difference indicator
2582  /// </summary>
2583  /// <param name="symbols">The symbols whose A/D Difference we want</param>
2584  /// <param name="resolution">The resolution</param>
2585  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to casting the input value to a TradeBar</param>
2586  /// <returns>The Advance/Decline Difference indicator for the requested symbol over the specified period</returns>
2587  [DocumentationAttribute(Indicators)]
2588  public AdvanceDeclineDifference ADDIFF(IEnumerable<Symbol> symbols, Resolution? resolution = null, Func<IBaseData, TradeBar> selector = null)
2589  {
2590  var name = CreateIndicatorName(QuantConnect.Symbol.None, "A/D Difference", resolution ?? GetSubscription(symbols.First()).Resolution);
2591  var adDiff = new AdvanceDeclineDifference(name);
2592  foreach (var symbol in symbols)
2593  {
2594  adDiff.Add(symbol);
2595  }
2596  InitializeIndicator(adDiff, resolution, selector, symbols.ToArray());
2597 
2598  return adDiff;
2599  }
2600 
2601  /// <summary>
2602  /// Creates a new McGinley Dynamic indicator
2603  /// </summary>
2604  /// <param name="symbol">The symbol whose McGinley Dynamic indicator value we want</param>
2605  /// <param name="period">The period of the McGinley Dynamic indicator</param>
2606  /// <param name="resolution">The resolution</param>
2607  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to casting the input value to a TradeBar</param>
2608  /// <returns>The McGinley Dynamic indicator for the requested symbol over the specified period</returns>
2609  [DocumentationAttribute(Indicators)]
2610  public McGinleyDynamic MGD(Symbol symbol, int period, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
2611  {
2612  var name = CreateIndicatorName(symbol, $"MGD({period})", resolution);
2613  var indicator = new McGinleyDynamic(name, period);
2614  InitializeIndicator(indicator, resolution, selector, symbol);
2615  return indicator;
2616  }
2617 
2618  /// <summary>
2619  /// Creates a new McClellan Oscillator indicator
2620  /// </summary>
2621  /// <param name="symbols">The symbols whose McClellan Oscillator we want</param>
2622  /// <param name="fastPeriod">Fast period EMA of advance decline difference</param>
2623  /// <param name="slowPeriod">Slow period EMA of advance decline difference</param>
2624  /// <param name="resolution">The resolution</param>
2625  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to casting the input value to a TradeBar</param>
2626  /// <returns>The McClellan Oscillator indicator for the requested symbol over the specified period</returns>
2627  [DocumentationAttribute(Indicators)]
2628  public McClellanOscillator MOSC(IEnumerable<Symbol> symbols, int fastPeriod = 19, int slowPeriod = 39, Resolution? resolution = null, Func<IBaseData, TradeBar> selector = null)
2629  {
2630  return MOSC(symbols.ToArray(), fastPeriod, slowPeriod, resolution, selector);
2631  }
2632 
2633  /// <summary>
2634  /// Creates a new McClellan Oscillator indicator
2635  /// </summary>
2636  /// <param name="symbols">The symbols whose McClellan Oscillator we want</param>
2637  /// <param name="fastPeriod">Fast period EMA of advance decline difference</param>
2638  /// <param name="slowPeriod">Slow period EMA of advance decline difference</param>
2639  /// <param name="resolution">The resolution</param>
2640  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to casting the input value to a TradeBar</param>
2641  /// <returns>The McClellan Oscillator indicator for the requested symbol over the specified period</returns>
2642  [DocumentationAttribute(Indicators)]
2643  public McClellanOscillator MOSC(Symbol[] symbols, int fastPeriod = 19, int slowPeriod = 39, Resolution? resolution = null, Func<IBaseData, TradeBar> selector = null)
2644  {
2645  var name = CreateIndicatorName(QuantConnect.Symbol.None, $"MO({fastPeriod},{slowPeriod})", resolution ?? GetSubscription(symbols.First()).Resolution);
2646  var mosc = new McClellanOscillator(name, fastPeriod, slowPeriod);
2647  foreach (var symbol in symbols)
2648  {
2649  mosc.Add(symbol);
2650  }
2651  InitializeIndicator(mosc, resolution, selector, symbols);
2652 
2653  return mosc;
2654  }
2655 
2656  /// <summary>
2657  /// Creates a new McClellan Summation Index indicator
2658  /// </summary>
2659  /// <param name="symbols">The symbols whose McClellan Summation Index we want</param>
2660  /// <param name="fastPeriod">Fast period EMA of advance decline difference</param>
2661  /// <param name="slowPeriod">Slow period EMA of advance decline difference</param>
2662  /// <param name="resolution">The resolution</param>
2663  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to casting the input value to a TradeBar</param>
2664  /// <returns>The McClellan Summation Index indicator for the requested symbol over the specified period</returns>
2665  [DocumentationAttribute(Indicators)]
2666  public McClellanSummationIndex MSI(IEnumerable<Symbol> symbols, int fastPeriod = 19, int slowPeriod = 39, Resolution? resolution = null, Func<IBaseData, TradeBar> selector = null)
2667  {
2668  return MSI(symbols.ToArray(), fastPeriod, slowPeriod, resolution, selector);
2669  }
2670 
2671  /// <summary>
2672  /// Creates a new McClellan Summation Index indicator
2673  /// </summary>
2674  /// <param name="symbols">The symbols whose McClellan Summation Index we want</param>
2675  /// <param name="fastPeriod">Fast period EMA of advance decline difference</param>
2676  /// <param name="slowPeriod">Slow period EMA of advance decline difference</param>
2677  /// <param name="resolution">The resolution</param>
2678  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to casting the input value to a TradeBar</param>
2679  /// <returns>The McClellan Summation Index indicator for the requested symbol over the specified period</returns>
2680  [DocumentationAttribute(Indicators)]
2681  public McClellanSummationIndex MSI(Symbol[] symbols, int fastPeriod = 19, int slowPeriod = 39, Resolution? resolution = null, Func<IBaseData, TradeBar> selector = null)
2682  {
2683  var name = CreateIndicatorName(QuantConnect.Symbol.None, $"MSI({fastPeriod},{slowPeriod})", resolution ?? GetSubscription(symbols.First()).Resolution);
2684  var msi = new McClellanSummationIndex(name, fastPeriod, slowPeriod);
2685  foreach (var symbol in symbols)
2686  {
2687  msi.Add(symbol);
2688  }
2689  InitializeIndicator(msi, resolution, selector, symbols);
2690 
2691  return msi;
2692  }
2693 
2694 
2695  /// <summary>
2696  /// Creates a new RogersSatchellVolatility indicator for the symbol. The indicator will be automatically
2697  /// updated on the given resolution.
2698  /// </summary>
2699  /// <param name="symbol">The symbol whose RogersSatchellVolatility we want</param>
2700  /// <param name="period">The period of the rolling window used to compute volatility</param>
2701  /// <param name="resolution">The resolution</param>
2702  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to casting the input value to a TradeBar</param>
2703  /// <returns>A new RogersSatchellVolatility indicator with the specified smoothing type and period</returns>
2704  [DocumentationAttribute(Indicators)]
2705  public RogersSatchellVolatility RSV(Symbol symbol, int period, Resolution? resolution = null, Func<IBaseData, IBaseDataBar> selector = null)
2706  {
2707  var name = CreateIndicatorName(symbol, $"RSV({period})", resolution);
2708  var indicator = new RogersSatchellVolatility(name, period);
2709  InitializeIndicator(indicator, resolution, selector, symbol);
2710 
2711  return indicator;
2712  }
2713 
2714  /// <summary>
2715  /// Creates a ZeroLagExponentialMovingAverage indicator for the symbol. The indicator will be automatically
2716  /// updated on the given resolution.
2717  /// </summary>
2718  /// <param name="symbol">The symbol whose ZLEMA we want</param>
2719  /// <param name="period">The period of the ZLEMA</param>
2720  /// <param name="resolution">The resolution</param>
2721  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
2722  /// <returns>The ZeroLagExponentialMovingAverage for the given parameters</returns>
2723  [DocumentationAttribute(Indicators)]
2724  public ZeroLagExponentialMovingAverage ZLEMA(Symbol symbol, int period, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
2725  {
2726  var name = CreateIndicatorName(symbol, $"ZLEMA({period})", resolution);
2727  var zeroLagExponentialMovingAverage = new ZeroLagExponentialMovingAverage(name, period);
2728  InitializeIndicator(zeroLagExponentialMovingAverage, resolution, selector, symbol);
2729 
2730  return zeroLagExponentialMovingAverage;
2731  }
2732 
2733  /// <summary>
2734  /// Creates a new name for an indicator created with the convenience functions (SMA, EMA, ect...)
2735  /// </summary>
2736  /// <param name="symbol">The symbol this indicator is registered to</param>
2737  /// <param name="type">The indicator type, for example, 'SMA(5)'</param>
2738  /// <param name="resolution">The resolution requested</param>
2739  /// <returns>A unique for the given parameters</returns>
2740  [DocumentationAttribute(Indicators)]
2741  public string CreateIndicatorName(Symbol symbol, FormattableString type, Resolution? resolution)
2742  {
2743  return CreateIndicatorName(symbol, Invariant(type), resolution);
2744  }
2745 
2746  /// <summary>
2747  /// Creates a new name for an indicator created with the convenience functions (SMA, EMA, ect...)
2748  /// </summary>
2749  /// <param name="symbol">The symbol this indicator is registered to</param>
2750  /// <param name="type">The indicator type, for example, 'SMA(5)'</param>
2751  /// <param name="resolution">The resolution requested</param>
2752  /// <returns>A unique for the given parameters</returns>
2753  [DocumentationAttribute(Indicators)]
2754  public string CreateIndicatorName(Symbol symbol, string type, Resolution? resolution)
2755  {
2756  var symbolIsNotEmpty = symbol != QuantConnect.Symbol.None && symbol != QuantConnect.Symbol.Empty;
2757 
2758  if (!resolution.HasValue && symbolIsNotEmpty)
2759  {
2760  resolution = GetSubscription(symbol).Resolution;
2761  }
2762 
2763  var res = string.Empty;
2764  switch (resolution)
2765  {
2766  case Resolution.Tick:
2767  res = "tick";
2768  break;
2769 
2770  case Resolution.Second:
2771  res = "sec";
2772  break;
2773 
2774  case Resolution.Minute:
2775  res = "min";
2776  break;
2777 
2778  case Resolution.Hour:
2779  res = "hr";
2780  break;
2781 
2782  case Resolution.Daily:
2783  res = "day";
2784  break;
2785 
2786  case null:
2787  break;
2788 
2789  default:
2790  throw new ArgumentOutOfRangeException(nameof(resolution), resolution, "resolution parameter is out of range.");
2791  }
2792 
2793  var parts = new List<string>();
2794 
2795  if (symbolIsNotEmpty)
2796  {
2797  parts.Add(symbol.ToString());
2798  }
2799  parts.Add(res);
2800 
2801  return Invariant($"{type}({string.Join("_", parts)})").Replace(")(", ",");
2802  }
2803 
2804  /// <summary>
2805  /// Gets the SubscriptionDataConfig for the specified symbol and tick type
2806  /// </summary>
2807  /// <exception cref="InvalidOperationException">Thrown if no configuration is found for the requested symbol</exception>
2808  /// <param name="symbol">The symbol to retrieve configuration for</param>
2809  /// <param name="tickType">The tick type of the subscription to get. If null, will use the first ordered by TickType</param>
2810  /// <returns>The SubscriptionDataConfig for the specified symbol</returns>
2811  private SubscriptionDataConfig GetSubscription(Symbol symbol, TickType? tickType = null)
2812  {
2813  SubscriptionDataConfig subscription;
2814  try
2815  {
2816  // deterministic ordering is required here
2819  // make sure common lean data types are at the bottom
2820  .OrderByDescending(x => LeanData.IsCommonLeanDataType(x.Type))
2821  .ThenBy(x => x.TickType)
2822  .ToList();
2823 
2824  // find our subscription
2825  subscription = subscriptions.FirstOrDefault(x => tickType == null || tickType == x.TickType);
2826  if (subscription == null)
2827  {
2828  // if we can't locate the exact subscription by tick type just grab the first one we find
2829  subscription = subscriptions.First();
2830  }
2831  }
2832  catch (InvalidOperationException)
2833  {
2834  // this will happen if we did not find the subscription, let's give the user a decent error message
2835  throw new Exception($"Please register to receive data for symbol \'{symbol}\' using the AddSecurity() function.");
2836  }
2837  return subscription;
2838  }
2839 
2840  /// <summary>
2841  /// Creates and registers a new consolidator to receive automatic updates at the specified resolution as well as configures
2842  /// the indicator to receive updates from the consolidator.
2843  /// </summary>
2844  /// <param name="symbol">The symbol to register against</param>
2845  /// <param name="indicator">The indicator to receive data from the consolidator</param>
2846  /// <param name="resolution">The resolution at which to send data to the indicator, null to use the same resolution as the subscription</param>
2847  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
2848  [DocumentationAttribute(ConsolidatingData)]
2849  [DocumentationAttribute(Indicators)]
2850  public void RegisterIndicator(Symbol symbol, IndicatorBase<IndicatorDataPoint> indicator, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
2851  {
2852  RegisterIndicator(symbol, indicator, ResolveConsolidator(symbol, resolution), selector ?? (x => x.Value));
2853  }
2854 
2855  /// <summary>
2856  /// Creates and registers a new consolidator to receive automatic updates at the specified resolution as well as configures
2857  /// the indicator to receive updates from the consolidator.
2858  /// </summary>
2859  /// <param name="symbol">The symbol to register against</param>
2860  /// <param name="indicator">The indicator to receive data from the consolidator</param>
2861  /// <param name="resolution">The resolution at which to send data to the indicator, null to use the same resolution as the subscription</param>
2862  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
2863  [DocumentationAttribute(ConsolidatingData)]
2864  [DocumentationAttribute(Indicators)]
2865  public void RegisterIndicator(Symbol symbol, IndicatorBase<IndicatorDataPoint> indicator, TimeSpan? resolution = null, Func<IBaseData, decimal> selector = null)
2866  {
2867  RegisterIndicator(symbol, indicator, ResolveConsolidator(symbol, resolution), selector ?? (x => x.Value));
2868  }
2869 
2870  /// <summary>
2871  /// Registers the consolidator to receive automatic updates as well as configures the indicator to receive updates
2872  /// from the consolidator.
2873  /// </summary>
2874  /// <param name="symbol">The symbol to register against</param>
2875  /// <param name="indicator">The indicator to receive data from the consolidator</param>
2876  /// <param name="consolidator">The consolidator to receive raw subscription data</param>
2877  /// <param name="selector">Selects a value from the BaseData send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
2878  [DocumentationAttribute(ConsolidatingData)]
2879  [DocumentationAttribute(Indicators)]
2880  public void RegisterIndicator(Symbol symbol, IndicatorBase<IndicatorDataPoint> indicator, IDataConsolidator consolidator, Func<IBaseData, decimal> selector = null)
2881  {
2882  // default our selector to the Value property on BaseData
2883  selector = selector ?? (x => x.Value);
2884 
2885  RegisterConsolidator(symbol, consolidator, null, indicator);
2886 
2887  // attach to the DataConsolidated event so it updates our indicator
2888  consolidator.DataConsolidated += (sender, consolidated) =>
2889  {
2890  var value = selector(consolidated);
2891  indicator.Update(new IndicatorDataPoint(consolidated.Symbol, consolidated.EndTime, value));
2892  };
2893  }
2894 
2895  /// <summary>
2896  /// Registers the consolidator to receive automatic updates as well as configures the indicator to receive updates
2897  /// from the consolidator.
2898  /// </summary>
2899  /// <param name="symbol">The symbol to register against</param>
2900  /// <param name="indicator">The indicator to receive data from the consolidator</param>
2901  /// <param name="resolution">The resolution at which to send data to the indicator, null to use the same resolution as the subscription</param>
2902  [DocumentationAttribute(ConsolidatingData)]
2903  [DocumentationAttribute(Indicators)]
2904  public void RegisterIndicator<T>(Symbol symbol, IndicatorBase<T> indicator, Resolution? resolution = null)
2905  where T : IBaseData
2906  {
2907  RegisterIndicator(symbol, indicator, ResolveConsolidator(symbol, resolution, typeof(T)));
2908  }
2909 
2910  /// <summary>
2911  /// Registers the consolidator to receive automatic updates as well as configures the indicator to receive updates
2912  /// from the consolidator.
2913  /// </summary>
2914  /// <param name="symbol">The symbol to register against</param>
2915  /// <param name="indicator">The indicator to receive data from the consolidator</param>
2916  /// <param name="resolution">The resolution at which to send data to the indicator, null to use the same resolution as the subscription</param>
2917  /// <param name="selector">Selects a value from the BaseData send into the indicator, if null defaults to a cast (x => (T)x)</param>
2918  [DocumentationAttribute(ConsolidatingData)]
2919  [DocumentationAttribute(Indicators)]
2920  public void RegisterIndicator<T>(Symbol symbol, IndicatorBase<T> indicator, Resolution? resolution, Func<IBaseData, T> selector)
2921  where T : IBaseData
2922  {
2923  RegisterIndicator(symbol, indicator, ResolveConsolidator(symbol, resolution, typeof(T)), selector);
2924  }
2925 
2926  /// <summary>
2927  /// Registers the consolidator to receive automatic updates as well as configures the indicator to receive updates
2928  /// from the consolidator.
2929  /// </summary>
2930  /// <param name="symbol">The symbol to register against</param>
2931  /// <param name="indicator">The indicator to receive data from the consolidator</param>
2932  /// <param name="resolution">The resolution at which to send data to the indicator, null to use the same resolution as the subscription</param>
2933  /// <param name="selector">Selects a value from the BaseData send into the indicator, if null defaults to a cast (x => (T)x)</param>
2934  [DocumentationAttribute(ConsolidatingData)]
2935  [DocumentationAttribute(Indicators)]
2936  public void RegisterIndicator<T>(Symbol symbol, IndicatorBase<T> indicator, TimeSpan? resolution, Func<IBaseData, T> selector = null)
2937  where T : IBaseData
2938  {
2939  RegisterIndicator(symbol, indicator, ResolveConsolidator(symbol, resolution, typeof(T)), selector);
2940  }
2941 
2942  /// <summary>
2943  /// Registers the consolidator to receive automatic updates as well as configures the indicator to receive updates
2944  /// from the consolidator.
2945  /// </summary>
2946  /// <param name="symbol">The symbol to register against</param>
2947  /// <param name="indicator">The indicator to receive data from the consolidator</param>
2948  /// <param name="consolidator">The consolidator to receive raw subscription data</param>
2949  /// <param name="selector">Selects a value from the BaseData send into the indicator, if null defaults to a cast (x => (T)x)</param>
2950  [DocumentationAttribute(ConsolidatingData)]
2951  [DocumentationAttribute(Indicators)]
2952  public void RegisterIndicator<T>(Symbol symbol, IndicatorBase<T> indicator, IDataConsolidator consolidator, Func<IBaseData, T> selector = null)
2953  where T : IBaseData
2954  {
2955  // assign default using cast
2956  var selectorToUse = selector ?? (x => (T)x);
2957 
2958  RegisterConsolidator(symbol, consolidator, null, indicator);
2959 
2960  // check the output type of the consolidator and verify we can assign it to T
2961  var type = typeof(T);
2962  if (!type.IsAssignableFrom(consolidator.OutputType))
2963  {
2964  if (type == typeof(IndicatorDataPoint) && selector == null)
2965  {
2966  // if no selector was provided and the indicator input is of 'IndicatorDataPoint', common case, a selector with a direct cast will fail
2967  // so we use a smarter selector as in other API methods
2968  selectorToUse = consolidated => (T)(object)new IndicatorDataPoint(consolidated.Symbol, consolidated.EndTime, consolidated.Value);
2969  }
2970  else
2971  {
2972  throw new ArgumentException($"Type mismatch found between consolidator and indicator for symbol: {symbol}." +
2973  $"Consolidator outputs type {consolidator.OutputType.Name} but indicator expects input type {type.Name}"
2974  );
2975  }
2976  }
2977 
2978  // attach to the DataConsolidated event so it updates our indicator
2979  consolidator.DataConsolidated += (sender, consolidated) =>
2980  {
2981  var value = selectorToUse(consolidated);
2982  indicator.Update(value);
2983  };
2984  }
2985 
2986  /// <summary>
2987  /// Will unregister an indicator and it's associated consolidator instance so they stop receiving data updates
2988  /// </summary>
2989  /// <param name="indicator">The indicator instance to unregister</param>
2990  [DocumentationAttribute(ConsolidatingData)]
2991  [DocumentationAttribute(Indicators)]
2992  public void UnregisterIndicator(IndicatorBase indicator)
2993  {
2994  DeregisterIndicator(indicator);
2995  }
2996 
2997  /// <summary>
2998  /// Will deregister an indicator and it's associated consolidator instance so they stop receiving data updates
2999  /// </summary>
3000  /// <param name="indicator">The indicator instance to deregister</param>
3001  [DocumentationAttribute(ConsolidatingData)]
3002  [DocumentationAttribute(Indicators)]
3003  public void DeregisterIndicator(IndicatorBase indicator)
3004  {
3005  foreach (var consolidator in indicator.Consolidators)
3006  {
3007  SubscriptionManager.RemoveConsolidator(null, consolidator);
3008  }
3009 
3010  indicator.Consolidators.Clear();
3011  }
3012 
3013  /// <summary>
3014  /// Warms up a given indicator with historical data
3015  /// </summary>
3016  /// <param name="symbol">The symbol whose indicator we want</param>
3017  /// <param name="indicator">The indicator we want to warm up</param>
3018  /// <param name="resolution">The resolution</param>
3019  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
3020  [DocumentationAttribute(HistoricalData)]
3021  [DocumentationAttribute(Indicators)]
3022  public void WarmUpIndicator(Symbol symbol, IndicatorBase<IndicatorDataPoint> indicator, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
3023  {
3024  WarmUpIndicator(new[] { symbol }, indicator, resolution, selector);
3025  }
3026 
3027  /// <summary>
3028  /// Warms up a given indicator with historical data
3029  /// </summary>
3030  /// <param name="symbols">The symbols whose indicator we want</param>
3031  /// <param name="indicator">The indicator we want to warm up</param>
3032  /// <param name="resolution">The resolution</param>
3033  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
3034  [DocumentationAttribute(HistoricalData)]
3035  [DocumentationAttribute(Indicators)]
3036  public void WarmUpIndicator(IEnumerable<Symbol> symbols, IndicatorBase<IndicatorDataPoint> indicator, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
3037  {
3038  if (AssertIndicatorHasWarmupPeriod(indicator))
3039  {
3040  IndicatorHistory(indicator, symbols, 0, resolution, selector);
3041  }
3042  }
3043 
3044  /// <summary>
3045  /// Warms up a given indicator with historical data
3046  /// </summary>
3047  /// <param name="symbol">The symbol whose indicator we want</param>
3048  /// <param name="indicator">The indicator we want to warm up</param>
3049  /// <param name="period">The necessary period to warm up the indicator</param>
3050  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
3051  [DocumentationAttribute(HistoricalData)]
3052  [DocumentationAttribute(Indicators)]
3053  public void WarmUpIndicator(Symbol symbol, IndicatorBase<IndicatorDataPoint> indicator, TimeSpan period, Func<IBaseData, decimal> selector = null)
3054  {
3055  var history = GetIndicatorWarmUpHistory(new[] { symbol }, indicator, period, out var identityConsolidator);
3056  if (history == Enumerable.Empty<Slice>()) return;
3057 
3058  // assign default using cast
3059  selector ??= (x => x.Value);
3060 
3061  Action<IBaseData> onDataConsolidated = bar =>
3062  {
3063  var input = new IndicatorDataPoint(bar.Symbol, bar.EndTime, selector(bar));
3064  indicator.Update(input);
3065  };
3066 
3067  WarmUpIndicatorImpl(symbol, period, onDataConsolidated, history, identityConsolidator);
3068  }
3069 
3070  /// <summary>
3071  /// Warms up a given indicator with historical data
3072  /// </summary>
3073  /// <param name="symbol">The symbol whose indicator we want</param>
3074  /// <param name="indicator">The indicator we want to warm up</param>
3075  /// <param name="resolution">The resolution</param>
3076  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
3077  [DocumentationAttribute(HistoricalData)]
3078  [DocumentationAttribute(Indicators)]
3079  public void WarmUpIndicator<T>(Symbol symbol, IndicatorBase<T> indicator, Resolution? resolution = null, Func<IBaseData, T> selector = null)
3080  where T : class, IBaseData
3081  {
3082  WarmUpIndicator(new[] { symbol }, indicator, resolution, selector);
3083  }
3084 
3085  /// <summary>
3086  /// Warms up a given indicator with historical data
3087  /// </summary>
3088  /// <param name="symbols">The symbols whose indicator we want</param>
3089  /// <param name="indicator">The indicator we want to warm up</param>
3090  /// <param name="resolution">The resolution</param>
3091  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
3092  [DocumentationAttribute(HistoricalData)]
3093  [DocumentationAttribute(Indicators)]
3094  public void WarmUpIndicator<T>(IEnumerable<Symbol> symbols, IndicatorBase<T> indicator, Resolution? resolution = null, Func<IBaseData, T> selector = null)
3095  where T : class, IBaseData
3096  {
3097  if (AssertIndicatorHasWarmupPeriod(indicator))
3098  {
3099  IndicatorHistory(indicator, symbols, 0, resolution, selector);
3100  }
3101  }
3102 
3103  /// <summary>
3104  /// Warms up a given indicator with historical data
3105  /// </summary>
3106  /// <param name="symbol">The symbol whose indicator we want</param>
3107  /// <param name="indicator">The indicator we want to warm up</param>
3108  /// <param name="period">The necessary period to warm up the indicator</param>
3109  /// <param name="selector">Selects a value from the BaseData send into the indicator, if null defaults to a cast (x => (T)x)</param>
3110  [DocumentationAttribute(HistoricalData)]
3111  [DocumentationAttribute(Indicators)]
3112  public void WarmUpIndicator<T>(Symbol symbol, IndicatorBase<T> indicator, TimeSpan period, Func<IBaseData, T> selector = null)
3113  where T : class, IBaseData
3114  {
3115  var history = GetIndicatorWarmUpHistory(new[] { symbol }, indicator, period, out var identityConsolidator);
3116  if (history == Enumerable.Empty<Slice>()) return;
3117 
3118  // assign default using cast
3119  selector ??= (x => (T)x);
3120 
3121  // we expect T type as input
3122  Action<T> onDataConsolidated = bar =>
3123  {
3124  indicator.Update(selector(bar));
3125  };
3126 
3127  WarmUpIndicatorImpl(symbol, period, onDataConsolidated, history, identityConsolidator);
3128  }
3129 
3130  private IEnumerable<Slice> GetIndicatorWarmUpHistory(IEnumerable<Symbol> symbols, IIndicator indicator, TimeSpan timeSpan, out bool identityConsolidator)
3131  {
3132  identityConsolidator = false;
3133  if (!AssertIndicatorHasWarmupPeriod(indicator))
3134  {
3135  return Enumerable.Empty<Slice>();
3136  }
3137 
3138  var periods = ((IIndicatorWarmUpPeriodProvider)indicator).WarmUpPeriod;
3139  if (periods != 0)
3140  {
3141  var resolution = timeSpan.ToHigherResolutionEquivalent(false);
3142  // if they are the same, means we can use an identity consolidator
3143  identityConsolidator = resolution.ToTimeSpan() == timeSpan;
3144  var resolutionTicks = resolution.ToTimeSpan().Ticks;
3145  if (resolutionTicks != 0)
3146  {
3147  periods *= (int)(timeSpan.Ticks / resolutionTicks);
3148  }
3149 
3150  try
3151  {
3152  return History(symbols, periods, resolution, dataNormalizationMode: GetIndicatorHistoryDataNormalizationMode(indicator));
3153  }
3154  catch (ArgumentException e)
3155  {
3156  Debug($"{indicator.Name} could not be warmed up. Reason: {e.Message}");
3157  }
3158  }
3159  return Enumerable.Empty<Slice>();
3160  }
3161 
3162  private bool AssertIndicatorHasWarmupPeriod(IIndicator indicator)
3163  {
3164  if (indicator is not IIndicatorWarmUpPeriodProvider)
3165  {
3166  if (!_isEmitWarmupInsightWarningSent)
3167  {
3168  Debug($"Warning: the 'WarmUpIndicator' feature only works with indicators which inherit from '{nameof(IIndicatorWarmUpPeriodProvider)}'" +
3169  $" and define a warm up period, setting property 'WarmUpPeriod' with a value > 0." +
3170  $" The provided indicator of type '{indicator.GetType().Name}' will not be warmed up.");
3171  _isEmitWarmupInsightWarningSent = true;
3172  }
3173  return false;
3174  }
3175  return true;
3176  }
3177 
3178  private void WarmUpIndicatorImpl<T>(Symbol symbol, TimeSpan period, Action<T> handler, IEnumerable<Slice> history, bool identityConsolidator)
3179  where T : class, IBaseData
3180  {
3181  IDataConsolidator consolidator;
3183  {
3184  consolidator = Consolidate(symbol, period, handler);
3185  }
3186  else
3187  {
3188  if (identityConsolidator)
3189  {
3190  period = TimeSpan.Zero;
3191  }
3192 
3193  var providedType = typeof(T);
3194  if (providedType.IsAbstract)
3195  {
3197  symbol.SecurityType,
3198  Resolution.Daily,
3199  // order by tick type so that behavior is consistent with 'GetSubscription()'
3200  symbol.IsCanonical())
3201  // make sure common lean data types are at the bottom
3202  .OrderByDescending(tuple => LeanData.IsCommonLeanDataType(tuple.Item1))
3203  .ThenBy(tuple => tuple.Item2).First();
3204 
3205  consolidator = CreateConsolidator(period, dataType.Item1, dataType.Item2);
3206  }
3207  else
3208  {
3209  // if the 'providedType' is not abstract we use it instead to determine which consolidator to use
3210  var tickType = LeanData.GetCommonTickTypeForCommonDataTypes(providedType, symbol.SecurityType);
3211  consolidator = CreateConsolidator(period, providedType, tickType);
3212  }
3213  consolidator.DataConsolidated += (s, bar) => handler((T)bar);
3214  }
3215 
3216  var consolidatorInputType = consolidator.InputType;
3217  IBaseData lastBar = null;
3218  foreach (var slice in history)
3219  {
3220  if (slice.TryGet(consolidatorInputType, symbol, out var data))
3221  {
3222  lastBar = data;
3223  consolidator.Update(lastBar);
3224  }
3225  }
3226 
3227  // Scan for time after we've pumped all the data through for this consolidator
3228  if (lastBar != null)
3229  {
3230  consolidator.Scan(lastBar.EndTime);
3231  }
3232 
3233  SubscriptionManager.RemoveConsolidator(symbol, consolidator);
3234  }
3235 
3236  /// <summary>
3237  /// Gets the default consolidator for the specified symbol and resolution
3238  /// </summary>
3239  /// <param name="symbol">The symbol whose data is to be consolidated</param>
3240  /// <param name="resolution">The resolution for the consolidator, if null, uses the resolution from subscription</param>
3241  /// <param name="dataType">The data type for this consolidator, if null, uses TradeBar over QuoteBar if present</param>
3242  /// <returns>The new default consolidator</returns>
3243  [DocumentationAttribute(ConsolidatingData)]
3244  [DocumentationAttribute(Indicators)]
3245  public IDataConsolidator ResolveConsolidator(Symbol symbol, Resolution? resolution, Type dataType = null)
3246  {
3247  var tickType = dataType != null ? LeanData.GetCommonTickTypeForCommonDataTypes(dataType, symbol.SecurityType) : (TickType?)null;
3248  return CreateConsolidator(symbol, null, tickType, null, resolution, null);
3249  }
3250 
3251  /// <summary>
3252  /// Gets the default consolidator for the specified symbol and resolution
3253  /// </summary>
3254  /// <param name="symbol">The symbol whose data is to be consolidated</param>
3255  /// <param name="timeSpan">The requested time span for the consolidator, if null, uses the resolution from subscription</param>
3256  /// <param name="dataType">The data type for this consolidator, if null, uses TradeBar over QuoteBar if present</param>
3257  /// <returns>The new default consolidator</returns>
3258  [DocumentationAttribute(ConsolidatingData)]
3259  [DocumentationAttribute(Indicators)]
3260  public IDataConsolidator ResolveConsolidator(Symbol symbol, TimeSpan? timeSpan, Type dataType = null)
3261  {
3262  var tickType = dataType != null ? LeanData.GetCommonTickTypeForCommonDataTypes(dataType, symbol.SecurityType) : (TickType?)null;
3263  return CreateConsolidator(symbol, null, tickType, timeSpan, null, null);
3264  }
3265 
3266  /// <summary>
3267  /// Creates a new consolidator for the specified period, generating the requested output type.
3268  /// </summary>
3269  /// <param name="period">The consolidation period</param>
3270  /// <param name="consolidatorInputType">The desired input type of the consolidator, such as TradeBar or QuoteBar</param>
3271  /// <param name="tickType">Trade or Quote. Optional, defaults to trade</param>
3272  /// <returns>A new consolidator matching the requested parameters</returns>
3273  [DocumentationAttribute(ConsolidatingData)]
3274  public static IDataConsolidator CreateConsolidator(TimeSpan period, Type consolidatorInputType, TickType? tickType = null)
3275  {
3276  if (period.Ticks == 0)
3277  {
3278  return CreateIdentityConsolidator(consolidatorInputType);
3279  }
3280 
3281  // if our type can be used as a trade bar, then let's just make one of those
3282  // we use IsAssignableFrom instead of IsSubclassOf so that we can account for types that are able to be cast to TradeBar
3283  if (typeof(TradeBar).IsAssignableFrom(consolidatorInputType))
3284  {
3285  return new TradeBarConsolidator(period);
3286  }
3287 
3288  // if our type can be used as a quote bar, then let's just make one of those
3289  // we use IsAssignableFrom instead of IsSubclassOf so that we can account for types that are able to be cast to QuoteBar
3290  if (typeof(QuoteBar).IsAssignableFrom(consolidatorInputType))
3291  {
3292  return new QuoteBarConsolidator(period);
3293  }
3294 
3295  // if our type can be used as a tick then we'll use a consolidator that keeps the TickType
3296  // we use IsAssignableFrom instead of IsSubclassOf so that we can account for types that are able to be cast to Tick
3297  if (typeof(Tick).IsAssignableFrom(consolidatorInputType))
3298  {
3299  switch (tickType)
3300  {
3301  case TickType.OpenInterest:
3302  return new OpenInterestConsolidator(period);
3303 
3304  case TickType.Quote:
3305  return new TickQuoteBarConsolidator(period);
3306 
3307  default:
3308  return new TickConsolidator(period);
3309  }
3310  }
3311 
3312  // if our type can be used as a DynamicData then we'll use the DynamicDataConsolidator
3313  if (typeof(DynamicData).IsAssignableFrom(consolidatorInputType))
3314  {
3315  return new DynamicDataConsolidator(period);
3316  }
3317 
3318  // no matter what we can always consolidate based on the time-value pair of BaseData
3319  return new BaseDataConsolidator(period);
3320  }
3321 
3322  /// <summary>
3323  /// Registers the <paramref name="handler"/> to receive consolidated data for the specified symbol
3324  /// </summary>
3325  /// <param name="symbol">The symbol who's data is to be consolidated</param>
3326  /// <param name="period">The consolidation period</param>
3327  /// <param name="handler">Data handler receives new consolidated data when generated</param>
3328  /// <returns>A new consolidator matching the requested parameters with the handler already registered</returns>
3329  [DocumentationAttribute(ConsolidatingData)]
3330  public IDataConsolidator Consolidate(Symbol symbol, Resolution period, Action<TradeBar> handler)
3331  {
3332  return Consolidate(symbol, period, TickType.Trade, handler);
3333  }
3334 
3335  /// <summary>
3336  /// Registers the <paramref name="handler"/> to receive consolidated data for the specified symbol
3337  /// </summary>
3338  /// <param name="symbol">The symbol who's data is to be consolidated</param>
3339  /// <param name="period">The consolidation period</param>
3340  /// <param name="handler">Data handler receives new consolidated data when generated</param>
3341  /// <returns>A new consolidator matching the requested parameters with the handler already registered</returns>
3342  [DocumentationAttribute(ConsolidatingData)]
3343  public IDataConsolidator Consolidate(Symbol symbol, TimeSpan period, Action<TradeBar> handler)
3344  {
3345  return Consolidate(symbol, period, TickType.Trade, handler);
3346  }
3347 
3348  /// <summary>
3349  /// Registers the <paramref name="handler"/> to receive consolidated data for the specified symbol
3350  /// </summary>
3351  /// <param name="symbol">The symbol who's data is to be consolidated</param>
3352  /// <param name="period">The consolidation period</param>
3353  /// <param name="handler">Data handler receives new consolidated data when generated</param>
3354  /// <returns>A new consolidator matching the requested parameters with the handler already registered</returns>
3355  [DocumentationAttribute(ConsolidatingData)]
3356  public IDataConsolidator Consolidate(Symbol symbol, Resolution period, Action<QuoteBar> handler)
3357  {
3358  return Consolidate(symbol, period.ToTimeSpan(), TickType.Quote, handler);
3359  }
3360 
3361  /// <summary>
3362  /// Registers the <paramref name="handler"/> to receive consolidated data for the specified symbol
3363  /// </summary>
3364  /// <param name="symbol">The symbol who's data is to be consolidated</param>
3365  /// <param name="period">The consolidation period</param>
3366  /// <param name="handler">Data handler receives new consolidated data when generated</param>
3367  /// <returns>A new consolidator matching the requested parameters with the handler already registered</returns>
3368  [DocumentationAttribute(ConsolidatingData)]
3369  public IDataConsolidator Consolidate(Symbol symbol, TimeSpan period, Action<QuoteBar> handler)
3370  {
3371  return Consolidate(symbol, period, TickType.Quote, handler);
3372  }
3373 
3374  /// <summary>
3375  /// Registers the <paramref name="handler"/> to receive consolidated data for the specified symbol and tick type.
3376  /// The handler and tick type must match.
3377  /// </summary>
3378  /// <param name="symbol">The symbol who's data is to be consolidated</param>
3379  /// <param name="period">The consolidation period</param>
3380  /// <param name="handler">Data handler receives new consolidated data when generated</param>
3381  /// <returns>A new consolidator matching the requested parameters with the handler already registered</returns>
3382  [DocumentationAttribute(ConsolidatingData)]
3383  public IDataConsolidator Consolidate<T>(Symbol symbol, TimeSpan period, Action<T> handler)
3384  where T : class, IBaseData
3385  {
3386  // only infer TickType from T if it's not abstract (for example IBaseData, BaseData), else if will end up being TradeBar let's not take that
3387  // decision here (default type), it will be taken later by 'GetSubscription' so we keep it centralized
3388  // This could happen when a user passes in a generic 'Action<BaseData>' handler
3389  var tickType = typeof(T).IsAbstract ? (TickType?)null : LeanData.GetCommonTickTypeForCommonDataTypes(typeof(T), symbol.SecurityType);
3390  return Consolidate(symbol, period, tickType, handler);
3391  }
3392 
3393  /// <summary>
3394  /// Registers the <paramref name="handler"/> to receive consolidated data for the specified symbol and tick type.
3395  /// The handler and tick type must match.
3396  /// </summary>
3397  /// <param name="symbol">The symbol who's data is to be consolidated</param>
3398  /// <param name="period">The consolidation period</param>
3399  /// <param name="tickType">The tick type of subscription used as data source for consolidator. Specify null to use first subscription found.</param>
3400  /// <param name="handler">Data handler receives new consolidated data when generated</param>
3401  /// <returns>A new consolidator matching the requested parameters with the handler already registered</returns>
3402  [DocumentationAttribute(ConsolidatingData)]
3403  public IDataConsolidator Consolidate<T>(Symbol symbol, Resolution period, TickType? tickType, Action<T> handler)
3404  where T : class, IBaseData
3405  {
3406  return Consolidate(symbol, null, tickType, handler, null, period);
3407  }
3408 
3409  /// <summary>
3410  /// Registers the <paramref name="handler"/> to receive consolidated data for the specified symbol and tick type.
3411  /// The handler and tick type must match.
3412  /// </summary>
3413  /// <param name="symbol">The symbol who's data is to be consolidated</param>
3414  /// <param name="period">The consolidation period</param>
3415  /// <param name="tickType">The tick type of subscription used as data source for consolidator. Specify null to use first subscription found.</param>
3416  /// <param name="handler">Data handler receives new consolidated data when generated</param>
3417  /// <returns>A new consolidator matching the requested parameters with the handler already registered</returns>
3418  [DocumentationAttribute(ConsolidatingData)]
3419  public IDataConsolidator Consolidate<T>(Symbol symbol, TimeSpan period, TickType? tickType, Action<T> handler)
3420  where T : class, IBaseData
3421  {
3422  return Consolidate(symbol, null, tickType, handler, period, null);
3423  }
3424 
3425  /// <summary>
3426  /// Registers the <paramref name="handler"/> to receive consolidated data for the specified symbol
3427  /// </summary>
3428  /// <param name="symbol">The symbol who's data is to be consolidated</param>
3429  /// <param name="calendar">The consolidation calendar</param>
3430  /// <param name="handler">Data handler receives new consolidated data when generated</param>
3431  /// <returns>A new consolidator matching the requested parameters with the handler already registered</returns>
3432  [DocumentationAttribute(ConsolidatingData)]
3433  public IDataConsolidator Consolidate(Symbol symbol, Func<DateTime, CalendarInfo> calendar, Action<QuoteBar> handler)
3434  {
3435  return Consolidate(symbol, calendar, TickType.Quote, handler);
3436  }
3437 
3438  /// <summary>
3439  /// Registers the <paramref name="handler"/> to receive consolidated data for the specified symbol
3440  /// </summary>
3441  /// <param name="symbol">The symbol who's data is to be consolidated</param>
3442  /// <param name="calendar">The consolidation calendar</param>
3443  /// <param name="handler">Data handler receives new consolidated data when generated</param>
3444  /// <returns>A new consolidator matching the requested parameters with the handler already registered</returns>
3445  [DocumentationAttribute(ConsolidatingData)]
3446  public IDataConsolidator Consolidate(Symbol symbol, Func<DateTime, CalendarInfo> calendar, Action<TradeBar> handler)
3447  {
3448  return Consolidate(symbol, calendar, TickType.Trade, handler);
3449  }
3450 
3451  /// <summary>
3452  /// Registers the <paramref name="handler"/> to receive consolidated data for the specified symbol and tick type.
3453  /// The handler and tick type must match.
3454  /// </summary>
3455  /// <param name="symbol">The symbol who's data is to be consolidated</param>
3456  /// <param name="calendar">The consolidation calendar</param>
3457  /// <param name="handler">Data handler receives new consolidated data when generated</param>
3458  /// <returns>A new consolidator matching the requested parameters with the handler already registered</returns>
3459  [DocumentationAttribute(ConsolidatingData)]
3460  public IDataConsolidator Consolidate<T>(Symbol symbol, Func<DateTime, CalendarInfo> calendar, Action<T> handler)
3461  where T : class, IBaseData
3462  {
3463  // only infer TickType from T if it's not abstract (for example IBaseData, BaseData), else if will end up being TradeBar let's not take that
3464  // decision here (default type), it will be taken later by 'GetSubscription' so we keep it centralized
3465  // This could happen when a user passes in a generic 'Action<BaseData>' handler
3466  var tickType = typeof(T).IsAbstract ? (TickType?)null : LeanData.GetCommonTickTypeForCommonDataTypes(typeof(T), symbol.SecurityType);
3467  return Consolidate(symbol, calendar, tickType, handler);
3468  }
3469 
3470  /// <summary>
3471  /// Registers the <paramref name="handler"/> to receive consolidated data for the specified symbol and tick type.
3472  /// The handler and tick type must match.
3473  /// </summary>
3474  /// <param name="symbol">The symbol who's data is to be consolidated</param>
3475  /// <param name="calendar">The consolidation calendar</param>
3476  /// <param name="tickType">The tick type of subscription used as data source for consolidator. Specify null to use first subscription found.</param>
3477  /// <param name="handler">Data handler receives new consolidated data when generated</param>
3478  /// <returns>A new consolidator matching the requested parameters with the handler already registered</returns>
3479  [DocumentationAttribute(ConsolidatingData)]
3480  public IDataConsolidator Consolidate<T>(Symbol symbol, Func<DateTime, CalendarInfo> calendar, TickType? tickType, Action<T> handler)
3481  where T : class, IBaseData
3482  {
3483  return Consolidate(symbol, calendar, tickType, handler, null, null);
3484  }
3485 
3486  /// <summary>
3487  /// Gets the historical data of an indicator for the specified symbol. The exact number of bars will be returned.
3488  /// The symbol must exist in the Securities collection.
3489  /// </summary>
3490  /// <param name="indicator">The target indicator</param>
3491  /// <param name="symbol">The symbol to retrieve historical data for</param>
3492  /// <param name="period">The number of bars to request</param>
3493  /// <param name="resolution">The resolution to request</param>
3494  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
3495  /// <returns>pandas.DataFrame of historical data of an indicator</returns>
3496  public IndicatorHistory IndicatorHistory(IndicatorBase<IndicatorDataPoint> indicator, Symbol symbol, int period, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
3497  {
3498  return IndicatorHistory(indicator, new[] { symbol }, period, resolution, selector);
3499  }
3500 
3501  /// <summary>
3502  /// Gets the historical data of an indicator for the specified symbols. The exact number of bars will be returned.
3503  /// The symbol must exist in the Securities collection.
3504  /// </summary>
3505  /// <param name="indicator">The target indicator</param>
3506  /// <param name="symbols">The symbols to retrieve historical data for</param>
3507  /// <param name="period">The number of bars to request</param>
3508  /// <param name="resolution">The resolution to request</param>
3509  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
3510  /// <returns>pandas.DataFrame of historical data of an indicator</returns>
3511  public IndicatorHistory IndicatorHistory(IndicatorBase<IndicatorDataPoint> indicator, IEnumerable<Symbol> symbols, int period, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
3512  {
3513  var warmupPeriod = (indicator as IIndicatorWarmUpPeriodProvider)?.WarmUpPeriod ?? 0;
3514  if (warmupPeriod > 0 && period > 0)
3515  {
3516  warmupPeriod -= 1;
3517  }
3518  var history = History(symbols, period + warmupPeriod, resolution, dataNormalizationMode: GetIndicatorHistoryDataNormalizationMode(indicator));
3519  return IndicatorHistory(indicator, history, selector);
3520  }
3521 
3522  /// <summary>
3523  /// Gets the historical data of a bar indicator for the specified symbol. The exact number of bars will be returned.
3524  /// The symbol must exist in the Securities collection.
3525  /// </summary>
3526  /// <param name="indicator">The target indicator</param>
3527  /// <param name="symbol">The symbol to retrieve historical data for</param>
3528  /// <param name="period">The number of bars to request</param>
3529  /// <param name="resolution">The resolution to request</param>
3530  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
3531  /// <returns>pandas.DataFrame of historical data of a bar indicator</returns>
3532  public IndicatorHistory IndicatorHistory<T>(IndicatorBase<T> indicator, Symbol symbol, int period, Resolution? resolution = null, Func<IBaseData, T> selector = null)
3533  where T : IBaseData
3534  {
3535  return IndicatorHistory(indicator, new[] { symbol }, period, resolution, selector);
3536  }
3537 
3538  /// <summary>
3539  /// Gets the historical data of a bar indicator for the specified symbols. The exact number of bars will be returned.
3540  /// The symbol must exist in the Securities collection.
3541  /// </summary>
3542  /// <param name="indicator">The target indicator</param>
3543  /// <param name="symbols">The symbols to retrieve historical data for</param>
3544  /// <param name="period">The number of bars to request</param>
3545  /// <param name="resolution">The resolution to request</param>
3546  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
3547  /// <returns>pandas.DataFrame of historical data of a bar indicator</returns>
3548  public IndicatorHistory IndicatorHistory<T>(IndicatorBase<T> indicator, IEnumerable<Symbol> symbols, int period, Resolution? resolution = null, Func<IBaseData, T> selector = null)
3549  where T : IBaseData
3550  {
3551  var warmupPeriod = (indicator as IIndicatorWarmUpPeriodProvider)?.WarmUpPeriod ?? 0;
3552  if (warmupPeriod > 0 && period > 0)
3553  {
3554  warmupPeriod -= 1;
3555  }
3556  var history = History(symbols, period + warmupPeriod, resolution, dataNormalizationMode: GetIndicatorHistoryDataNormalizationMode(indicator));
3557  return IndicatorHistory(indicator, history, selector);
3558  }
3559 
3560  /// <summary>
3561  /// Gets the historical data of an indicator for the specified symbol. The exact number of bars will be returned.
3562  /// The symbol must exist in the Securities collection.
3563  /// </summary>
3564  /// <param name="indicator">The target indicator</param>
3565  /// <param name="symbol">The symbol to retrieve historical data for</param>
3566  /// <param name="span">The span over which to retrieve recent historical data</param>
3567  /// <param name="resolution">The resolution to request</param>
3568  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
3569  /// <returns>pandas.DataFrame of historical data of an indicator</returns>
3570  public IndicatorHistory IndicatorHistory(IndicatorBase<IndicatorDataPoint> indicator, Symbol symbol, TimeSpan span, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
3571  {
3572  return IndicatorHistory(indicator, new[] { symbol }, span, resolution, selector);
3573  }
3574 
3575  /// <summary>
3576  /// Gets the historical data of an indicator for the specified symbol. The exact number of bars will be returned.
3577  /// The symbol must exist in the Securities collection.
3578  /// </summary>
3579  /// <param name="indicator">The target indicator</param>
3580  /// <param name="symbols">The symbols to retrieve historical data for</param>
3581  /// <param name="span">The span over which to retrieve recent historical data</param>
3582  /// <param name="resolution">The resolution to request</param>
3583  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
3584  /// <returns>pandas.DataFrame of historical data of an indicator</returns>
3585  public IndicatorHistory IndicatorHistory(IndicatorBase<IndicatorDataPoint> indicator, IEnumerable<Symbol> symbols, TimeSpan span, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
3586  {
3587  return IndicatorHistory(indicator, symbols, Time - span, Time, resolution, selector);
3588  }
3589 
3590  /// <summary>
3591  /// Gets the historical data of a bar indicator for the specified symbol. The exact number of bars will be returned.
3592  /// The symbol must exist in the Securities collection.
3593  /// </summary>
3594  /// <param name="indicator">The target indicator</param>
3595  /// <param name="symbols">The symbols to retrieve historical data for</param>
3596  /// <param name="span">The span over which to retrieve recent historical data</param>
3597  /// <param name="resolution">The resolution to request</param>
3598  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
3599  /// <returns>pandas.DataFrame of historical data of a bar indicator</returns>
3600  public IndicatorHistory IndicatorHistory<T>(IndicatorBase<T> indicator, IEnumerable<Symbol> symbols, TimeSpan span, Resolution? resolution = null, Func<IBaseData, T> selector = null)
3601  where T : IBaseData
3602  {
3603  return IndicatorHistory(indicator, symbols, Time - span, Time, resolution, selector);
3604  }
3605 
3606  /// <summary>
3607  /// Gets the historical data of a bar indicator for the specified symbol. The exact number of bars will be returned.
3608  /// The symbol must exist in the Securities collection.
3609  /// </summary>
3610  /// <param name="indicator">The target indicator</param>
3611  /// <param name="symbol">The symbol to retrieve historical data for</param>
3612  /// <param name="span">The span over which to retrieve recent historical data</param>
3613  /// <param name="resolution">The resolution to request</param>
3614  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
3615  /// <returns>pandas.DataFrame of historical data of a bar indicator</returns>
3616  public IndicatorHistory IndicatorHistory<T>(IndicatorBase<T> indicator, Symbol symbol, TimeSpan span, Resolution? resolution = null, Func<IBaseData, T> selector = null)
3617  where T : IBaseData
3618  {
3619  return IndicatorHistory(indicator, new[] { symbol }, span, resolution, selector);
3620  }
3621 
3622  /// <summary>
3623  /// Gets the historical data of an indicator for the specified symbols. The exact number of bars will be returned.
3624  /// The symbol must exist in the Securities collection.
3625  /// </summary>
3626  /// <param name="indicator">The target indicator</param>
3627  /// <param name="symbols">The symbols to retrieve historical data for</param>
3628  /// <param name="start">The start time in the algorithm's time zone</param>
3629  /// <param name="end">The end time in the algorithm's time zone</param>
3630  /// <param name="resolution">The resolution to request</param>
3631  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
3632  /// <returns>pandas.DataFrame of historical data of an indicator</returns>
3633  public IndicatorHistory IndicatorHistory(IndicatorBase<IndicatorDataPoint> indicator, IEnumerable<Symbol> symbols, DateTime start, DateTime end, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
3634  {
3635  var history = History(symbols, GetIndicatorAdjustedHistoryStart(indicator, symbols, start, end, resolution), end, resolution, dataNormalizationMode: GetIndicatorHistoryDataNormalizationMode(indicator));
3636  return IndicatorHistory(indicator, history, selector);
3637  }
3638 
3639  /// <summary>
3640  /// Gets the historical data of an indicator for the specified symbol. The exact number of bars will be returned.
3641  /// The symbol must exist in the Securities collection.
3642  /// </summary>
3643  /// <param name="indicator">The target indicator</param>
3644  /// <param name="symbol">The symbol to retrieve historical data for</param>
3645  /// <param name="start">The start time in the algorithm's time zone</param>
3646  /// <param name="end">The end time in the algorithm's time zone</param>
3647  /// <param name="resolution">The resolution to request</param>
3648  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
3649  /// <returns>pandas.DataFrame of historical data of an indicator</returns>
3650  public IndicatorHistory IndicatorHistory(IndicatorBase<IndicatorDataPoint> indicator, Symbol symbol, DateTime start, DateTime end, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
3651  {
3652  return IndicatorHistory(indicator, new[] { symbol }, start, end, resolution, selector);
3653  }
3654 
3655  /// <summary>
3656  /// Gets the historical data of a bar indicator for the specified symbol. The exact number of bars will be returned.
3657  /// The symbol must exist in the Securities collection.
3658  /// </summary>
3659  /// <param name="indicator">The target indicator</param>
3660  /// <param name="symbol">The symbol to retrieve historical data for</param>
3661  /// <param name="start">The start time in the algorithm's time zone</param>
3662  /// <param name="end">The end time in the algorithm's time zone</param>
3663  /// <param name="resolution">The resolution to request</param>
3664  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
3665  /// <returns>pandas.DataFrame of historical data of a bar indicator</returns>
3666  public IndicatorHistory IndicatorHistory<T>(IndicatorBase<T> indicator, Symbol symbol, DateTime start, DateTime end, Resolution? resolution = null, Func<IBaseData, T> selector = null)
3667  where T : IBaseData
3668  {
3669  return IndicatorHistory(indicator, new[] { symbol }, start, end, resolution, selector);
3670  }
3671 
3672  /// <summary>
3673  /// Gets the historical data of a bar indicator for the specified symbols. The exact number of bars will be returned.
3674  /// The symbol must exist in the Securities collection.
3675  /// </summary>
3676  /// <param name="indicator">The target indicator</param>
3677  /// <param name="symbols">The symbols to retrieve historical data for</param>
3678  /// <param name="start">The start time in the algorithm's time zone</param>
3679  /// <param name="end">The end time in the algorithm's time zone</param>
3680  /// <param name="resolution">The resolution to request</param>
3681  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
3682  /// <returns>pandas.DataFrame of historical data of a bar indicator</returns>
3683  public IndicatorHistory IndicatorHistory<T>(IndicatorBase<T> indicator, IEnumerable<Symbol> symbols, DateTime start, DateTime end, Resolution? resolution = null, Func<IBaseData, T> selector = null)
3684  where T : IBaseData
3685  {
3686  var history = History(symbols, GetIndicatorAdjustedHistoryStart(indicator, symbols, start, end, resolution), end, resolution, dataNormalizationMode: GetIndicatorHistoryDataNormalizationMode(indicator));
3687  return IndicatorHistory(indicator, history, selector);
3688  }
3689 
3690  /// <summary>
3691  /// Gets the historical data of an indicator and convert it into pandas.DataFrame
3692  /// </summary>
3693  /// <param name="indicator">The target indicator</param>
3694  /// <param name="history">Historical data used to calculate the indicator</param>
3695  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
3696  /// <returns>pandas.DataFrame containing the historical data of <paramref name="indicator"/></returns>
3697  public IndicatorHistory IndicatorHistory(IndicatorBase<IndicatorDataPoint> indicator, IEnumerable<Slice> history, Func<IBaseData, decimal> selector = null)
3698  {
3699  selector ??= (x => x.Value);
3700  return IndicatorHistory(indicator, history, (bar) => indicator.Update(new IndicatorDataPoint(bar.Symbol, bar.EndTime, selector(bar))), GetDataTypeFromSelector(selector));
3701  }
3702 
3703  /// <summary>
3704  /// Gets the historical data of an bar indicator and convert it into pandas.DataFrame
3705  /// </summary>
3706  /// <param name="indicator">Bar indicator</param>
3707  /// <param name="history">Historical data used to calculate the indicator</param>
3708  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
3709  /// <returns>pandas.DataFrame containing the historical data of <paramref name="indicator"/></returns>
3710  public IndicatorHistory IndicatorHistory<T>(IndicatorBase<T> indicator, IEnumerable<Slice> history, Func<IBaseData, T> selector = null)
3711  where T : IBaseData
3712  {
3713  selector ??= (x => (T)x);
3714  return IndicatorHistory(indicator, history, (bar) => indicator.Update(selector(bar)));
3715  }
3716 
3717  /// <summary>
3718  /// Adds the provided consolidator and asserts the handler T type is assignable from the consolidator output,
3719  /// if not will throw <see cref="ArgumentException"/>
3720  /// </summary>
3721  private IDataConsolidator Consolidate<T>(Symbol symbol, Func<DateTime, CalendarInfo> calendar, TickType? tickType, Action<T> handler, TimeSpan? period, Resolution? resolution)
3722  where T : class, IBaseData
3723  {
3724  var consolidator = CreateConsolidator(symbol, calendar, tickType, period, resolution, typeof(T));
3725  if (handler != null)
3726  {
3727  // register user-defined handler to receive consolidated data events
3728  consolidator.DataConsolidated += (sender, consolidated) => handler((T)consolidated);
3729 
3730  // register the consolidator for automatic updates via SubscriptionManager
3731  RegisterConsolidator(symbol, consolidator, tickType, indicatorBase: null);
3732  }
3733  return consolidator;
3734  }
3735 
3736  private IDataConsolidator CreateConsolidator(Symbol symbol, Func<DateTime, CalendarInfo> calendar, TickType? tickType, TimeSpan? period, Resolution? resolution, Type consolidatorType)
3737  {
3738  // resolve consolidator input subscription
3739  var subscription = GetSubscription(symbol, tickType);
3740 
3741  // verify this consolidator will give reasonable results, if someone asks for second consolidation but we have minute
3742  // data we won't be able to do anything good, we'll call it second, but it would really just be minute!
3743  if (period.HasValue && period.Value < subscription.Increment || resolution.HasValue && resolution.Value < subscription.Resolution)
3744  {
3745  throw new ArgumentException($"Unable to create {symbol} consolidator because {symbol} is registered for " +
3746  Invariant($"{subscription.Resolution.ToStringInvariant()} data. Consolidators require higher resolution data to produce lower resolution data.")
3747  );
3748  }
3749 
3750  IDataConsolidator consolidator = null;
3751  if (calendar != null)
3752  {
3753  // create requested consolidator
3754  consolidator = CreateConsolidator(calendar, subscription.Type, subscription.TickType);
3755  }
3756  else
3757  {
3758  // if not specified, default to the subscription resolution
3759  if (!period.HasValue && !resolution.HasValue)
3760  {
3761  period = subscription.Increment;
3762  }
3763 
3764  if (period.HasValue && period.Value == subscription.Increment || resolution.HasValue && resolution.Value == subscription.Resolution)
3765  {
3766  consolidator = CreateIdentityConsolidator(subscription.Type);
3767  }
3768  else
3769  {
3770  if (resolution.HasValue)
3771  {
3772  if (resolution.Value == Resolution.Daily)
3773  {
3774  consolidator = new MarketHourAwareConsolidator(Settings.DailyPreciseEndTime, resolution.Value, subscription.Type, subscription.TickType, subscription.ExtendedMarketHours);
3775  }
3776  period = resolution.Value.ToTimeSpan();
3777  }
3778  consolidator ??= CreateConsolidator(period.Value, subscription.Type, subscription.TickType);
3779  }
3780  }
3781 
3782  if (consolidatorType != null && !consolidatorType.IsAssignableFrom(consolidator.OutputType))
3783  {
3784  throw new ArgumentException(
3785  $"Unable to consolidate with the specified handler because the consolidator's output type " +
3786  $"is {consolidator.OutputType.Name} but the handler's input type is {subscription.Type.Name}.");
3787  }
3788  return consolidator;
3789  }
3790 
3791  private IDataConsolidator CreateConsolidator(Func<DateTime, CalendarInfo> calendar, Type consolidatorInputType, TickType tickType)
3792  {
3793  // if our type can be used as a trade bar, then let's just make one of those
3794  // we use IsAssignableFrom instead of IsSubclassOf so that we can account for types that are able to be cast to TradeBar
3795  if (typeof(TradeBar).IsAssignableFrom(consolidatorInputType))
3796  {
3797  return new TradeBarConsolidator(calendar);
3798  }
3799 
3800  // if our type can be used as a quote bar, then let's just make one of those
3801  // we use IsAssignableFrom instead of IsSubclassOf so that we can account for types that are able to be cast to QuoteBar
3802  if (typeof(QuoteBar).IsAssignableFrom(consolidatorInputType))
3803  {
3804  return new QuoteBarConsolidator(calendar);
3805  }
3806 
3807  // if our type can be used as a tick then we'll use a consolidator that keeps the TickType
3808  // we use IsAssignableFrom instead of IsSubclassOf so that we can account for types that are able to be cast to Tick
3809  if (typeof(Tick).IsAssignableFrom(consolidatorInputType))
3810  {
3811  if (tickType == TickType.Quote)
3812  {
3813  return new TickQuoteBarConsolidator(calendar);
3814  }
3815  return new TickConsolidator(calendar);
3816  }
3817 
3818  // if our type can be used as a DynamicData then we'll use the DynamicDataConsolidator
3819  if (typeof(DynamicData).IsAssignableFrom(consolidatorInputType))
3820  {
3821  return new DynamicDataConsolidator(calendar);
3822  }
3823 
3824  // no matter what we can always consolidate based on the time-value pair of BaseData
3825  return new BaseDataConsolidator(calendar);
3826  }
3827 
3828  /// <summary>
3829  /// Creates a new consolidator identity consolidator for the requested output type.
3830  /// </summary>
3831  private static IDataConsolidator CreateIdentityConsolidator(Type consolidatorInputType)
3832  {
3833  if (typeof(TradeBar).IsAssignableFrom(consolidatorInputType))
3834  {
3836  }
3837  else if (typeof(QuoteBar).IsAssignableFrom(consolidatorInputType))
3838  {
3840  }
3841  else if (typeof(Tick).IsAssignableFrom(consolidatorInputType))
3842  {
3843  return new IdentityDataConsolidator<Tick>();
3844  }
3845  else if (typeof(DynamicData).IsAssignableFrom(consolidatorInputType))
3846  {
3847  return new DynamicDataConsolidator(1);
3848  }
3850  }
3851 
3852  /// <summary>
3853  /// Registers and warms up (if EnableAutomaticIndicatorWarmUp is set) the indicator
3854  /// </summary>
3855  private void InitializeIndicator(IndicatorBase<IndicatorDataPoint> indicator, Resolution? resolution = null,
3856  Func<IBaseData, decimal> selector = null, params Symbol[] symbols)
3857  {
3858  var dataType = GetDataTypeFromSelector(selector);
3859  foreach (var symbol in symbols)
3860  {
3861  RegisterIndicator(symbol, indicator, ResolveConsolidator(symbol, resolution, dataType), selector);
3862  }
3863 
3865  {
3866  WarmUpIndicator(symbols, indicator, resolution, selector);
3867  }
3868  }
3869 
3870  private void InitializeIndicator<T>(IndicatorBase<T> indicator, Resolution? resolution = null,
3871  Func<IBaseData, T> selector = null, params Symbol[] symbols)
3872  where T : class, IBaseData
3873  {
3874  foreach (var symbol in symbols)
3875  {
3876  RegisterIndicator(symbol, indicator, resolution, selector);
3877  }
3878 
3880  {
3881  WarmUpIndicator(symbols, indicator, resolution, selector);
3882  }
3883  }
3884 
3885  private void InitializeOptionIndicator(IndicatorBase<IndicatorDataPoint> indicator, Resolution? resolution, Symbol symbol, Symbol mirrorOption)
3886  {
3887  RegisterIndicator(symbol, indicator, ResolveConsolidator(symbol, resolution, typeof(QuoteBar)));
3888  RegisterIndicator(symbol.Underlying, indicator, ResolveConsolidator(symbol.Underlying, resolution));
3889  var symbols = new List<Symbol> { symbol, symbol.Underlying };
3890  if (mirrorOption != null)
3891  {
3892  RegisterIndicator(mirrorOption, indicator, ResolveConsolidator(mirrorOption, resolution, typeof(QuoteBar)));
3893  symbols.Add(mirrorOption);
3894  }
3895 
3897  {
3898  WarmUpIndicator(symbols, indicator, resolution);
3899  }
3900  }
3901 
3902  private string InitializeOptionIndicator<T>(Symbol symbol, out IRiskFreeInterestRateModel riskFreeRateModel, out IDividendYieldModel dividendYieldModel,
3903  decimal? riskFreeRate = null, decimal? dividendYield = null, OptionPricingModelType? optionModel = null, Resolution? resolution = null)
3904  where T : OptionIndicatorBase
3905  {
3906  var name = CreateIndicatorName(symbol,
3907  $"{typeof(T).Name}({riskFreeRate},{dividendYield},{OptionIndicatorBase.GetOptionModel(optionModel, symbol.ID.OptionStyle)})",
3908  resolution);
3909 
3910  riskFreeRateModel = riskFreeRate.HasValue
3911  ? new ConstantRiskFreeRateInterestRateModel(riskFreeRate.Value)
3912  // Make it a function so it's lazily evaluated: SetRiskFreeInterestRateModel can be called after this method
3913  : new FuncRiskFreeRateInterestRateModel((datetime) => RiskFreeInterestRateModel.GetInterestRate(datetime));
3914 
3915  if (dividendYield.HasValue)
3916  {
3917  dividendYieldModel = new ConstantDividendYieldModel(dividendYield.Value);
3918  }
3919  else
3920  {
3921  dividendYieldModel = DividendYieldProvider.CreateForOption(symbol);
3922  }
3923 
3924  return name;
3925  }
3926 
3927  private void RegisterConsolidator(Symbol symbol, IDataConsolidator consolidator, TickType? tickType, IndicatorBase indicatorBase)
3928  {
3929  // keep a reference of the consolidator so we can unregister it later using only a reference to the indicator
3930  indicatorBase?.Consolidators.Add(consolidator);
3931 
3932  // register the consolidator for automatic updates via SubscriptionManager
3933  SubscriptionManager.AddConsolidator(symbol, consolidator, tickType);
3934  }
3935 
3936  private DateTime GetIndicatorAdjustedHistoryStart(IndicatorBase indicator, IEnumerable<Symbol> symbols, DateTime start, DateTime end, Resolution? resolution = null)
3937  {
3938  var warmupPeriod = (indicator as IIndicatorWarmUpPeriodProvider)?.WarmUpPeriod ?? 0;
3939  if (warmupPeriod != 0)
3940  {
3941  warmupPeriod -= 1;
3942  if (warmupPeriod > 0)
3943  {
3944  foreach (var request in CreateDateRangeHistoryRequests(symbols, start, end, resolution))
3945  {
3946  var adjustedStart = _historyRequestFactory.GetStartTimeAlgoTz(request.StartTimeUtc, request.Symbol, warmupPeriod, request.Resolution,
3947  request.ExchangeHours, request.DataTimeZone, request.DataType, request.IncludeExtendedMarketHours);
3948  if (adjustedStart < start)
3949  {
3950  start = adjustedStart;
3951  }
3952  }
3953  }
3954  }
3955  return start;
3956  }
3957 
3958  private DataNormalizationMode? GetIndicatorHistoryDataNormalizationMode(IIndicator indicator)
3959  {
3960  DataNormalizationMode? dataNormalizationMode = null;
3961  if (indicator is OptionIndicatorBase optionIndicator && optionIndicator.OptionSymbol.Underlying.SecurityType == SecurityType.Equity)
3962  {
3963  // we use point in time raw data to warmup option indicators which use underlying prices and strikes
3964  dataNormalizationMode = DataNormalizationMode.ScaledRaw;
3965  }
3966  return dataNormalizationMode;
3967  }
3968 
3969  private IndicatorHistory IndicatorHistory<T>(IndicatorBase<T> indicator, IEnumerable<Slice> history, Action<IBaseData> updateIndicator, Type dataType = null)
3970  where T : IBaseData
3971  {
3972  // Reset the indicator
3973  indicator.Reset();
3974 
3975  var indicatorType = indicator.GetType();
3976  // Create a dictionary of the indicator properties & the indicator value itself
3977  var indicatorsDataPointPerProperty = indicatorType.GetProperties()
3978  .Where(x => x.PropertyType.IsGenericType && x.Name != "Consolidators" && x.Name != "Window")
3979  .Select(x => InternalIndicatorValues.Create(indicator, x))
3980  .Concat(new[] { InternalIndicatorValues.Create(indicator, "Current") })
3981  .ToList();
3982 
3983  var indicatorsDataPointsByTime = new List<IndicatorDataPoints>();
3984  var lastConsumedTime = DateTime.MinValue;
3985  IndicatorDataPoint lastPoint = null;
3986  void consumeLastPoint(IndicatorDataPoint newInputPoint)
3987  {
3988  if (newInputPoint == null || lastConsumedTime == newInputPoint.EndTime)
3989  {
3990  return;
3991  }
3992  lastConsumedTime = newInputPoint.EndTime;
3993 
3994  var IndicatorDataPoints = new IndicatorDataPoints { Time = newInputPoint.Time, EndTime = newInputPoint.EndTime };
3995  indicatorsDataPointsByTime.Add(IndicatorDataPoints);
3996  for (var i = 0; i < indicatorsDataPointPerProperty.Count; i++)
3997  {
3998  var newPoint = indicatorsDataPointPerProperty[i].UpdateValue();
3999  IndicatorDataPoints.SetProperty(indicatorsDataPointPerProperty[i].Name, newPoint);
4000  }
4001  }
4002 
4003  IndicatorUpdatedHandler callback = (object _, IndicatorDataPoint newInputPoint) =>
4004  {
4005  if (!indicator.IsReady)
4006  {
4007  return;
4008  }
4009 
4010  if (lastPoint == null || lastPoint.Time != newInputPoint.Time)
4011  {
4012  // if null, it's the first point, we transitions from not ready to ready
4013  // else when the time changes we fetch the indicators values, some indicators which consume data from multiple symbols might trigger the Updated event
4014  // even if their value has not changed yet
4015  consumeLastPoint(newInputPoint);
4016  }
4017  lastPoint = newInputPoint;
4018  };
4019 
4020  // register the callback, update the indicator and unregister finally
4021  indicator.Updated += callback;
4022 
4023  if (typeof(T) == typeof(IndicatorDataPoint) || typeof(T).IsAbstract)
4024  {
4025  history.PushThrough(bar => updateIndicator(bar), dataType);
4026  }
4027  else
4028  {
4029  // if the indicator requires a specific type, like a QuoteBar for an equity symbol, we need to fetch it directly
4030  foreach (var dataDictionary in history.Get<T>())
4031  {
4032  foreach (var dataPoint in dataDictionary.Values)
4033  {
4034  updateIndicator(dataPoint);
4035  }
4036  }
4037  }
4038  // flush the last point, this will be useful for indicator consuming time from multiple symbols
4039  consumeLastPoint(lastPoint);
4040  indicator.Updated -= callback;
4041 
4042  return new IndicatorHistory(indicatorsDataPointsByTime, indicatorsDataPointPerProperty,
4043  new Lazy<PyObject>(
4044  () => PandasConverter.GetIndicatorDataFrame(indicatorsDataPointPerProperty.Select(x => new KeyValuePair<string, List<IndicatorDataPoint>>(x.Name, x.Values))),
4045  isThreadSafe: false));
4046  }
4047 
4048  private Type GetDataTypeFromSelector(Func<IBaseData, decimal> selector)
4049  {
4050  Type dataType = null;
4051  if (_quoteRequiredFields.Any(x => ReferenceEquals(selector, x)))
4052  {
4053  dataType = typeof(QuoteBar);
4054  }
4055  else if (ReferenceEquals(selector, Field.Volume))
4056  {
4057  dataType = typeof(TradeBar);
4058  }
4059 
4060  return dataType;
4061  }
4062  }
4063 }