Overall Statistics |
Total Orders 11 Average Win 0.15% Average Loss 0% Compounding Annual Return 16.665% Drawdown 2.800% Expectancy 0 Start Equity 100000 End Equity 108017.84 Net Profit 8.018% Sharpe Ratio 1.324 Sortino Ratio 1.616 Probabilistic Sharpe Ratio 88.489% Loss Rate 0% Win Rate 100% Profit-Loss Ratio 0 Alpha -0.026 Beta 0.498 Annual Standard Deviation 0.044 Annual Variance 0.002 Information Ratio -2.485 Tracking Error 0.045 Treynor Ratio 0.118 Total Fees $1.00 Estimated Strategy Capacity $110000000.00 Lowest Capacity Asset SPXW 32JQ5BIPGEQ7I|SPX 31 Portfolio Turnover 0.26% |
# region imports from AlgorithmImports import * # endregion class StrategyTwoSellPutAndHedge(QCAlgorithm): def initialize(self): self.set_start_date(2024, 1, 1) self.set_end_date(2024, 7, 1) self.set_cash(100000) self.set_security_initializer(BrokerageModelSecurityInitializer(self.brokerage_model, FuncSecuritySeeder(self.get_last_known_prices))) # Adds the SPXW options. # The (-10,10, 30, 30) filter means we will get 10 strikes below and above ATM # which should include the 10-delta put options, 30 days out. spx = self.add_index("SPX").symbol self.index_option_symbol = Symbol.create_canonical_option(spx, "SPXW", Market.USA, "?SPXW") # We will hedge the short puts with SPY self.hedge = self.add_equity("SPY").symbol # We will check for trades every day, so we open new trades after the option expires self.schedule.on(self.date_rules.month_start(spx), self.time_rules.after_market_open(spx, 1), self.trade) def trade(self): # Get all the contracts available for the day option_contract_list = self.option_chain_provider.get_option_contract_list(self.index_option_symbol, self.time) # Filter the OTM puts with expiry to one month expiry = min(option_contract_list, key=lambda symbol: abs((symbol.id.date - self.time).days - 30)).id.date underlying_price = self.securities[self.index_option_symbol.underlying].price puts = filter(lambda symbol: symbol.id.option_right == OptionRight.PUT and symbol.id.date == expiry and symbol.id.strike_price < underlying_price, option_contract_list) deltas = {} risk_free_rate = self.risk_free_interest_rate_model.GetInterestRate(self.time) for put in puts: call = Symbol.create_option(put.underlying, Market.USA, put.id.option_style, OptionRight.CALL, put.id.strike_price, expiry) delta = Delta(put, risk_free_rate, 0, call) history = self.history[TradeBar]([put, call], 10, Resolution.DAILY) for bars in history: for symbol, bar in bars.items(): delta.update(IndicatorDataPoint(symbol, bar.end_time, bar.close)) deltas[put] = delta.current.value # Get the put closest to 10 put = sorted(deltas.items(), key=lambda x: abs(x[1]+.10))[0][0] # Sell the put and buy the hedge if we don' have it self.add_option_contract(put) self.market_order(put, -1, tag=f'Delta={deltas[put]:.3f}') if not self.portfolio[self.hedge].invested: self.market_order(self.hedge, 100) # Remove the subcriptions we don«'t need for symbol, _ in deltas.items(): if symbol == put: continue self.remove_option_contract(symbol)