| 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))