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 ZigZag indicator for the specified symbol, with adjustable sensitivity and minimum trend length.
2816  /// </summary>
2817  /// <param name="symbol">The symbol for which to create the ZigZag indicator.</param>
2818  /// <param name="sensitivity">The sensitivity for detecting pivots.</param>
2819  /// <param name="minTrendLength">The minimum number of bars required for a trend before a pivot is confirmed.</param>
2820  /// <param name="resolution">The resolution</param>
2821  /// <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>
2822  /// <returns>The configured ZigZag indicator.</returns>
2823  [DocumentationAttribute(Indicators)]
2824  public ZigZag ZZ(Symbol symbol, decimal sensitivity = 0.05m, int minTrendLength = 1, Resolution? resolution = null, Func<IBaseData, IBaseDataBar> selector = null)
2825  {
2826  var name = CreateIndicatorName(symbol, $"ZZ({sensitivity},{minTrendLength})", resolution);
2827  var zigZag = new ZigZag(name, sensitivity, minTrendLength);
2828  InitializeIndicator(zigZag, resolution, selector, symbol);
2829  return zigZag;
2830  }
2831 
2832  /// <summary>
2833  /// Creates a new name for an indicator created with the convenience functions (SMA, EMA, ect...)
2834  /// </summary>
2835  /// <param name="symbol">The symbol this indicator is registered to</param>
2836  /// <param name="type">The indicator type, for example, 'SMA(5)'</param>
2837  /// <param name="resolution">The resolution requested</param>
2838  /// <returns>A unique for the given parameters</returns>
2839  [DocumentationAttribute(Indicators)]
2840  public string CreateIndicatorName(Symbol symbol, FormattableString type, Resolution? resolution)
2841  {
2842  return CreateIndicatorName(symbol, Invariant(type), resolution);
2843  }
2844 
2845  /// <summary>
2846  /// Creates a new name for an indicator created with the convenience functions (SMA, EMA, ect...)
2847  /// </summary>
2848  /// <param name="symbol">The symbol this indicator is registered to</param>
2849  /// <param name="type">The indicator type, for example, 'SMA(5)'</param>
2850  /// <param name="resolution">The resolution requested</param>
2851  /// <returns>A unique for the given parameters</returns>
2852  [DocumentationAttribute(Indicators)]
2853  public string CreateIndicatorName(Symbol symbol, string type, Resolution? resolution)
2854  {
2855  var symbolIsNotEmpty = symbol != QuantConnect.Symbol.None && symbol != QuantConnect.Symbol.Empty;
2856 
2857  if (!resolution.HasValue && symbolIsNotEmpty)
2858  {
2859  resolution = GetSubscription(symbol).Resolution;
2860  }
2861 
2862  var res = string.Empty;
2863  switch (resolution)
2864  {
2865  case Resolution.Tick:
2866  res = "tick";
2867  break;
2868 
2869  case Resolution.Second:
2870  res = "sec";
2871  break;
2872 
2873  case Resolution.Minute:
2874  res = "min";
2875  break;
2876 
2877  case Resolution.Hour:
2878  res = "hr";
2879  break;
2880 
2881  case Resolution.Daily:
2882  res = "day";
2883  break;
2884 
2885  case null:
2886  break;
2887 
2888  default:
2889  throw new ArgumentOutOfRangeException(nameof(resolution), resolution, "resolution parameter is out of range.");
2890  }
2891 
2892  var parts = new List<string>();
2893 
2894  if (symbolIsNotEmpty)
2895  {
2896  parts.Add(symbol.ToString());
2897  }
2898  parts.Add(res);
2899 
2900  return Invariant($"{type}({string.Join("_", parts)})").Replace(")(", ",");
2901  }
2902 
2903  /// <summary>
2904  /// Gets the SubscriptionDataConfig for the specified symbol and tick type
2905  /// </summary>
2906  /// <exception cref="InvalidOperationException">Thrown if no configuration is found for the requested symbol</exception>
2907  /// <param name="symbol">The symbol to retrieve configuration for</param>
2908  /// <param name="tickType">The tick type of the subscription to get. If null, will use the first ordered by TickType</param>
2909  /// <returns>The SubscriptionDataConfig for the specified symbol</returns>
2910  private SubscriptionDataConfig GetSubscription(Symbol symbol, TickType? tickType = null)
2911  {
2912  SubscriptionDataConfig subscription;
2913  try
2914  {
2915  // deterministic ordering is required here
2918  // make sure common lean data types are at the bottom
2919  .OrderByDescending(x => LeanData.IsCommonLeanDataType(x.Type))
2920  .ThenBy(x => x.TickType)
2921  .ToList();
2922 
2923  // find our subscription
2924  subscription = subscriptions.FirstOrDefault(x => tickType == null || tickType == x.TickType);
2925  if (subscription == null)
2926  {
2927  // if we can't locate the exact subscription by tick type just grab the first one we find
2928  subscription = subscriptions.First();
2929  }
2930  }
2931  catch (InvalidOperationException)
2932  {
2933  // this will happen if we did not find the subscription, let's give the user a decent error message
2934  throw new Exception($"Please register to receive data for symbol \'{symbol}\' using the AddSecurity() function.");
2935  }
2936  return subscription;
2937  }
2938 
2939  /// <summary>
2940  /// Creates and registers a new consolidator to receive automatic updates at the specified resolution as well as configures
2941  /// the indicator to receive updates from the consolidator.
2942  /// </summary>
2943  /// <param name="symbol">The symbol to register against</param>
2944  /// <param name="indicator">The indicator to receive data from the consolidator</param>
2945  /// <param name="resolution">The resolution at which to send data to the indicator, null to use the same resolution as the subscription</param>
2946  /// <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>
2947  [DocumentationAttribute(ConsolidatingData)]
2948  [DocumentationAttribute(Indicators)]
2949  public void RegisterIndicator(Symbol symbol, IndicatorBase<IndicatorDataPoint> indicator, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
2950  {
2951  RegisterIndicator(symbol, indicator, ResolveConsolidator(symbol, resolution), selector ?? (x => x.Value));
2952  }
2953 
2954  /// <summary>
2955  /// Creates and registers a new consolidator to receive automatic updates at the specified resolution as well as configures
2956  /// the indicator to receive updates from the consolidator.
2957  /// </summary>
2958  /// <param name="symbol">The symbol to register against</param>
2959  /// <param name="indicator">The indicator to receive data from the consolidator</param>
2960  /// <param name="resolution">The resolution at which to send data to the indicator, null to use the same resolution as the subscription</param>
2961  /// <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>
2962  [DocumentationAttribute(ConsolidatingData)]
2963  [DocumentationAttribute(Indicators)]
2964  public void RegisterIndicator(Symbol symbol, IndicatorBase<IndicatorDataPoint> indicator, TimeSpan? resolution = null, Func<IBaseData, decimal> selector = null)
2965  {
2966  RegisterIndicator(symbol, indicator, ResolveConsolidator(symbol, resolution), selector ?? (x => x.Value));
2967  }
2968 
2969  /// <summary>
2970  /// Registers the consolidator to receive automatic updates as well as configures the indicator to receive updates
2971  /// from the consolidator.
2972  /// </summary>
2973  /// <param name="symbol">The symbol to register against</param>
2974  /// <param name="indicator">The indicator to receive data from the consolidator</param>
2975  /// <param name="consolidator">The consolidator to receive raw subscription data</param>
2976  /// <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>
2977  [DocumentationAttribute(ConsolidatingData)]
2978  [DocumentationAttribute(Indicators)]
2979  public void RegisterIndicator(Symbol symbol, IndicatorBase<IndicatorDataPoint> indicator, IDataConsolidator consolidator, Func<IBaseData, decimal> selector = null)
2980  {
2981  // default our selector to the Value property on BaseData
2982  selector = selector ?? (x => x.Value);
2983 
2984  RegisterConsolidator(symbol, consolidator, null, indicator);
2985 
2986  // attach to the DataConsolidated event so it updates our indicator
2987  consolidator.DataConsolidated += (sender, consolidated) =>
2988  {
2989  var value = selector(consolidated);
2990  indicator.Update(new IndicatorDataPoint(consolidated.Symbol, consolidated.EndTime, value));
2991  };
2992  }
2993 
2994  /// <summary>
2995  /// Registers the consolidator to receive automatic updates as well as configures the indicator to receive updates
2996  /// from the consolidator.
2997  /// </summary>
2998  /// <param name="symbol">The symbol to register against</param>
2999  /// <param name="indicator">The indicator to receive data from the consolidator</param>
3000  /// <param name="resolution">The resolution at which to send data to the indicator, null to use the same resolution as the subscription</param>
3001  [DocumentationAttribute(ConsolidatingData)]
3002  [DocumentationAttribute(Indicators)]
3003  public void RegisterIndicator<T>(Symbol symbol, IndicatorBase<T> indicator, Resolution? resolution = null)
3004  where T : IBaseData
3005  {
3006  RegisterIndicator(symbol, indicator, ResolveConsolidator(symbol, resolution, typeof(T)));
3007  }
3008 
3009  /// <summary>
3010  /// Registers the consolidator to receive automatic updates as well as configures the indicator to receive updates
3011  /// from the consolidator.
3012  /// </summary>
3013  /// <param name="symbol">The symbol to register against</param>
3014  /// <param name="indicator">The indicator to receive data from the consolidator</param>
3015  /// <param name="resolution">The resolution at which to send data to the indicator, null to use the same resolution as the subscription</param>
3016  /// <param name="selector">Selects a value from the BaseData send into the indicator, if null defaults to a cast (x => (T)x)</param>
3017  [DocumentationAttribute(ConsolidatingData)]
3018  [DocumentationAttribute(Indicators)]
3019  public void RegisterIndicator<T>(Symbol symbol, IndicatorBase<T> indicator, Resolution? resolution, Func<IBaseData, T> selector)
3020  where T : IBaseData
3021  {
3022  RegisterIndicator(symbol, indicator, ResolveConsolidator(symbol, resolution, typeof(T)), selector);
3023  }
3024 
3025  /// <summary>
3026  /// Registers the consolidator to receive automatic updates as well as configures the indicator to receive updates
3027  /// from the consolidator.
3028  /// </summary>
3029  /// <param name="symbol">The symbol to register against</param>
3030  /// <param name="indicator">The indicator to receive data from the consolidator</param>
3031  /// <param name="resolution">The resolution at which to send data to the indicator, null to use the same resolution as the subscription</param>
3032  /// <param name="selector">Selects a value from the BaseData send into the indicator, if null defaults to a cast (x => (T)x)</param>
3033  [DocumentationAttribute(ConsolidatingData)]
3034  [DocumentationAttribute(Indicators)]
3035  public void RegisterIndicator<T>(Symbol symbol, IndicatorBase<T> indicator, TimeSpan? resolution, Func<IBaseData, T> selector = null)
3036  where T : IBaseData
3037  {
3038  RegisterIndicator(symbol, indicator, ResolveConsolidator(symbol, resolution, typeof(T)), selector);
3039  }
3040 
3041  /// <summary>
3042  /// Registers the consolidator to receive automatic updates as well as configures the indicator to receive updates
3043  /// from the consolidator.
3044  /// </summary>
3045  /// <param name="symbol">The symbol to register against</param>
3046  /// <param name="indicator">The indicator to receive data from the consolidator</param>
3047  /// <param name="consolidator">The consolidator to receive raw subscription data</param>
3048  /// <param name="selector">Selects a value from the BaseData send into the indicator, if null defaults to a cast (x => (T)x)</param>
3049  [DocumentationAttribute(ConsolidatingData)]
3050  [DocumentationAttribute(Indicators)]
3051  public void RegisterIndicator<T>(Symbol symbol, IndicatorBase<T> indicator, IDataConsolidator consolidator, Func<IBaseData, T> selector = null)
3052  where T : IBaseData
3053  {
3054  // assign default using cast
3055  var selectorToUse = selector ?? (x => (T)x);
3056 
3057  RegisterConsolidator(symbol, consolidator, null, indicator);
3058 
3059  // check the output type of the consolidator and verify we can assign it to T
3060  var type = typeof(T);
3061  if (!type.IsAssignableFrom(consolidator.OutputType))
3062  {
3063  if (type == typeof(IndicatorDataPoint) && selector == null)
3064  {
3065  // if no selector was provided and the indicator input is of 'IndicatorDataPoint', common case, a selector with a direct cast will fail
3066  // so we use a smarter selector as in other API methods
3067  selectorToUse = consolidated => (T)(object)new IndicatorDataPoint(consolidated.Symbol, consolidated.EndTime, consolidated.Value);
3068  }
3069  else
3070  {
3071  throw new ArgumentException($"Type mismatch found between consolidator and indicator for symbol: {symbol}." +
3072  $"Consolidator outputs type {consolidator.OutputType.Name} but indicator expects input type {type.Name}"
3073  );
3074  }
3075  }
3076 
3077  // attach to the DataConsolidated event so it updates our indicator
3078  consolidator.DataConsolidated += (sender, consolidated) =>
3079  {
3080  var value = selectorToUse(consolidated);
3081  indicator.Update(value);
3082  };
3083  }
3084 
3085  /// <summary>
3086  /// Will unregister an indicator and it's associated consolidator instance so they stop receiving data updates
3087  /// </summary>
3088  /// <param name="indicator">The indicator instance to unregister</param>
3089  [DocumentationAttribute(ConsolidatingData)]
3090  [DocumentationAttribute(Indicators)]
3091  public void UnregisterIndicator(IndicatorBase indicator)
3092  {
3093  DeregisterIndicator(indicator);
3094  }
3095 
3096  /// <summary>
3097  /// Will deregister an indicator and it's associated consolidator instance so they stop receiving data updates
3098  /// </summary>
3099  /// <param name="indicator">The indicator instance to deregister</param>
3100  [DocumentationAttribute(ConsolidatingData)]
3101  [DocumentationAttribute(Indicators)]
3102  public void DeregisterIndicator(IndicatorBase indicator)
3103  {
3104  foreach (var consolidator in indicator.Consolidators)
3105  {
3106  SubscriptionManager.RemoveConsolidator(null, consolidator);
3107  }
3108 
3109  indicator.Consolidators.Clear();
3110  }
3111 
3112  /// <summary>
3113  /// Warms up a given indicator with historical data
3114  /// </summary>
3115  /// <param name="symbol">The symbol whose indicator we want</param>
3116  /// <param name="indicator">The indicator we want to warm up</param>
3117  /// <param name="resolution">The resolution</param>
3118  /// <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>
3119  [DocumentationAttribute(HistoricalData)]
3120  [DocumentationAttribute(Indicators)]
3121  public void WarmUpIndicator(Symbol symbol, IndicatorBase<IndicatorDataPoint> indicator, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
3122  {
3123  WarmUpIndicator(new[] { symbol }, indicator, resolution, selector);
3124  }
3125 
3126  /// <summary>
3127  /// Warms up a given indicator with historical data
3128  /// </summary>
3129  /// <param name="symbols">The symbols whose indicator we want</param>
3130  /// <param name="indicator">The indicator we want to warm up</param>
3131  /// <param name="resolution">The resolution</param>
3132  /// <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>
3133  [DocumentationAttribute(HistoricalData)]
3134  [DocumentationAttribute(Indicators)]
3135  public void WarmUpIndicator(IEnumerable<Symbol> symbols, IndicatorBase<IndicatorDataPoint> indicator, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
3136  {
3137  if (AssertIndicatorHasWarmupPeriod(indicator))
3138  {
3139  IndicatorHistory(indicator, symbols, 0, resolution, selector);
3140  }
3141  }
3142 
3143  /// <summary>
3144  /// Warms up a given indicator with historical data
3145  /// </summary>
3146  /// <param name="symbol">The symbol whose indicator we want</param>
3147  /// <param name="indicator">The indicator we want to warm up</param>
3148  /// <param name="period">The necessary period to warm up the indicator</param>
3149  /// <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>
3150  [DocumentationAttribute(HistoricalData)]
3151  [DocumentationAttribute(Indicators)]
3152  public void WarmUpIndicator(Symbol symbol, IndicatorBase<IndicatorDataPoint> indicator, TimeSpan period, Func<IBaseData, decimal> selector = null)
3153  {
3154  var history = GetIndicatorWarmUpHistory(new[] { symbol }, indicator, period, out var identityConsolidator);
3155  if (history == Enumerable.Empty<Slice>()) return;
3156 
3157  // assign default using cast
3158  selector ??= (x => x.Value);
3159 
3160  Action<IBaseData> onDataConsolidated = bar =>
3161  {
3162  var input = new IndicatorDataPoint(bar.Symbol, bar.EndTime, selector(bar));
3163  indicator.Update(input);
3164  };
3165 
3166  WarmUpIndicatorImpl(symbol, period, onDataConsolidated, history, identityConsolidator);
3167  }
3168 
3169  /// <summary>
3170  /// Warms up a given indicator with historical data
3171  /// </summary>
3172  /// <param name="symbol">The symbol whose indicator we want</param>
3173  /// <param name="indicator">The indicator we want to warm up</param>
3174  /// <param name="resolution">The resolution</param>
3175  /// <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>
3176  [DocumentationAttribute(HistoricalData)]
3177  [DocumentationAttribute(Indicators)]
3178  public void WarmUpIndicator<T>(Symbol symbol, IndicatorBase<T> indicator, Resolution? resolution = null, Func<IBaseData, T> selector = null)
3179  where T : class, IBaseData
3180  {
3181  WarmUpIndicator(new[] { symbol }, indicator, resolution, selector);
3182  }
3183 
3184  /// <summary>
3185  /// Warms up a given indicator with historical data
3186  /// </summary>
3187  /// <param name="symbols">The symbols whose indicator we want</param>
3188  /// <param name="indicator">The indicator we want to warm up</param>
3189  /// <param name="resolution">The resolution</param>
3190  /// <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>
3191  [DocumentationAttribute(HistoricalData)]
3192  [DocumentationAttribute(Indicators)]
3193  public void WarmUpIndicator<T>(IEnumerable<Symbol> symbols, IndicatorBase<T> indicator, Resolution? resolution = null, Func<IBaseData, T> selector = null)
3194  where T : class, IBaseData
3195  {
3196  if (AssertIndicatorHasWarmupPeriod(indicator))
3197  {
3198  IndicatorHistory(indicator, symbols, 0, resolution, selector);
3199  }
3200  }
3201 
3202  /// <summary>
3203  /// Warms up a given indicator with historical data
3204  /// </summary>
3205  /// <param name="symbol">The symbol whose indicator we want</param>
3206  /// <param name="indicator">The indicator we want to warm up</param>
3207  /// <param name="period">The necessary period to warm up the indicator</param>
3208  /// <param name="selector">Selects a value from the BaseData send into the indicator, if null defaults to a cast (x => (T)x)</param>
3209  [DocumentationAttribute(HistoricalData)]
3210  [DocumentationAttribute(Indicators)]
3211  public void WarmUpIndicator<T>(Symbol symbol, IndicatorBase<T> indicator, TimeSpan period, Func<IBaseData, T> selector = null)
3212  where T : class, IBaseData
3213  {
3214  var history = GetIndicatorWarmUpHistory(new[] { symbol }, indicator, period, out var identityConsolidator);
3215  if (history == Enumerable.Empty<Slice>()) return;
3216 
3217  // assign default using cast
3218  selector ??= (x => (T)x);
3219 
3220  // we expect T type as input
3221  Action<T> onDataConsolidated = bar =>
3222  {
3223  indicator.Update(selector(bar));
3224  };
3225 
3226  WarmUpIndicatorImpl(symbol, period, onDataConsolidated, history, identityConsolidator);
3227  }
3228 
3229  private IEnumerable<Slice> GetIndicatorWarmUpHistory(IEnumerable<Symbol> symbols, IIndicator indicator, TimeSpan timeSpan, out bool identityConsolidator)
3230  {
3231  identityConsolidator = false;
3232  if (!AssertIndicatorHasWarmupPeriod(indicator))
3233  {
3234  return Enumerable.Empty<Slice>();
3235  }
3236 
3237  var periods = ((IIndicatorWarmUpPeriodProvider)indicator).WarmUpPeriod;
3238  if (periods != 0)
3239  {
3240  var resolution = timeSpan.ToHigherResolutionEquivalent(false);
3241  // if they are the same, means we can use an identity consolidator
3242  identityConsolidator = resolution.ToTimeSpan() == timeSpan;
3243  var resolutionTicks = resolution.ToTimeSpan().Ticks;
3244  if (resolutionTicks != 0)
3245  {
3246  periods *= (int)(timeSpan.Ticks / resolutionTicks);
3247  }
3248 
3249  try
3250  {
3251  return History(symbols, periods, resolution, dataNormalizationMode: GetIndicatorHistoryDataNormalizationMode(indicator));
3252  }
3253  catch (ArgumentException e)
3254  {
3255  Debug($"{indicator.Name} could not be warmed up. Reason: {e.Message}");
3256  }
3257  }
3258  return Enumerable.Empty<Slice>();
3259  }
3260 
3261  private bool AssertIndicatorHasWarmupPeriod(IIndicator indicator)
3262  {
3263  if (indicator is not IIndicatorWarmUpPeriodProvider)
3264  {
3265  if (!_isEmitWarmupInsightWarningSent)
3266  {
3267  Debug($"Warning: the 'WarmUpIndicator' feature only works with indicators which inherit from '{nameof(IIndicatorWarmUpPeriodProvider)}'" +
3268  $" and define a warm up period, setting property 'WarmUpPeriod' with a value > 0." +
3269  $" The provided indicator of type '{indicator.GetType().Name}' will not be warmed up.");
3270  _isEmitWarmupInsightWarningSent = true;
3271  }
3272  return false;
3273  }
3274  return true;
3275  }
3276 
3277  private void WarmUpIndicatorImpl<T>(Symbol symbol, TimeSpan period, Action<T> handler, IEnumerable<Slice> history, bool identityConsolidator)
3278  where T : class, IBaseData
3279  {
3280  IDataConsolidator consolidator;
3282  {
3283  consolidator = Consolidate(symbol, period, handler);
3284  }
3285  else
3286  {
3287  if (identityConsolidator)
3288  {
3289  period = TimeSpan.Zero;
3290  }
3291 
3292  var providedType = typeof(T);
3293  if (providedType.IsAbstract)
3294  {
3296  symbol.SecurityType,
3297  Resolution.Daily,
3298  // order by tick type so that behavior is consistent with 'GetSubscription()'
3299  symbol.IsCanonical())
3300  // make sure common lean data types are at the bottom
3301  .OrderByDescending(tuple => LeanData.IsCommonLeanDataType(tuple.Item1))
3302  .ThenBy(tuple => tuple.Item2).First();
3303 
3304  consolidator = CreateConsolidator(period, dataType.Item1, dataType.Item2);
3305  }
3306  else
3307  {
3308  // if the 'providedType' is not abstract we use it instead to determine which consolidator to use
3309  var tickType = LeanData.GetCommonTickTypeForCommonDataTypes(providedType, symbol.SecurityType);
3310  consolidator = CreateConsolidator(period, providedType, tickType);
3311  }
3312  consolidator.DataConsolidated += (s, bar) => handler((T)bar);
3313  }
3314 
3315  var consolidatorInputType = consolidator.InputType;
3316  IBaseData lastBar = null;
3317  foreach (var slice in history)
3318  {
3319  if (slice.TryGet(consolidatorInputType, symbol, out var data))
3320  {
3321  lastBar = data;
3322  consolidator.Update(lastBar);
3323  }
3324  }
3325 
3326  // Scan for time after we've pumped all the data through for this consolidator
3327  if (lastBar != null)
3328  {
3329  DateTime currentTime;
3330  if (Securities.TryGetValue(symbol, out var security))
3331  {
3332  currentTime = security.LocalTime;
3333  }
3334  else
3335  {
3336  var exchangeHours = MarketHoursDatabase.GetExchangeHours(symbol.ID.Market, symbol, symbol.SecurityType);
3337  currentTime = UtcTime.ConvertFromUtc(exchangeHours.TimeZone);
3338  }
3339 
3340  consolidator.Scan(currentTime);
3341  }
3342 
3343  SubscriptionManager.RemoveConsolidator(symbol, consolidator);
3344  }
3345 
3346  /// <summary>
3347  /// Gets the default consolidator for the specified symbol and resolution
3348  /// </summary>
3349  /// <param name="symbol">The symbol whose data is to be consolidated</param>
3350  /// <param name="resolution">The resolution for the consolidator, if null, uses the resolution from subscription</param>
3351  /// <param name="dataType">The data type for this consolidator, if null, uses TradeBar over QuoteBar if present</param>
3352  /// <returns>The new default consolidator</returns>
3353  [DocumentationAttribute(ConsolidatingData)]
3354  [DocumentationAttribute(Indicators)]
3355  public IDataConsolidator ResolveConsolidator(Symbol symbol, Resolution? resolution, Type dataType = null)
3356  {
3357  var tickType = dataType != null ? LeanData.GetCommonTickTypeForCommonDataTypes(dataType, symbol.SecurityType) : (TickType?)null;
3358  return CreateConsolidator(symbol, null, tickType, null, resolution, null);
3359  }
3360 
3361  /// <summary>
3362  /// Gets the default consolidator for the specified symbol and resolution
3363  /// </summary>
3364  /// <param name="symbol">The symbol whose data is to be consolidated</param>
3365  /// <param name="timeSpan">The requested time span for the consolidator, if null, uses the resolution from subscription</param>
3366  /// <param name="dataType">The data type for this consolidator, if null, uses TradeBar over QuoteBar if present</param>
3367  /// <returns>The new default consolidator</returns>
3368  [DocumentationAttribute(ConsolidatingData)]
3369  [DocumentationAttribute(Indicators)]
3370  public IDataConsolidator ResolveConsolidator(Symbol symbol, TimeSpan? timeSpan, Type dataType = null)
3371  {
3372  var tickType = dataType != null ? LeanData.GetCommonTickTypeForCommonDataTypes(dataType, symbol.SecurityType) : (TickType?)null;
3373  return CreateConsolidator(symbol, null, tickType, timeSpan, null, null);
3374  }
3375 
3376  /// <summary>
3377  /// Creates a new consolidator for the specified period, generating the requested output type.
3378  /// </summary>
3379  /// <param name="period">The consolidation period</param>
3380  /// <param name="consolidatorInputType">The desired input type of the consolidator, such as TradeBar or QuoteBar</param>
3381  /// <param name="tickType">Trade or Quote. Optional, defaults to trade</param>
3382  /// <returns>A new consolidator matching the requested parameters</returns>
3383  [DocumentationAttribute(ConsolidatingData)]
3384  public static IDataConsolidator CreateConsolidator(TimeSpan period, Type consolidatorInputType, TickType? tickType = null)
3385  {
3386  if (period.Ticks == 0)
3387  {
3388  return CreateIdentityConsolidator(consolidatorInputType);
3389  }
3390 
3391  // if our type can be used as a trade bar, then let's just make one of those
3392  // we use IsAssignableFrom instead of IsSubclassOf so that we can account for types that are able to be cast to TradeBar
3393  if (typeof(TradeBar).IsAssignableFrom(consolidatorInputType))
3394  {
3395  return new TradeBarConsolidator(period);
3396  }
3397 
3398  // if our type can be used as a quote bar, then let's just make one of those
3399  // we use IsAssignableFrom instead of IsSubclassOf so that we can account for types that are able to be cast to QuoteBar
3400  if (typeof(QuoteBar).IsAssignableFrom(consolidatorInputType))
3401  {
3402  return new QuoteBarConsolidator(period);
3403  }
3404 
3405  // if our type can be used as a tick then we'll use a consolidator that keeps the TickType
3406  // we use IsAssignableFrom instead of IsSubclassOf so that we can account for types that are able to be cast to Tick
3407  if (typeof(Tick).IsAssignableFrom(consolidatorInputType))
3408  {
3409  switch (tickType)
3410  {
3411  case TickType.OpenInterest:
3412  return new OpenInterestConsolidator(period);
3413 
3414  case TickType.Quote:
3415  return new TickQuoteBarConsolidator(period);
3416 
3417  default:
3418  return new TickConsolidator(period);
3419  }
3420  }
3421 
3422  // if our type can be used as a DynamicData then we'll use the DynamicDataConsolidator
3423  if (typeof(DynamicData).IsAssignableFrom(consolidatorInputType))
3424  {
3425  return new DynamicDataConsolidator(period);
3426  }
3427 
3428  // no matter what we can always consolidate based on the time-value pair of BaseData
3429  return new BaseDataConsolidator(period);
3430  }
3431 
3432  /// <summary>
3433  /// Registers the <paramref name="handler"/> to receive consolidated data for the specified symbol
3434  /// </summary>
3435  /// <param name="symbol">The symbol who's data is to be consolidated</param>
3436  /// <param name="period">The consolidation period</param>
3437  /// <param name="handler">Data handler receives new consolidated data when generated</param>
3438  /// <returns>A new consolidator matching the requested parameters with the handler already registered</returns>
3439  [DocumentationAttribute(ConsolidatingData)]
3440  public IDataConsolidator Consolidate(Symbol symbol, Resolution period, Action<TradeBar> handler)
3441  {
3442  return Consolidate(symbol, period, TickType.Trade, handler);
3443  }
3444 
3445  /// <summary>
3446  /// Registers the <paramref name="handler"/> to receive consolidated data for the specified symbol
3447  /// </summary>
3448  /// <param name="symbol">The symbol who's data is to be consolidated</param>
3449  /// <param name="period">The consolidation period</param>
3450  /// <param name="handler">Data handler receives new consolidated data when generated</param>
3451  /// <returns>A new consolidator matching the requested parameters with the handler already registered</returns>
3452  [DocumentationAttribute(ConsolidatingData)]
3453  public IDataConsolidator Consolidate(Symbol symbol, TimeSpan period, Action<TradeBar> handler)
3454  {
3455  return Consolidate(symbol, period, TickType.Trade, handler);
3456  }
3457 
3458  /// <summary>
3459  /// Registers the <paramref name="handler"/> to receive consolidated data for the specified symbol
3460  /// </summary>
3461  /// <param name="symbol">The symbol who's data is to be consolidated</param>
3462  /// <param name="period">The consolidation period</param>
3463  /// <param name="handler">Data handler receives new consolidated data when generated</param>
3464  /// <returns>A new consolidator matching the requested parameters with the handler already registered</returns>
3465  [DocumentationAttribute(ConsolidatingData)]
3466  public IDataConsolidator Consolidate(Symbol symbol, Resolution period, Action<QuoteBar> handler)
3467  {
3468  return Consolidate(symbol, period.ToTimeSpan(), TickType.Quote, handler);
3469  }
3470 
3471  /// <summary>
3472  /// Registers the <paramref name="handler"/> to receive consolidated data for the specified symbol
3473  /// </summary>
3474  /// <param name="symbol">The symbol who's data is to be consolidated</param>
3475  /// <param name="period">The consolidation period</param>
3476  /// <param name="handler">Data handler receives new consolidated data when generated</param>
3477  /// <returns>A new consolidator matching the requested parameters with the handler already registered</returns>
3478  [DocumentationAttribute(ConsolidatingData)]
3479  public IDataConsolidator Consolidate(Symbol symbol, TimeSpan period, Action<QuoteBar> handler)
3480  {
3481  return Consolidate(symbol, period, TickType.Quote, handler);
3482  }
3483 
3484  /// <summary>
3485  /// Registers the <paramref name="handler"/> to receive consolidated data for the specified symbol and tick type.
3486  /// The handler and tick type must match.
3487  /// </summary>
3488  /// <param name="symbol">The symbol who's data is to be consolidated</param>
3489  /// <param name="period">The consolidation period</param>
3490  /// <param name="handler">Data handler receives new consolidated data when generated</param>
3491  /// <returns>A new consolidator matching the requested parameters with the handler already registered</returns>
3492  [DocumentationAttribute(ConsolidatingData)]
3493  public IDataConsolidator Consolidate<T>(Symbol symbol, TimeSpan period, Action<T> handler)
3494  where T : class, IBaseData
3495  {
3496  // 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
3497  // decision here (default type), it will be taken later by 'GetSubscription' so we keep it centralized
3498  // This could happen when a user passes in a generic 'Action<BaseData>' handler
3499  var tickType = typeof(T).IsAbstract ? (TickType?)null : LeanData.GetCommonTickTypeForCommonDataTypes(typeof(T), symbol.SecurityType);
3500  return Consolidate(symbol, period, tickType, handler);
3501  }
3502 
3503  /// <summary>
3504  /// Registers the <paramref name="handler"/> to receive consolidated data for the specified symbol and tick type.
3505  /// The handler and tick type must match.
3506  /// </summary>
3507  /// <param name="symbol">The symbol who's data is to be consolidated</param>
3508  /// <param name="period">The consolidation period</param>
3509  /// <param name="tickType">The tick type of subscription used as data source for consolidator. Specify null to use first subscription found.</param>
3510  /// <param name="handler">Data handler receives new consolidated data when generated</param>
3511  /// <returns>A new consolidator matching the requested parameters with the handler already registered</returns>
3512  [DocumentationAttribute(ConsolidatingData)]
3513  public IDataConsolidator Consolidate<T>(Symbol symbol, Resolution period, TickType? tickType, Action<T> handler)
3514  where T : class, IBaseData
3515  {
3516  return Consolidate(symbol, null, tickType, handler, null, period);
3517  }
3518 
3519  /// <summary>
3520  /// Registers the <paramref name="handler"/> to receive consolidated data for the specified symbol and tick type.
3521  /// The handler and tick type must match.
3522  /// </summary>
3523  /// <param name="symbol">The symbol who's data is to be consolidated</param>
3524  /// <param name="period">The consolidation period</param>
3525  /// <param name="tickType">The tick type of subscription used as data source for consolidator. Specify null to use first subscription found.</param>
3526  /// <param name="handler">Data handler receives new consolidated data when generated</param>
3527  /// <returns>A new consolidator matching the requested parameters with the handler already registered</returns>
3528  [DocumentationAttribute(ConsolidatingData)]
3529  public IDataConsolidator Consolidate<T>(Symbol symbol, TimeSpan period, TickType? tickType, Action<T> handler)
3530  where T : class, IBaseData
3531  {
3532  return Consolidate(symbol, null, tickType, handler, period, null);
3533  }
3534 
3535  /// <summary>
3536  /// Registers the <paramref name="handler"/> to receive consolidated data for the specified symbol
3537  /// </summary>
3538  /// <param name="symbol">The symbol who's data is to be consolidated</param>
3539  /// <param name="calendar">The consolidation calendar</param>
3540  /// <param name="handler">Data handler receives new consolidated data when generated</param>
3541  /// <returns>A new consolidator matching the requested parameters with the handler already registered</returns>
3542  [DocumentationAttribute(ConsolidatingData)]
3543  public IDataConsolidator Consolidate(Symbol symbol, Func<DateTime, CalendarInfo> calendar, Action<QuoteBar> handler)
3544  {
3545  return Consolidate(symbol, calendar, TickType.Quote, handler);
3546  }
3547 
3548  /// <summary>
3549  /// Registers the <paramref name="handler"/> to receive consolidated data for the specified symbol
3550  /// </summary>
3551  /// <param name="symbol">The symbol who's data is to be consolidated</param>
3552  /// <param name="calendar">The consolidation calendar</param>
3553  /// <param name="handler">Data handler receives new consolidated data when generated</param>
3554  /// <returns>A new consolidator matching the requested parameters with the handler already registered</returns>
3555  [DocumentationAttribute(ConsolidatingData)]
3556  public IDataConsolidator Consolidate(Symbol symbol, Func<DateTime, CalendarInfo> calendar, Action<TradeBar> handler)
3557  {
3558  return Consolidate(symbol, calendar, TickType.Trade, handler);
3559  }
3560 
3561  /// <summary>
3562  /// Registers the <paramref name="handler"/> to receive consolidated data for the specified symbol and tick type.
3563  /// The handler and tick type must match.
3564  /// </summary>
3565  /// <param name="symbol">The symbol who's data is to be consolidated</param>
3566  /// <param name="calendar">The consolidation calendar</param>
3567  /// <param name="handler">Data handler receives new consolidated data when generated</param>
3568  /// <returns>A new consolidator matching the requested parameters with the handler already registered</returns>
3569  [DocumentationAttribute(ConsolidatingData)]
3570  public IDataConsolidator Consolidate<T>(Symbol symbol, Func<DateTime, CalendarInfo> calendar, Action<T> handler)
3571  where T : class, IBaseData
3572  {
3573  // 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
3574  // decision here (default type), it will be taken later by 'GetSubscription' so we keep it centralized
3575  // This could happen when a user passes in a generic 'Action<BaseData>' handler
3576  var tickType = typeof(T).IsAbstract ? (TickType?)null : LeanData.GetCommonTickTypeForCommonDataTypes(typeof(T), symbol.SecurityType);
3577  return Consolidate(symbol, calendar, tickType, handler);
3578  }
3579 
3580  /// <summary>
3581  /// Registers the <paramref name="handler"/> to receive consolidated data for the specified symbol and tick type.
3582  /// The handler and tick type must match.
3583  /// </summary>
3584  /// <param name="symbol">The symbol who's data is to be consolidated</param>
3585  /// <param name="calendar">The consolidation calendar</param>
3586  /// <param name="tickType">The tick type of subscription used as data source for consolidator. Specify null to use first subscription found.</param>
3587  /// <param name="handler">Data handler receives new consolidated data when generated</param>
3588  /// <returns>A new consolidator matching the requested parameters with the handler already registered</returns>
3589  [DocumentationAttribute(ConsolidatingData)]
3590  public IDataConsolidator Consolidate<T>(Symbol symbol, Func<DateTime, CalendarInfo> calendar, TickType? tickType, Action<T> handler)
3591  where T : class, IBaseData
3592  {
3593  return Consolidate(symbol, calendar, tickType, handler, null, null);
3594  }
3595 
3596  /// <summary>
3597  /// Gets the historical data of an indicator for the specified symbol. The exact number of bars will be returned.
3598  /// The symbol must exist in the Securities collection.
3599  /// </summary>
3600  /// <param name="indicator">The target indicator</param>
3601  /// <param name="symbol">The symbol to retrieve historical data for</param>
3602  /// <param name="period">The number of bars to request</param>
3603  /// <param name="resolution">The resolution to request</param>
3604  /// <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>
3605  /// <returns>pandas.DataFrame of historical data of an indicator</returns>
3606  public IndicatorHistory IndicatorHistory(IndicatorBase<IndicatorDataPoint> indicator, Symbol symbol, int period, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
3607  {
3608  return IndicatorHistory(indicator, new[] { symbol }, period, resolution, selector);
3609  }
3610 
3611  /// <summary>
3612  /// Gets the historical data of an indicator for the specified symbols. The exact number of bars will be returned.
3613  /// The symbol must exist in the Securities collection.
3614  /// </summary>
3615  /// <param name="indicator">The target indicator</param>
3616  /// <param name="symbols">The symbols to retrieve historical data for</param>
3617  /// <param name="period">The number of bars to request</param>
3618  /// <param name="resolution">The resolution to request</param>
3619  /// <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>
3620  /// <returns>pandas.DataFrame of historical data of an indicator</returns>
3621  public IndicatorHistory IndicatorHistory(IndicatorBase<IndicatorDataPoint> indicator, IEnumerable<Symbol> symbols, int period, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
3622  {
3623  var warmupPeriod = (indicator as IIndicatorWarmUpPeriodProvider)?.WarmUpPeriod ?? 0;
3624  if (warmupPeriod > 0 && period > 0)
3625  {
3626  warmupPeriod -= 1;
3627  }
3628  var history = History(symbols, period + warmupPeriod, resolution, dataNormalizationMode: GetIndicatorHistoryDataNormalizationMode(indicator));
3629  return IndicatorHistory(indicator, history, selector);
3630  }
3631 
3632  /// <summary>
3633  /// Gets the historical data of a bar indicator for the specified symbol. The exact number of bars will be returned.
3634  /// The symbol must exist in the Securities collection.
3635  /// </summary>
3636  /// <param name="indicator">The target indicator</param>
3637  /// <param name="symbol">The symbol to retrieve historical data for</param>
3638  /// <param name="period">The number of bars to request</param>
3639  /// <param name="resolution">The resolution to request</param>
3640  /// <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>
3641  /// <returns>pandas.DataFrame of historical data of a bar indicator</returns>
3642  public IndicatorHistory IndicatorHistory<T>(IndicatorBase<T> indicator, Symbol symbol, int period, Resolution? resolution = null, Func<IBaseData, T> selector = null)
3643  where T : IBaseData
3644  {
3645  return IndicatorHistory(indicator, new[] { symbol }, period, resolution, selector);
3646  }
3647 
3648  /// <summary>
3649  /// Gets the historical data of a bar indicator for the specified symbols. The exact number of bars will be returned.
3650  /// The symbol must exist in the Securities collection.
3651  /// </summary>
3652  /// <param name="indicator">The target indicator</param>
3653  /// <param name="symbols">The symbols to retrieve historical data for</param>
3654  /// <param name="period">The number of bars to request</param>
3655  /// <param name="resolution">The resolution to request</param>
3656  /// <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>
3657  /// <returns>pandas.DataFrame of historical data of a bar indicator</returns>
3658  public IndicatorHistory IndicatorHistory<T>(IndicatorBase<T> indicator, IEnumerable<Symbol> symbols, int period, Resolution? resolution = null, Func<IBaseData, T> selector = null)
3659  where T : IBaseData
3660  {
3661  var warmupPeriod = (indicator as IIndicatorWarmUpPeriodProvider)?.WarmUpPeriod ?? 0;
3662  if (warmupPeriod > 0 && period > 0)
3663  {
3664  warmupPeriod -= 1;
3665  }
3666  var history = History(symbols, period + warmupPeriod, resolution, dataNormalizationMode: GetIndicatorHistoryDataNormalizationMode(indicator));
3667  return IndicatorHistory(indicator, history, selector);
3668  }
3669 
3670  /// <summary>
3671  /// Gets the historical data of an indicator for the specified symbol. The exact number of bars will be returned.
3672  /// The symbol must exist in the Securities collection.
3673  /// </summary>
3674  /// <param name="indicator">The target indicator</param>
3675  /// <param name="symbol">The symbol to retrieve historical data for</param>
3676  /// <param name="span">The span over which to retrieve recent historical data</param>
3677  /// <param name="resolution">The resolution to request</param>
3678  /// <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>
3679  /// <returns>pandas.DataFrame of historical data of an indicator</returns>
3680  public IndicatorHistory IndicatorHistory(IndicatorBase<IndicatorDataPoint> indicator, Symbol symbol, TimeSpan span, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
3681  {
3682  return IndicatorHistory(indicator, new[] { symbol }, span, resolution, selector);
3683  }
3684 
3685  /// <summary>
3686  /// Gets the historical data of an indicator for the specified symbol. The exact number of bars will be returned.
3687  /// The symbol must exist in the Securities collection.
3688  /// </summary>
3689  /// <param name="indicator">The target indicator</param>
3690  /// <param name="symbols">The symbols to retrieve historical data for</param>
3691  /// <param name="span">The span over which to retrieve recent historical data</param>
3692  /// <param name="resolution">The resolution to request</param>
3693  /// <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>
3694  /// <returns>pandas.DataFrame of historical data of an indicator</returns>
3695  public IndicatorHistory IndicatorHistory(IndicatorBase<IndicatorDataPoint> indicator, IEnumerable<Symbol> symbols, TimeSpan span, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
3696  {
3697  return IndicatorHistory(indicator, symbols, Time - span, Time, resolution, selector);
3698  }
3699 
3700  /// <summary>
3701  /// Gets the historical data of a bar indicator for the specified symbol. The exact number of bars will be returned.
3702  /// The symbol must exist in the Securities collection.
3703  /// </summary>
3704  /// <param name="indicator">The target indicator</param>
3705  /// <param name="symbols">The symbols to retrieve historical data for</param>
3706  /// <param name="span">The span over which to retrieve recent historical data</param>
3707  /// <param name="resolution">The resolution to request</param>
3708  /// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
3709  /// <returns>pandas.DataFrame of historical data of a bar indicator</returns>
3710  public IndicatorHistory IndicatorHistory<T>(IndicatorBase<T> indicator, IEnumerable<Symbol> symbols, TimeSpan span, Resolution? resolution = null, Func<IBaseData, T> selector = null)
3711  where T : IBaseData
3712  {
3713  return IndicatorHistory(indicator, symbols, Time - span, Time, resolution, selector);
3714  }
3715 
3716  /// <summary>
3717  /// Gets the historical data of a bar indicator for the specified symbol. The exact number of bars will be returned.
3718  /// The symbol must exist in the Securities collection.
3719  /// </summary>
3720  /// <param name="indicator">The target indicator</param>
3721  /// <param name="symbol">The symbol to retrieve historical data for</param>
3722  /// <param name="span">The span over which to retrieve recent historical data</param>
3723  /// <param name="resolution">The resolution to request</param>
3724  /// <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>
3725  /// <returns>pandas.DataFrame of historical data of a bar indicator</returns>
3726  public IndicatorHistory IndicatorHistory<T>(IndicatorBase<T> indicator, Symbol symbol, TimeSpan span, Resolution? resolution = null, Func<IBaseData, T> selector = null)
3727  where T : IBaseData
3728  {
3729  return IndicatorHistory(indicator, new[] { symbol }, span, resolution, selector);
3730  }
3731 
3732  /// <summary>
3733  /// Gets the historical data of an indicator for the specified symbols. The exact number of bars will be returned.
3734  /// The symbol must exist in the Securities collection.
3735  /// </summary>
3736  /// <param name="indicator">The target indicator</param>
3737  /// <param name="symbols">The symbols to retrieve historical data for</param>
3738  /// <param name="start">The start time in the algorithm's time zone</param>
3739  /// <param name="end">The end time in the algorithm's time zone</param>
3740  /// <param name="resolution">The resolution to request</param>
3741  /// <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>
3742  /// <returns>pandas.DataFrame of historical data of an indicator</returns>
3743  public IndicatorHistory IndicatorHistory(IndicatorBase<IndicatorDataPoint> indicator, IEnumerable<Symbol> symbols, DateTime start, DateTime end, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
3744  {
3745  var history = History(symbols, GetIndicatorAdjustedHistoryStart(indicator, symbols, start, end, resolution), end, resolution, dataNormalizationMode: GetIndicatorHistoryDataNormalizationMode(indicator));
3746  return IndicatorHistory(indicator, history, selector);
3747  }
3748 
3749  /// <summary>
3750  /// Gets the historical data of an indicator for the specified symbol. The exact number of bars will be returned.
3751  /// The symbol must exist in the Securities collection.
3752  /// </summary>
3753  /// <param name="indicator">The target indicator</param>
3754  /// <param name="symbol">The symbol to retrieve historical data for</param>
3755  /// <param name="start">The start time in the algorithm's time zone</param>
3756  /// <param name="end">The end time in the algorithm's time zone</param>
3757  /// <param name="resolution">The resolution to request</param>
3758  /// <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>
3759  /// <returns>pandas.DataFrame of historical data of an indicator</returns>
3760  public IndicatorHistory IndicatorHistory(IndicatorBase<IndicatorDataPoint> indicator, Symbol symbol, DateTime start, DateTime end, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
3761  {
3762  return IndicatorHistory(indicator, new[] { symbol }, start, end, resolution, selector);
3763  }
3764 
3765  /// <summary>
3766  /// Gets the historical data of a bar indicator for the specified symbol. The exact number of bars will be returned.
3767  /// The symbol must exist in the Securities collection.
3768  /// </summary>
3769  /// <param name="indicator">The target indicator</param>
3770  /// <param name="symbol">The symbol to retrieve historical data for</param>
3771  /// <param name="start">The start time in the algorithm's time zone</param>
3772  /// <param name="end">The end time in the algorithm's time zone</param>
3773  /// <param name="resolution">The resolution to request</param>
3774  /// <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>
3775  /// <returns>pandas.DataFrame of historical data of a bar indicator</returns>
3776  public IndicatorHistory IndicatorHistory<T>(IndicatorBase<T> indicator, Symbol symbol, DateTime start, DateTime end, Resolution? resolution = null, Func<IBaseData, T> selector = null)
3777  where T : IBaseData
3778  {
3779  return IndicatorHistory(indicator, new[] { symbol }, start, end, resolution, selector);
3780  }
3781 
3782  /// <summary>
3783  /// Gets the historical data of a bar indicator for the specified symbols. The exact number of bars will be returned.
3784  /// The symbol must exist in the Securities collection.
3785  /// </summary>
3786  /// <param name="indicator">The target indicator</param>
3787  /// <param name="symbols">The symbols to retrieve historical data for</param>
3788  /// <param name="start">The start time in the algorithm's time zone</param>
3789  /// <param name="end">The end time in the algorithm's time zone</param>
3790  /// <param name="resolution">The resolution to request</param>
3791  /// <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>
3792  /// <returns>pandas.DataFrame of historical data of a bar indicator</returns>
3793  public IndicatorHistory IndicatorHistory<T>(IndicatorBase<T> indicator, IEnumerable<Symbol> symbols, DateTime start, DateTime end, Resolution? resolution = null, Func<IBaseData, T> selector = null)
3794  where T : IBaseData
3795  {
3796  var history = History(symbols, GetIndicatorAdjustedHistoryStart(indicator, symbols, start, end, resolution), end, resolution, dataNormalizationMode: GetIndicatorHistoryDataNormalizationMode(indicator));
3797  return IndicatorHistory(indicator, history, selector);
3798  }
3799 
3800  /// <summary>
3801  /// Gets the historical data of an indicator and convert it into pandas.DataFrame
3802  /// </summary>
3803  /// <param name="indicator">The target indicator</param>
3804  /// <param name="history">Historical data used to calculate the indicator</param>
3805  /// <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>
3806  /// <returns>pandas.DataFrame containing the historical data of <paramref name="indicator"/></returns>
3807  public IndicatorHistory IndicatorHistory(IndicatorBase<IndicatorDataPoint> indicator, IEnumerable<Slice> history, Func<IBaseData, decimal> selector = null)
3808  {
3809  selector ??= (x => x.Value);
3810  return IndicatorHistory(indicator, history, (bar) => indicator.Update(new IndicatorDataPoint(bar.Symbol, bar.EndTime, selector(bar))), GetDataTypeFromSelector(selector));
3811  }
3812 
3813  /// <summary>
3814  /// Gets the historical data of an bar indicator and convert it into pandas.DataFrame
3815  /// </summary>
3816  /// <param name="indicator">Bar indicator</param>
3817  /// <param name="history">Historical data used to calculate the indicator</param>
3818  /// <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>
3819  /// <returns>pandas.DataFrame containing the historical data of <paramref name="indicator"/></returns>
3820  public IndicatorHistory IndicatorHistory<T>(IndicatorBase<T> indicator, IEnumerable<Slice> history, Func<IBaseData, T> selector = null)
3821  where T : IBaseData
3822  {
3823  selector ??= (x => (T)x);
3824  return IndicatorHistory(indicator, history, (bar) => indicator.Update(selector(bar)));
3825  }
3826 
3827  /// <summary>
3828  /// Adds the provided consolidator and asserts the handler T type is assignable from the consolidator output,
3829  /// if not will throw <see cref="ArgumentException"/>
3830  /// </summary>
3831  private IDataConsolidator Consolidate<T>(Symbol symbol, Func<DateTime, CalendarInfo> calendar, TickType? tickType, Action<T> handler, TimeSpan? period, Resolution? resolution)
3832  where T : class, IBaseData
3833  {
3834  var consolidator = CreateConsolidator(symbol, calendar, tickType, period, resolution, typeof(T));
3835  if (handler != null)
3836  {
3837  // register user-defined handler to receive consolidated data events
3838  consolidator.DataConsolidated += (sender, consolidated) => handler((T)consolidated);
3839 
3840  // register the consolidator for automatic updates via SubscriptionManager
3841  RegisterConsolidator(symbol, consolidator, tickType, indicatorBase: null);
3842  }
3843  return consolidator;
3844  }
3845 
3846  private IDataConsolidator CreateConsolidator(Symbol symbol, Func<DateTime, CalendarInfo> calendar, TickType? tickType, TimeSpan? period, Resolution? resolution, Type consolidatorType)
3847  {
3848  // resolve consolidator input subscription
3849  var subscription = GetSubscription(symbol, tickType);
3850 
3851  // verify this consolidator will give reasonable results, if someone asks for second consolidation but we have minute
3852  // data we won't be able to do anything good, we'll call it second, but it would really just be minute!
3853  if (period.HasValue && period.Value < subscription.Increment || resolution.HasValue && resolution.Value < subscription.Resolution)
3854  {
3855  throw new ArgumentException($"Unable to create {symbol} consolidator because {symbol} is registered for " +
3856  Invariant($"{subscription.Resolution.ToStringInvariant()} data. Consolidators require higher resolution data to produce lower resolution data.")
3857  );
3858  }
3859 
3860  IDataConsolidator consolidator = null;
3861  if (calendar != null)
3862  {
3863  // create requested consolidator
3864  consolidator = CreateConsolidator(calendar, subscription.Type, subscription.TickType);
3865  }
3866  else
3867  {
3868  // if not specified, default to the subscription resolution
3869  if (!period.HasValue && !resolution.HasValue)
3870  {
3871  period = subscription.Increment;
3872  }
3873 
3874  if (period.HasValue && period.Value == subscription.Increment || resolution.HasValue && resolution.Value == subscription.Resolution)
3875  {
3876  consolidator = CreateIdentityConsolidator(subscription.Type);
3877  }
3878  else
3879  {
3880  if (resolution.HasValue)
3881  {
3882  if (resolution.Value == Resolution.Daily)
3883  {
3884  consolidator = new MarketHourAwareConsolidator(Settings.DailyPreciseEndTime, resolution.Value, subscription.Type, subscription.TickType,
3885  Settings.DailyConsolidationUseExtendedMarketHours && subscription.ExtendedMarketHours);
3886  }
3887  period = resolution.Value.ToTimeSpan();
3888  }
3889  consolidator ??= CreateConsolidator(period.Value, subscription.Type, subscription.TickType);
3890  }
3891  }
3892 
3893  if (consolidatorType != null && !consolidatorType.IsAssignableFrom(consolidator.OutputType))
3894  {
3895  throw new ArgumentException(
3896  $"Unable to consolidate with the specified handler because the consolidator's output type " +
3897  $"is {consolidator.OutputType.Name} but the handler's input type is {subscription.Type.Name}.");
3898  }
3899  return consolidator;
3900  }
3901 
3902  private IDataConsolidator CreateConsolidator(Func<DateTime, CalendarInfo> calendar, Type consolidatorInputType, TickType tickType)
3903  {
3904  // if our type can be used as a trade bar, then let's just make one of those
3905  // we use IsAssignableFrom instead of IsSubclassOf so that we can account for types that are able to be cast to TradeBar
3906  if (typeof(TradeBar).IsAssignableFrom(consolidatorInputType))
3907  {
3908  return new TradeBarConsolidator(calendar);
3909  }
3910 
3911  // if our type can be used as a quote bar, then let's just make one of those
3912  // we use IsAssignableFrom instead of IsSubclassOf so that we can account for types that are able to be cast to QuoteBar
3913  if (typeof(QuoteBar).IsAssignableFrom(consolidatorInputType))
3914  {
3915  return new QuoteBarConsolidator(calendar);
3916  }
3917 
3918  // if our type can be used as a tick then we'll use a consolidator that keeps the TickType
3919  // we use IsAssignableFrom instead of IsSubclassOf so that we can account for types that are able to be cast to Tick
3920  if (typeof(Tick).IsAssignableFrom(consolidatorInputType))
3921  {
3922  if (tickType == TickType.Quote)
3923  {
3924  return new TickQuoteBarConsolidator(calendar);
3925  }
3926  return new TickConsolidator(calendar);
3927  }
3928 
3929  // if our type can be used as a DynamicData then we'll use the DynamicDataConsolidator
3930  if (typeof(DynamicData).IsAssignableFrom(consolidatorInputType))
3931  {
3932  return new DynamicDataConsolidator(calendar);
3933  }
3934 
3935  // no matter what we can always consolidate based on the time-value pair of BaseData
3936  return new BaseDataConsolidator(calendar);
3937  }
3938 
3939  /// <summary>
3940  /// Creates a new consolidator identity consolidator for the requested output type.
3941  /// </summary>
3942  private static IDataConsolidator CreateIdentityConsolidator(Type consolidatorInputType)
3943  {
3944  if (typeof(TradeBar).IsAssignableFrom(consolidatorInputType))
3945  {
3947  }
3948  else if (typeof(QuoteBar).IsAssignableFrom(consolidatorInputType))
3949  {
3951  }
3952  else if (typeof(Tick).IsAssignableFrom(consolidatorInputType))
3953  {
3954  return new IdentityDataConsolidator<Tick>();
3955  }
3956  else if (typeof(DynamicData).IsAssignableFrom(consolidatorInputType))
3957  {
3958  return new DynamicDataConsolidator(1);
3959  }
3961  }
3962 
3963  /// <summary>
3964  /// Registers and warms up (if EnableAutomaticIndicatorWarmUp is set) the indicator
3965  /// </summary>
3966  private void InitializeIndicator(IndicatorBase<IndicatorDataPoint> indicator, Resolution? resolution = null,
3967  Func<IBaseData, decimal> selector = null, params Symbol[] symbols)
3968  {
3969  var dataType = GetDataTypeFromSelector(selector);
3970  foreach (var symbol in symbols)
3971  {
3972  RegisterIndicator(symbol, indicator, ResolveConsolidator(symbol, resolution, dataType), selector);
3973  }
3974 
3976  {
3977  WarmUpIndicator(symbols, indicator, resolution, selector);
3978  }
3979  }
3980 
3981  private void InitializeIndicator<T>(IndicatorBase<T> indicator, Resolution? resolution = null,
3982  Func<IBaseData, T> selector = null, params Symbol[] symbols)
3983  where T : class, IBaseData
3984  {
3985  foreach (var symbol in symbols)
3986  {
3987  RegisterIndicator(symbol, indicator, resolution, selector);
3988  }
3989 
3991  {
3992  WarmUpIndicator(symbols, indicator, resolution, selector);
3993  }
3994  }
3995 
3996  private void InitializeOptionIndicator(IndicatorBase<IndicatorDataPoint> indicator, Resolution? resolution, Symbol symbol, Symbol mirrorOption)
3997  {
3998  RegisterIndicator(symbol, indicator, ResolveConsolidator(symbol, resolution, typeof(QuoteBar)));
3999  RegisterIndicator(symbol.Underlying, indicator, ResolveConsolidator(symbol.Underlying, resolution));
4000  var symbols = new List<Symbol> { symbol, symbol.Underlying };
4001  if (mirrorOption != null)
4002  {
4003  RegisterIndicator(mirrorOption, indicator, ResolveConsolidator(mirrorOption, resolution, typeof(QuoteBar)));
4004  symbols.Add(mirrorOption);
4005  }
4006 
4008  {
4009  WarmUpIndicator(symbols, indicator, resolution);
4010  }
4011  }
4012 
4013  private string InitializeOptionIndicator<T>(Symbol symbol, out IRiskFreeInterestRateModel riskFreeRateModel, out IDividendYieldModel dividendYieldModel,
4014  decimal? riskFreeRate = null, decimal? dividendYield = null, OptionPricingModelType? optionModel = null, Resolution? resolution = null)
4015  where T : OptionIndicatorBase
4016  {
4017  var name = CreateIndicatorName(symbol,
4018  $"{typeof(T).Name}({riskFreeRate},{dividendYield},{OptionIndicatorBase.GetOptionModel(optionModel, symbol.ID.OptionStyle)})",
4019  resolution);
4020 
4021  riskFreeRateModel = riskFreeRate.HasValue
4022  ? new ConstantRiskFreeRateInterestRateModel(riskFreeRate.Value)
4023  // Make it a function so it's lazily evaluated: SetRiskFreeInterestRateModel can be called after this method
4024  : new FuncRiskFreeRateInterestRateModel((datetime) => RiskFreeInterestRateModel.GetInterestRate(datetime));
4025 
4026  if (dividendYield.HasValue)
4027  {
4028  dividendYieldModel = new ConstantDividendYieldModel(dividendYield.Value);
4029  }
4030  else
4031  {
4032  dividendYieldModel = DividendYieldProvider.CreateForOption(symbol);
4033  }
4034 
4035  return name;
4036  }
4037 
4038  private void RegisterConsolidator(Symbol symbol, IDataConsolidator consolidator, TickType? tickType, IndicatorBase indicatorBase)
4039  {
4040  // keep a reference of the consolidator so we can unregister it later using only a reference to the indicator
4041  indicatorBase?.Consolidators.Add(consolidator);
4042 
4043  // register the consolidator for automatic updates via SubscriptionManager
4044  SubscriptionManager.AddConsolidator(symbol, consolidator, tickType);
4045  }
4046 
4047  private DateTime GetIndicatorAdjustedHistoryStart(IndicatorBase indicator, IEnumerable<Symbol> symbols, DateTime start, DateTime end, Resolution? resolution = null)
4048  {
4049  var warmupPeriod = (indicator as IIndicatorWarmUpPeriodProvider)?.WarmUpPeriod ?? 0;
4050  if (warmupPeriod != 0)
4051  {
4052  warmupPeriod -= 1;
4053  if (warmupPeriod > 0)
4054  {
4055  foreach (var request in CreateDateRangeHistoryRequests(symbols, start, end, resolution))
4056  {
4057  var adjustedStart = _historyRequestFactory.GetStartTimeAlgoTz(request.StartTimeUtc, request.Symbol, warmupPeriod, request.Resolution,
4058  request.ExchangeHours, request.DataTimeZone, request.DataType, request.IncludeExtendedMarketHours);
4059  if (adjustedStart < start)
4060  {
4061  start = adjustedStart;
4062  }
4063  }
4064  }
4065  }
4066  return start;
4067  }
4068 
4069  private DataNormalizationMode? GetIndicatorHistoryDataNormalizationMode(IIndicator indicator)
4070  {
4071  DataNormalizationMode? dataNormalizationMode = null;
4072  if (indicator is OptionIndicatorBase optionIndicator && optionIndicator.OptionSymbol.Underlying.SecurityType == SecurityType.Equity)
4073  {
4074  // we use point in time raw data to warmup option indicators which use underlying prices and strikes
4075  dataNormalizationMode = DataNormalizationMode.ScaledRaw;
4076  }
4077  return dataNormalizationMode;
4078  }
4079 
4080  private IndicatorHistory IndicatorHistory<T>(IndicatorBase<T> indicator, IEnumerable<Slice> history, Action<IBaseData> updateIndicator, Type dataType = null)
4081  where T : IBaseData
4082  {
4083  // Reset the indicator
4084  indicator.Reset();
4085 
4086  var indicatorType = indicator.GetType();
4087  // Create a dictionary of the indicator properties & the indicator value itself
4088  var indicatorsDataPointPerProperty = indicatorType.GetProperties()
4089  .Where(x => x.PropertyType.IsGenericType && x.Name != "Consolidators" && x.Name != "Window")
4090  .Select(x => InternalIndicatorValues.Create(indicator, x))
4091  .Concat(new[] { InternalIndicatorValues.Create(indicator, "Current") })
4092  .ToList();
4093 
4094  var indicatorsDataPointsByTime = new List<IndicatorDataPoints>();
4095  var lastConsumedTime = DateTime.MinValue;
4096  IndicatorDataPoint lastPoint = null;
4097  void consumeLastPoint(IndicatorDataPoint newInputPoint)
4098  {
4099  if (newInputPoint == null || lastConsumedTime == newInputPoint.EndTime)
4100  {
4101  return;
4102  }
4103  lastConsumedTime = newInputPoint.EndTime;
4104 
4105  var IndicatorDataPoints = new IndicatorDataPoints { Time = newInputPoint.Time, EndTime = newInputPoint.EndTime };
4106  indicatorsDataPointsByTime.Add(IndicatorDataPoints);
4107  for (var i = 0; i < indicatorsDataPointPerProperty.Count; i++)
4108  {
4109  var newPoint = indicatorsDataPointPerProperty[i].UpdateValue();
4110  IndicatorDataPoints.SetProperty(indicatorsDataPointPerProperty[i].Name, newPoint);
4111  }
4112  }
4113 
4114  IndicatorUpdatedHandler callback = (object _, IndicatorDataPoint newInputPoint) =>
4115  {
4116  if (!indicator.IsReady)
4117  {
4118  return;
4119  }
4120 
4121  if (lastPoint == null || lastPoint.Time != newInputPoint.Time)
4122  {
4123  // if null, it's the first point, we transitions from not ready to ready
4124  // else when the time changes we fetch the indicators values, some indicators which consume data from multiple symbols might trigger the Updated event
4125  // even if their value has not changed yet
4126  consumeLastPoint(newInputPoint);
4127  }
4128  lastPoint = newInputPoint;
4129  };
4130 
4131  // register the callback, update the indicator and unregister finally
4132  indicator.Updated += callback;
4133 
4134  if (typeof(T) == typeof(IndicatorDataPoint) || typeof(T).IsAbstract)
4135  {
4136  history.PushThrough(bar => updateIndicator(bar), dataType);
4137  }
4138  else
4139  {
4140  // if the indicator requires a specific type, like a QuoteBar for an equity symbol, we need to fetch it directly
4141  foreach (var dataDictionary in history.Get<T>())
4142  {
4143  foreach (var dataPoint in dataDictionary.Values)
4144  {
4145  updateIndicator(dataPoint);
4146  }
4147  }
4148  }
4149  // flush the last point, this will be useful for indicator consuming time from multiple symbols
4150  consumeLastPoint(lastPoint);
4151  indicator.Updated -= callback;
4152 
4153  return new IndicatorHistory(indicatorsDataPointsByTime, indicatorsDataPointPerProperty,
4154  new Lazy<PyObject>(
4155  () => PandasConverter.GetIndicatorDataFrame(indicatorsDataPointPerProperty.Select(x => new KeyValuePair<string, List<IndicatorDataPoint>>(x.Name, x.Values))),
4156  isThreadSafe: false));
4157  }
4158 
4159  private Type GetDataTypeFromSelector(Func<IBaseData, decimal> selector)
4160  {
4161  Type dataType = null;
4162  if (_quoteRequiredFields.Any(x => ReferenceEquals(selector, x)))
4163  {
4164  dataType = typeof(QuoteBar);
4165  }
4166  else if (ReferenceEquals(selector, Field.Volume))
4167  {
4168  dataType = typeof(TradeBar);
4169  }
4170 
4171  return dataType;
4172  }
4173  }
4174 }