Overall Statistics |
Total Orders 238 Average Win 0.00% Average Loss -0.01% Compounding Annual Return -0.170% Drawdown 1.000% Expectancy -0.487 Start Equity 1000000 End Equity 991520.1 Net Profit -0.848% Sharpe Ratio -5.589 Sortino Ratio -3.692 Probabilistic Sharpe Ratio 0.029% Loss Rate 60% Win Rate 40% Profit-Loss Ratio 0.29 Alpha -0.025 Beta 0.004 Annual Standard Deviation 0.004 Annual Variance 0 Information Ratio -0.717 Tracking Error 0.173 Treynor Ratio -6.19 Total Fees $293.93 Estimated Strategy Capacity $0 Lowest Capacity Asset VX YHPO8JXZLPT5 Portfolio Turnover 0.14% |
# region imports from AlgorithmImports import * # endregion class StrategyTwoSellPutAndHedge(QCAlgorithm): def initialize(self): self.set_start_date(2019, 6, 1) self.set_end_date(2024, 6, 1) self.set_cash(1000000) self.set_warmup(timedelta(100)) self.settings.daily_precise_end_time = True # Initialize asset data immediately. self.set_security_initializer(BrokerageModelSecurityInitializer(self.brokerage_model, FuncSecuritySeeder(self.get_last_known_prices))) # Adds the VIX chain # The default mapping mode for the continous contract is OPEN_INTEREST, but we will set it explicitly # The default data normalization mode for the continous contract is RAW, but we will set it explicitly # For other options, see https://www.quantconnect.com/docs/v2/writing-algorithms/universes/futures#12-Continous-Contracts self.future = self.add_future(Futures.Indices.VIX, # SP_500_E_MINI # VIX extended_market_hours=False, data_mapping_mode=DataMappingMode.OPEN_INTEREST, data_normalization_mode=DataNormalizationMode.RAW) # We don't have VIX Future Options data; but used VIX Cash Options as a hedge instead vix = self.add_index("VIX").symbol self.index_option_symbol = Symbol.create_canonical_option(vix, "VIXW", Market.USA, "?VIXW") self.mapped_future = None self.schedule.on(self.date_rules.every_day(self.future.symbol), self.time_rules.after_market_open(self.future.symbol, 5), self.trade) def trade(self): if self.is_warming_up: self.mapped_future = self.future.mapped return # Contract is rolling. if self.future.mapped != self.mapped_future: #Clean up open positions in old future and old hedge. self.liquidate() # Open short in old VIX future contract that is no longer mapped self.market_order(self.mapped_future, -1) self.mapped_future = self.future.mapped # Refresh our hedge option_contract_list = self.option_chain_provider.get_option_contract_list(self.index_option_symbol, self.time) # Price of the VIX Index: underlying_price = self.securities[self.index_option_symbol.underlying].price # Find right expiry date close to 90 days expiry = min(option_contract_list, key=lambda symbol: abs((symbol.id.date - self.time).days - 90)).id.date # Filter the strike prices on above expiry. calls = filter(lambda symbol: symbol.id.option_right == OptionRight.CALL and symbol.id.date == expiry and symbol.id.strike_price > underlying_price, option_contract_list) # Add the contract to calculate the delta deltas_by_symbol = {} for call in calls: put = Symbol.create_option(call.id.underlying.symbol, "VIXW", call.id.market, call.id.option_style, OptionRight.PUT, call.id.strike_price, call.id.date) deltas = self.indicator_history(Delta(option=call, mirror_option=put), [call, put, call.Underlying], 24, Resolution.HOUR) if deltas.count == 0: continue deltas_by_symbol[call] = list(deltas)[-1].current.value call = sorted(deltas_by_symbol.items(), key=lambda x: abs(x[1]-.10))[0][0] self.add_option_contract(call) self.market_order(call, -1, tag=f'Delta={deltas_by_symbol[call]:.3f}')