Overall Statistics |
Total Orders 7563 Average Win 0.50% Average Loss -0.30% Compounding Annual Return 5.212% Drawdown 24.000% Expectancy 0.062 Start Equity 100000 End Equity 173982.72 Net Profit 73.983% Sharpe Ratio 0.183 Sortino Ratio 0.201 Probabilistic Sharpe Ratio 0.366% Loss Rate 60% Win Rate 40% Profit-Loss Ratio 1.67 Alpha -0.007 Beta 0.392 Annual Standard Deviation 0.137 Annual Variance 0.019 Information Ratio -0.366 Tracking Error 0.152 Treynor Ratio 0.064 Total Fees $0.00 Estimated Strategy Capacity $1100000.00 Lowest Capacity Asset SHY SGNKIKYGE9NP Portfolio Turnover 189.50% |
# region imports from AlgorithmImports import * # endregion class KellyCriterionSMACrossoverAlgorithm(QCAlgorithm): def initialize(self): self.set_start_date(2014, 1, 1) # Remove fees to focus the research on the portfolio weighting, not the signal. self.set_security_initializer(lambda s: s.set_fee_model(ConstantFeeModel(0))) # Add the risky and risk-free assets. self._risk_asset = self.add_equity('IBM', Resolution.HOUR, leverage=6) self._rf_asset = self.add_equity('SHY', Resolution.HOUR, leverage=6) # Add some strategy-specific indicators/variables. self._risk_asset.short_sma = self.sma(self._risk_asset.symbol, 1) self._risk_asset.long_sma = self.sma(self._risk_asset.symbol, 6) # Add a warm-up period so we some historical performance of the strategy once we start trading. self.set_warm_up(timedelta(365)) # Add a list and Scheduled Event to track the average exposure to the risky asset. self._risky_weights = [] self.schedule.on(self.date_rules.every_day(self._risk_asset.symbol), self.time_rules.at(23, 59), self._sample_weight) def on_data(self, data: Slice): # Wait until the market is open. if not data.bars or not self.is_market_open(self._risk_asset.symbol) or self.is_warming_up: return if not self._risk_asset.holdings.is_long and self._risk_asset.short_sma > self._risk_asset.long_sma: self.set_holdings([PortfolioTarget(self._risk_asset.symbol, 1)], True) elif self._risk_asset.holdings.is_long and self._risk_asset.short_sma < self._risk_asset.long_sma: self.set_holdings([PortfolioTarget(self._rf_asset.symbol, 1)], True) def _sample_weight(self): self._risky_weights.append(self._risk_asset.holdings.holdings_value / self.portfolio.total_portfolio_value) def on_end_of_algorithm(self): self.log(f"Average weight: {sum(self._risky_weights) / len(self._risky_weights)}")