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