Statistics
Algorithm Statistics
Introduction
The StatisticsResults
object tracks all the statistics of your algorithm. You can access the statistics anywhere in your algorithm where you have a reference to the algorithm class. Some of these statistics are a function of the risk free interest rate and the number of trading days per year.
Get Values
To get the StatisticsResults
, use the statistics
member of the algorithm class.
sharpe = self.statistics.total_performance.portfolio_statistics.sharpe_ratio
To get the value of a custom statistic while your algorithm runs, index the summary
member with the statistic name. The values in the summary
dictionary are strings, so you may need to cast the value that returns to a different data type.
value = self.statistics.summary["name"]
The following table describe other ways to get the statistics after your backtest completes:
Deployment Target | Access Tools |
---|---|
QuantConnect Cloud |
|
Local |
|
Examples
The following examples demonstrate common practices for getting algorithm statistics.
Example 1: Portfolio Statistics
To evaluate the algorithm's best domain or regime, we can log the portfolio statistics daily along the backtest to analyze. To do so, we log the Sharpe Ratio, Beta, and 95% Value-at-Risk at the end of each day, storing them in the object store for assessment later.
class AlgorithmStatisticsAlgorithm(QCAlgorithm): _statistics = ["Time,Sharpe,Beta,95VaR"] def initialize(self) -> None: self.set_start_date(2024, 8, 12) self.set_end_date(2024, 9, 1) self.set_cash(1000000) # Request SPY data to trade. self.spy = self.add_equity("SPY").symbol # Create an EMA indicator to generate trade signals. self._ema = self.ema(self.spy, 20, Resolution.DAILY) # Warm-up indicator for immediate readiness. self.warm_up_indicator(self.spy, self._ema, Resolution.DAILY) def on_data(self, slice: Slice) -> None: bar = slice.bars.get(self.spy) if bar: # Trend-following strategy using price above or below EMA. # If the price is above EMA, SPY is in an uptrend, and we buy it. if bar.close > self._ema.current.value and not self.portfolio[self.spy].is_long: self.set_holdings(self.spy, 1) elif bar.close < self._ema.current.value and not self.portfolio[self.spy].is_short: self.set_holdings(self.spy, -1) def on_end_of_day(self, symbol: Symbol) -> None: # Obtain the algorithm statistics interested. sharpe = self.statistics.total_performance.portfolio_statistics.sharpe_ratio b = self.statistics.total_performance.portfolio_statistics.beta var = self.statistics.total_performance.portfolio_statistics.value_at_risk_95 # Plot the statistics. self.plot("Statistics", "Sharpe", sharpe) self.plot("Statistics", "Beta", b) self.plot("Statistics", "Value-at-Risk", var) # Write to save the statistics. self._statistics.append(f'{self.time.strftime("%Y%m%d")},{sharpe},{b},{var}') def on_end_of_algorithm(self) -> None: # Save the logged statistics for later access in the object store. self.object_store.save(f'{self.project_id}/algorithm-statistics', '\n'.join(self._statistics))
Other Examples
For more examples, see the following algorithms: