| Overall Statistics |
|
Total Orders 105 Average Win 1.03% Average Loss 0% Compounding Annual Return 12.411% Drawdown 15.200% Expectancy -0.074 Start Equity 1000000 End Equity 1794725.3 Net Profit 79.473% Sharpe Ratio 0.625 Sortino Ratio 0.507 Probabilistic Sharpe Ratio 40.237% Loss Rate 7% Win Rate 93% Profit-Loss Ratio 0 Alpha 0.017 Beta 0.467 Annual Standard Deviation 0.092 Annual Variance 0.009 Information Ratio -0.301 Tracking Error 0.1 Treynor Ratio 0.124 Total Fees $1370.20 Estimated Strategy Capacity $0 Lowest Capacity Asset SPY R735QTJ8XC9X Portfolio Turnover 0.35% |
# region imports
from AlgorithmImports import *
# endregion
## https://www.quantconnect.com/research/17871/automating-the-wheel-strategy/p1
## https://www.quantconnect.cloud/backtest/a6f2b22108f0edb0ee48ae660393565b
class WheelStrategyAlgorithm(QCAlgorithm):
def initialize(self):
self.set_start_date(2020, 6, 1)
self.set_cash(1_000_000)
self.set_security_initializer(BrokerageModelSecurityInitializer(self.brokerage_model, FuncSecuritySeeder(self.get_last_known_prices)))
self._equity = self.add_equity("SPY", data_normalization_mode=DataNormalizationMode.Raw)
self._otm_threshold = 0.05 # 5%
def _get_target_contract(self, right, target_price):
contract_symbols = self.option_chain_provider.get_option_contract_list(self._equity.symbol, self.time)
expiry = min([s.id.date for s in contract_symbols if s.id.date.date() > self.time.date() + timedelta(30)])
filtered_symbols = [
s for s in contract_symbols
if (s.id.date == expiry and s.id.option_right == right and
(s.id.strike_price <= target_price if right == OptionRight.PUT else s.id.strike_price >= target_price))
]
symbol = sorted(filtered_symbols, key=lambda s: s.id.strike_price, reverse=right == OptionRight.PUT)[0]
self.add_option_contract(symbol)
return symbol
def on_data(self, data):
if not self.portfolio.invested and self.is_market_open(self._equity.symbol):
symbol = self._get_target_contract(OptionRight.PUT, self._equity.price * (1-self._otm_threshold))
self.set_holdings(symbol, -0.2)
elif [self._equity.symbol] == [symbol for symbol, holding in self.portfolio.items() if holding.invested]:
symbol = self._get_target_contract(OptionRight.CALL, self._equity.price * (1+self._otm_threshold))
self.market_order(symbol, -self._equity.holdings.quantity / 100)