Overall Statistics
Total Orders
466
Average Win
0.27%
Average Loss
-0.20%
Compounding Annual Return
0.899%
Drawdown
8.000%
Expectancy
0.121
Start Equity
1000000
End Equity
1080199
Net Profit
8.020%
Sharpe Ratio
-0.533
Sortino Ratio
-0.287
Probabilistic Sharpe Ratio
0.364%
Loss Rate
53%
Win Rate
47%
Profit-Loss Ratio
1.36
Alpha
-0.025
Beta
0.106
Annual Standard Deviation
0.029
Annual Variance
0.001
Information Ratio
-0.735
Tracking Error
0.136
Treynor Ratio
-0.147
Total Fees
$0.00
Estimated Strategy Capacity
$10000.00
Lowest Capacity Asset
SPX 32L3DOV2BROMM|SPX 31
Portfolio Turnover
0.11%
# region imports
from AlgorithmImports import *
# endregion


class VolatilityTradingOptionAlgorithm(QCAlgorithm):

    def initialize(self):
        self.set_start_date(2016, 1, 1)
        self.set_cash(1_000_000)
        self.settings.automatic_indicator_warm_up = True

        self._vix = self.add_index('VIX')
        self._vix.std = self.std(self._vix.symbol, 24*21, resolution=Resolution.DAILY)
        self._vix.sma = self.sma(self._vix.symbol, 24*21, resolution=Resolution.DAILY)
        self._spx = self.add_index_option('SPX')
        self._spx.set_filter(lambda universe: universe.straddle(30))

        self.schedule.on(self.date_rules.every_day(self._spx.symbol), self.time_rules.after_market_open(self._spx.symbol, 30), self._trade)

    def _trade(self):        
        z_score = (self._vix.price - self._vix.sma.current.value) / self._vix.std.current.value
        quantity = -int(z_score) 
        if quantity == 0:
            self.liquidate()
        elif not self.portfolio.invested:
            chain = self.current_slice.option_chains.get(self._spx.symbol, None)
            if not chain: return
            chain = [c for c in chain if c.expiry > self.time]
            expiry = min([x.expiry for x in chain])
            strike = sorted([c for c in chain if c.expiry == expiry], key=lambda x: abs(x.strike - self._spx.price))[0].strike
            strategy = OptionStrategies.straddle(self._spx.symbol, strike, expiry)
            self.order(strategy, quantity)

    def on_order_event(self, order_event):
        if order_event.status == OrderStatus.FILLED and order_event.is_assignment:
            self.liquidate()