18 using MathNet.Numerics.Statistics;
47 private readonly
Symbol _referenceSymbol;
52 private readonly
Symbol _targetSymbol;
62 private bool _previousSymbolIsTarget;
67 private bool _isTimezoneDifferent;
72 private DateTimeZone _targetTimeZone;
77 private DateTimeZone _referenceTimeZone;
97 private decimal _beta;
107 public override bool IsReady => _targetReturns.IsReady && _referenceReturns.IsReady;
123 throw new ArgumentException($
"Period parameter for Beta indicator must be greater than 2 but was {period}.");
125 _referenceSymbol = referenceSymbol;
126 _targetSymbol = targetSymbol;
135 _targetTimeZone = dataFolder.
GetExchangeHours(_targetSymbol.ID.Market, _targetSymbol, _targetSymbol.ID.SecurityType).
TimeZone;
136 _referenceTimeZone = dataFolder.GetExchangeHours(_referenceSymbol.ID.Market, _referenceSymbol, _referenceSymbol.ID.SecurityType).TimeZone;
137 _isTimezoneDifferent = _targetTimeZone != _referenceTimeZone;
138 WarmUpPeriod = period + 1 + (_isTimezoneDifferent ? 1 : 0);
149 : this($
"B({period})", targetSymbol, referenceSymbol, period)
163 : this(name, targetSymbol, referenceSymbol, period)
180 if (_previousInput ==
null)
182 _previousInput = input;
183 _previousSymbolIsTarget = input.
Symbol == _targetSymbol;
185 _resolution = timeDifference.TotalHours > 1 ?
Resolution.Daily : timeDifference.ToHigherResolutionEquivalent(
false);
189 var inputEndTime = input.
EndTime;
190 var previousInputEndTime = _previousInput.
EndTime;
192 if (_isTimezoneDifferent)
194 inputEndTime = inputEndTime.ConvertToUtc(_previousSymbolIsTarget ? _referenceTimeZone : _targetTimeZone);
195 previousInputEndTime = previousInputEndTime.ConvertToUtc(_previousSymbolIsTarget ? _targetTimeZone : _referenceTimeZone);
199 if (input.
Symbol != _previousInput.
Symbol && TruncateToResolution(inputEndTime) == TruncateToResolution(previousInputEndTime))
202 AddDataPoint(_previousInput);
205 _previousInput = input;
206 _previousSymbolIsTarget = input.
Symbol == _targetSymbol;
215 private DateTime TruncateToResolution(DateTime date)
222 return date.Date.AddHours(date.Hour);
224 return date.Date.AddHours(date.Hour).AddMinutes(date.Minute);
239 if (input.
Symbol == _targetSymbol)
241 _targetDataPoints.Add(input.
Close);
242 if (_targetDataPoints.Count > 1)
244 _targetReturns.Add(GetNewReturn(_targetDataPoints));
247 else if (input.
Symbol == _referenceSymbol)
249 _referenceDataPoints.Add(input.
Close);
250 if (_referenceDataPoints.Count > 1)
252 _referenceReturns.Add(GetNewReturn(_referenceDataPoints));
257 throw new ArgumentException($
"The given symbol {input.Symbol} was not {_targetSymbol} or {_referenceSymbol} symbol");
267 private static double GetNewReturn(RollingWindow<decimal> rollingWindow)
269 return (
double)((rollingWindow[0].SafeDivision(rollingWindow[1]) - 1));
276 private void ComputeBeta()
278 var varianceComputed = _referenceReturns.Variance();
279 var covarianceComputed = _targetReturns.Covariance(_referenceReturns);
282 var variance = !varianceComputed.IsNaNOrZero() ? varianceComputed : 1;
283 var covariance = !covarianceComputed.IsNaNOrZero() ? covarianceComputed : 0;
284 _beta = (decimal)(covariance / variance);
292 _previousInput =
null;
293 _targetDataPoints.Reset();
294 _referenceDataPoints.Reset();
295 _targetReturns.Reset();
296 _referenceReturns.Reset();