diff --git a/Algorithm.CSharp/AddBetaIndicatorRegressionAlgorithm.cs b/Algorithm.CSharp/AddBetaIndicatorRegressionAlgorithm.cs index bb9b00466855..60e8c67e4480 100644 --- a/Algorithm.CSharp/AddBetaIndicatorRegressionAlgorithm.cs +++ b/Algorithm.CSharp/AddBetaIndicatorRegressionAlgorithm.cs @@ -44,6 +44,11 @@ public override void Initialize() _beta = B("IBM", "SPY", 3, Resolution.Daily); _sma = SMA("SPY", 3, Resolution.Daily); _lastSMAValue = 0; + + if (!_beta.IsReady) + { + throw new RegressionTestException("Beta indicator was expected to be ready"); + } } public override void OnData(Slice slice) @@ -84,18 +89,6 @@ public override void OnOrderEvent(OrderEvent orderEvent) } } - /// - /// End of algorithm run event handler. This method is called at the end of a backtest or live trading operation. Intended for closing out logs. - /// - public override void OnEndOfAlgorithm() - { - if (!_beta.IsReady) - { - throw new RegressionTestException("Beta indicator was expected to be ready"); - } - Log($"Beta between IBM and SPY is: {_beta.Current.Value}"); - } - /// /// This is used by the regression test system to indicate if the open source Lean repository has the required data to run this algorithm. /// @@ -114,7 +107,7 @@ public override void OnEndOfAlgorithm() /// /// Data Points count of the algorithm history /// - public int AlgorithmHistoryDataPoints => 9; + public int AlgorithmHistoryDataPoints => 15; /// /// Final status of the algorithm diff --git a/Algorithm/QCAlgorithm.Indicators.cs b/Algorithm/QCAlgorithm.Indicators.cs index 9724762fd395..a55b412d3f97 100644 --- a/Algorithm/QCAlgorithm.Indicators.cs +++ b/Algorithm/QCAlgorithm.Indicators.cs @@ -390,9 +390,8 @@ public BollingerBands BB(Symbol symbol, int period, decimal k, MovingAverageType [DocumentationAttribute(Indicators)] public Beta B(Symbol target, Symbol reference, int period, Resolution? resolution = null, Func selector = null) { - var effectiveResolution = resolution ?? Resolution.Daily; var name = CreateIndicatorName(QuantConnect.Symbol.None, $"B({period})", resolution); - var beta = new Beta(name, target, reference, period, effectiveResolution); + var beta = new Beta(name, target, reference, period); InitializeIndicator(beta, resolution, selector, target, reference); return beta; diff --git a/Indicators/Beta.cs b/Indicators/Beta.cs index 4077bc0c610b..b90f9e8e6fbb 100644 --- a/Indicators/Beta.cs +++ b/Indicators/Beta.cs @@ -99,7 +99,7 @@ public class Beta : BarIndicator, IIndicatorWarmUpPeriodProvider /// /// Gets a flag indicating when the indicator is ready and fully initialized /// - public override bool IsReady => _targetReturns.Samples >= WarmUpPeriod && _referenceReturns.Samples >= WarmUpPeriod; + public override bool IsReady => (2 * _targetReturns.Samples >= WarmUpPeriod) && (2 * _referenceReturns.Samples >= WarmUpPeriod); /// /// Creates a new Beta indicator with the specified name, target, reference, @@ -109,8 +109,7 @@ public class Beta : BarIndicator, IIndicatorWarmUpPeriodProvider /// The target symbol of this indicator /// The period of this indicator /// The reference symbol of this indicator - /// The resolution - public Beta(string name, Symbol targetSymbol, Symbol referenceSymbol, int period, Resolution resolution = Resolution.Daily) + public Beta(string name, Symbol targetSymbol, Symbol referenceSymbol, int period) : base(name) { // Assert the period is greater than two, otherwise the beta can not be computed @@ -119,12 +118,7 @@ public Beta(string name, Symbol targetSymbol, Symbol referenceSymbol, int period throw new ArgumentException($"Period parameter for Beta indicator must be greater than 2 but was {period}."); } - if (resolution == Resolution.Tick) - { - throw new ArgumentException($"Resolution parameter for Beta indicator must be greater than Tick."); - } - - WarmUpPeriod = period; + WarmUpPeriod = 2 * period; _referenceSymbol = referenceSymbol; _targetSymbol = targetSymbol; @@ -140,7 +134,6 @@ public Beta(string name, Symbol targetSymbol, Symbol referenceSymbol, int period _referenceTimeZone = MarketHoursDatabase.FromDataFolder() .GetExchangeHours(_referenceSymbol.ID.Market, _referenceSymbol, _referenceSymbol.ID.SecurityType).TimeZone; _isTimezoneDifferent = _targetTimeZone != _referenceTimeZone; - _resolution = resolution; } /// @@ -150,9 +143,8 @@ public Beta(string name, Symbol targetSymbol, Symbol referenceSymbol, int period /// The target symbol of this indicator /// The period of this indicator /// The reference symbol of this indicator - /// The resolution - public Beta(Symbol targetSymbol, Symbol referenceSymbol, int period, Resolution resolution = Resolution.Daily) - : this($"B({period})", targetSymbol, referenceSymbol, period, resolution) + public Beta(Symbol targetSymbol, Symbol referenceSymbol, int period) + : this($"B({period})", targetSymbol, referenceSymbol, period) { } @@ -191,6 +183,8 @@ protected override decimal ComputeNextValue(IBaseDataBar input) if (_previousInput == null) { _previousInput = input; + var timeDifference = input.EndTime - input.Time; + _resolution = timeDifference.TotalHours > 1 ? Resolution.Daily : timeDifference.ToHigherResolutionEquivalent(false); return decimal.Zero; } diff --git a/Tests/Indicators/BetaIndicatorTests.cs b/Tests/Indicators/BetaIndicatorTests.cs index 437442868687..e7a5c81b58b4 100644 --- a/Tests/Indicators/BetaIndicatorTests.cs +++ b/Tests/Indicators/BetaIndicatorTests.cs @@ -205,18 +205,18 @@ public void ValidateBetaCalculation() var values = new List() { - new TradeBar() { Symbol = Symbols.AAPL, Low = 1, High = 2, Volume = 100, Close = 10, Time = _reference.AddDays(1) }, - new TradeBar() { Symbol = Symbols.SPX, Low = 1, High = 2, Volume = 100, Close = 35, Time = _reference.AddDays(1) }, - new TradeBar() { Symbol = Symbols.AAPL, Low = 1, High = 2, Volume = 100, Close = 2, Time = _reference.AddDays(2) }, - new TradeBar() { Symbol = Symbols.AAPL, Low = 1, High = 2, Volume = 100, Close = 2, Time = _reference.AddDays(2) }, - new TradeBar() { Symbol = Symbols.AAPL, Low = 1, High = 2, Volume = 100, Close = 15, Time = _reference.AddDays(3) }, - new TradeBar() { Symbol = Symbols.SPX, Low = 1, High = 2, Volume = 100, Close = 80, Time = _reference.AddDays(3) }, - new TradeBar() { Symbol = Symbols.SPX, Low = 1, High = 2, Volume = 100, Close = 4, Time = _reference.AddDays(4) }, - new TradeBar() { Symbol = Symbols.SPX, Low = 1, High = 2, Volume = 100, Close = 4, Time = _reference.AddDays(4) }, - new TradeBar() { Symbol = Symbols.SPX, Low = 1, High = 2, Volume = 100, Close = 37, Time = _reference.AddDays(5) }, - new TradeBar() { Symbol = Symbols.AAPL, Low = 1, High = 2, Volume = 100, Close = 90, Time = _reference.AddDays(5) }, - new TradeBar() { Symbol = Symbols.AAPL, Low = 1, High = 2, Volume = 100, Close = 105, Time = _reference.AddDays(6) }, - new TradeBar() { Symbol = Symbols.SPX, Low = 1, High = 2, Volume = 100, Close = 302, Time = _reference.AddDays(6) }, + new TradeBar() { Symbol = Symbols.AAPL, Low = 1, High = 2, Volume = 100, Close = 10, Time = _reference.AddDays(1), EndTime = _reference.AddDays(2) }, + new TradeBar() { Symbol = Symbols.SPX, Low = 1, High = 2, Volume = 100, Close = 35, Time = _reference.AddDays(1), EndTime = _reference.AddDays(2) }, + new TradeBar() { Symbol = Symbols.AAPL, Low = 1, High = 2, Volume = 100, Close = 2, Time = _reference.AddDays(2),EndTime = _reference.AddDays(3) }, + new TradeBar() { Symbol = Symbols.AAPL, Low = 1, High = 2, Volume = 100, Close = 2, Time = _reference.AddDays(2), EndTime = _reference.AddDays(3) }, + new TradeBar() { Symbol = Symbols.AAPL, Low = 1, High = 2, Volume = 100, Close = 15, Time = _reference.AddDays(3), EndTime = _reference.AddDays(4) }, + new TradeBar() { Symbol = Symbols.SPX, Low = 1, High = 2, Volume = 100, Close = 80, Time = _reference.AddDays(3), EndTime = _reference.AddDays(4) }, + new TradeBar() { Symbol = Symbols.SPX, Low = 1, High = 2, Volume = 100, Close = 4, Time = _reference.AddDays(4), EndTime = _reference.AddDays(5) }, + new TradeBar() { Symbol = Symbols.SPX, Low = 1, High = 2, Volume = 100, Close = 4, Time = _reference.AddDays(4), EndTime = _reference.AddDays(5) }, + new TradeBar() { Symbol = Symbols.SPX, Low = 1, High = 2, Volume = 100, Close = 37, Time = _reference.AddDays(5), EndTime = _reference.AddDays(6) }, + new TradeBar() { Symbol = Symbols.AAPL, Low = 1, High = 2, Volume = 100, Close = 90, Time = _reference.AddDays(5), EndTime = _reference.AddDays(6) }, + new TradeBar() { Symbol = Symbols.AAPL, Low = 1, High = 2, Volume = 100, Close = 105, Time = _reference.AddDays(6), EndTime = _reference.AddDays(7) }, + new TradeBar() { Symbol = Symbols.SPX, Low = 1, High = 2, Volume = 100, Close = 302, Time = _reference.AddDays(6), EndTime = _reference.AddDays(7) }, }; // Calculating beta manually using the formula: Beta = Covariance(AAPL, SPX) / Variance(SPX) @@ -249,8 +249,10 @@ public void BetaWithDifferentTimeZones() for (int i = 0; i < 10; i++) { - indicator.Update(new TradeBar() { Symbol = Symbols.SPY, Low = 1, High = 2, Volume = 100, Close = i + 1, Time = _reference.AddDays(1 + i) }); - indicator.Update(new TradeBar() { Symbol = Symbols.BTCUSD, Low = 1, High = 2, Volume = 100, Close = i + 1, Time = _reference.AddDays(1 + i) }); + var startTime = _reference.AddDays(1 + i); + var endTime = startTime.AddDays(1); + indicator.Update(new TradeBar() { Symbol = Symbols.SPY, Low = 1, High = 2, Volume = 100, Close = i + 1, Time = startTime, EndTime = endTime }); + indicator.Update(new TradeBar() { Symbol = Symbols.BTCUSD, Low = 1, High = 2, Volume = 100, Close = i + 1, Time = startTime, EndTime = endTime }); } Assert.AreEqual(1, (double)indicator.Current.Value); }