Overall Statistics |
Total Orders 67 Average Win 8.55% Average Loss -2.79% Compounding Annual Return 10.838% Drawdown 25.100% Expectancy -0.137 Start Equity 1000000 End Equity 2784559.38 Net Profit 178.456% Sharpe Ratio 0.584 Sortino Ratio 0.661 Probabilistic Sharpe Ratio 20.158% Loss Rate 79% Win Rate 21% Profit-Loss Ratio 3.07 Alpha 0.013 Beta 0.538 Annual Standard Deviation 0.097 Annual Variance 0.009 Information Ratio -0.271 Tracking Error 0.089 Treynor Ratio 0.106 Total Fees $1905.75 Estimated Strategy Capacity $68000000.00 Lowest Capacity Asset SPY R735QTJ8XC9X Portfolio Turnover 0.06% |
# region imports from AlgorithmImports import * from datetime import timedelta # endregion class HipsterOrangeCrocodile(QCAlgorithm): def initialize(self): self.set_start_date(2015, 1, 1) self.set_cash(1000000) self.equity = self.add_equity("SPY", Resolution.Minute) self.equity.set_data_normalization_mode(DataNormalizationMode.Raw) self.symbol = self.equity.symbol self.set_benchmark("SPY") self.vix = self.add_index("VIX").symbol self.rank = 0 self.contract = str() self.contracts_added = set() self.days_before_exp = 2 self.dte = 25 self.otm = 0.01 self.lookback_iv = 150 self.iv_lvl = 0.5 self.percentage = 0.9 self.options_alloc = 90 self.schedule.on(self.date_rules.every_day(self.symbol), self.time_rules.after_market_open(self.symbol, 30), self.plotting) self.schedule.on(self.date_rules.every_day(self.symbol), self.time_rules.after_market_open(self.symbol, 30), self.vix_rank) self.set_warm_up(timedelta(self.lookback_iv)) def vix_rank(self): history = self.history(TradeBar, self.vix, self.lookback_iv, Resolution.Daily) self.rank = ((self.Securities[self.vix].Price - min(history["low"])) / (max(history["high"]) - min(history["low"]))) def on_data(self, data: Slice): if self.is_warming_up: return if not self.portfolio[self.symbol].invested: self.set_holdings(self.symbol, self.percentage) if self.rank > self.iv_lvl: self.buy_put(data) if self.contract: if self.contract.ID.date - self.time <= timedelta(self.days_before_exp): self.liquidate(self.contract) self.log("Closed: too close to expiration") self.contract = str() def buy_put(self, data: Slice): if self.contract == str(): self.contract = self.options_filter(data) self.log(f"Option filter done. contract={self.contract}") return elif not self.portfolio[self.contract].invested and data.contains_key(self.contract): qty = round(self.portfolio[self.symbol].quantity / self.options_alloc) self.log(f"Buying option contract {self.contract} - qty={qty}") self.buy(self.contract, qty) else: self.log(f"Got contract and get to buy option {self.contract}") def options_filter(self, data: Slice): contracts = self.option_chain_provider.get_option_contract_list(self.symbol, data.time) self.underlying_price = self.securities[self.symbol].price otm_puts = [i for i in contracts if i.ID.option_right == OptionRight.PUT and self.underlying_price - i.ID.strike_price > self.otm * self.underlying_price and self.dte - 8 < (i.ID.date - data.time).days < self.dte + 8 ] if len(otm_puts) > 0: contract = sorted( sorted(otm_puts, key = lambda x: abs((x.ID.date - self.time).days - self.dte)), key= lambda x:self.underlying_price - x.ID.strike_price )[0] if contract not in self.contracts_added: self.contracts_added.add(contract) self.add_option_contract(contract, Resolution.MINUTE) return contract return str() def plotting(self): self.plot("Vol Chart", "Rank", self.rank) self.plot("Vol Chart", "lvl", self.iv_lvl) self.plot("Data chart", self.symbol, self.securities[self.symbol].close) option_invested = [x.key for x in self.portfolio if x.value.invested and x.value.type == SecurityType.OPTION] if option_invested: self.plot("Data Chart", "Strike", option_invested[0].ID.strike_price) def on_order_event(self, order_event): self.log(str(order_event))