book
Checkout our new book! Hands on AI Trading with Python, QuantConnect, and AWS Learn More arrow

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.

Properties

The StatisticsResults object has the following properties:

Add Statistics

To add custom statistics to the StatisticsResults object, call the set_summary_statistic method with the statistic name and value.

Select Language:
self.set_summary_statistic("name", value)

Get Values

To get the StatisticsResults, use the statistics member of the algorithm class.

Select Language:
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.

Select Language:
value = self.statistics.summary["name"]

The following table describe other ways to get the statistics after your backtest completes:

Deployment TargetAccess 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.

Select Language:
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:

You can also see our Videos. You can also get in touch with us via Discord.

Did you find this page helpful?

Contribute to the documentation: