diff --git a/Algorithm.CSharp/StatisticsResultsAlgorithm.cs b/Algorithm.CSharp/StatisticsResultsAlgorithm.cs index 51b01fab4d92..102127f5f9a0 100644 --- a/Algorithm.CSharp/StatisticsResultsAlgorithm.cs +++ b/Algorithm.CSharp/StatisticsResultsAlgorithm.cs @@ -32,6 +32,7 @@ public class StatisticsResultsAlgorithm : QCAlgorithm, IRegressionAlgorithmDefin { private const string MostTradedSecurityStatistic = "Most Traded Security"; private const string MostTradedSecurityTradeCountStatistic = "Most Traded Security Trade Count"; + private const string InitializeStatistic = "Initialize Statistic"; private Symbol _spy; @@ -61,6 +62,9 @@ public override void Initialize() _fastIbmEma = EMA(_spy, 10, Resolution.Minute); _slowIbmEma = EMA(_spy, 30, Resolution.Minute); + + // Custom summary statistics can also be set during initialization + SetSummaryStatistic(InitializeStatistic, 1); } public override void OnData(Slice slice) @@ -152,6 +156,10 @@ public override void OnEndOfAlgorithm() { throw new RegressionTestException($"Statistic {MostTradedSecurityTradeCountStatistic} should be in the summary statistics"); } + if (!statistics.TryGetValue(InitializeStatistic, out var initializeStatistic) || initializeStatistic != "1") + { + throw new RegressionTestException($"Statistic {InitializeStatistic} set during initialization should be in the summary statistics"); + } var mostTradeSecurityKvp = _tradeCounts.MaxBy(kvp => kvp.Value); CheckMostTradedSecurityStatistic(statistics, mostTradeSecurityKvp.Key, mostTradeSecurityKvp.Value); } diff --git a/Algorithm.Python/StatisticsResultsAlgorithm.py b/Algorithm.Python/StatisticsResultsAlgorithm.py index 44da587710e0..b2b6f8817499 100644 --- a/Algorithm.Python/StatisticsResultsAlgorithm.py +++ b/Algorithm.Python/StatisticsResultsAlgorithm.py @@ -22,6 +22,7 @@ class StatisticsResultsAlgorithm(QCAlgorithm): most_traded_security_statistic = "Most Traded Security" most_traded_security_trade_count_statistic = "Most Traded Security Trade Count" + initialize_statistic = "Initialize Statistic" def initialize(self): self.set_start_date(2013, 10, 7) @@ -39,6 +40,9 @@ def initialize(self): self.trade_counts = {self.spy: 0, self.ibm: 0} + # Custom summary statistics can also be set during initialization + self.set_summary_statistic(StatisticsResultsAlgorithm.initialize_statistic, 1) + def on_data(self, data: Slice): if not self.slow_spy_ema.is_ready: return @@ -97,6 +101,8 @@ def on_end_of_algorithm(self): raise AssertionError(f"Statistic {StatisticsResultsAlgorithm.most_traded_security_statistic} should be in the summary statistics") if StatisticsResultsAlgorithm.most_traded_security_trade_count_statistic not in statistics: raise AssertionError(f"Statistic {StatisticsResultsAlgorithm.most_traded_security_trade_count_statistic} should be in the summary statistics") + if StatisticsResultsAlgorithm.initialize_statistic not in statistics or statistics[StatisticsResultsAlgorithm.initialize_statistic] != "1": + raise AssertionError(f"Statistic {StatisticsResultsAlgorithm.initialize_statistic} set during initialization should be in the summary statistics") most_trade_security, most_trade_security_trade_count = self.get_most_trade_security() self.check_most_traded_security_statistic(statistics, most_trade_security, most_trade_security_trade_count) diff --git a/Algorithm/QCAlgorithm.Plotting.cs b/Algorithm/QCAlgorithm.Plotting.cs index a8c68999dd4b..beb974539379 100644 --- a/Algorithm/QCAlgorithm.Plotting.cs +++ b/Algorithm/QCAlgorithm.Plotting.cs @@ -503,6 +503,14 @@ public void SetSummaryStatistic(string name, string value) throw new ArgumentException($"'{name}' is a reserved statistic name."); } + if (_statisticsService == null) + { + // the statistics service is attached after Initialize, keep the statistic until then + _pendingSummaryStatistics ??= new(); + _pendingSummaryStatistics[name] = value; + return; + } + _statisticsService.SetSummaryStatistic(name, value); } diff --git a/Algorithm/QCAlgorithm.cs b/Algorithm/QCAlgorithm.cs index d6987b6c1fcc..b820cfe31f1b 100644 --- a/Algorithm/QCAlgorithm.cs +++ b/Algorithm/QCAlgorithm.cs @@ -121,6 +121,8 @@ public partial class QCAlgorithm : MarshalByRefObject, IAlgorithm private ConcurrentQueue _logMessages = new ConcurrentQueue(); private ConcurrentQueue _errorMessages = new ConcurrentQueue(); private IStatisticsService _statisticsService; + // summary statistics set before the statistics service is attached, e.g. during Initialize + private Dictionary _pendingSummaryStatistics; private IBrokerageModel _brokerageModel; private bool _sentBroadcastCommandsDisabled; @@ -3914,6 +3916,15 @@ public void SetStatisticsService(IStatisticsService statisticsService) if (_statisticsService == null) { _statisticsService = statisticsService; + + if (_pendingSummaryStatistics != null) + { + foreach (var (name, value) in _pendingSummaryStatistics) + { + _statisticsService.SetSummaryStatistic(name, value); + } + _pendingSummaryStatistics = null; + } } }