Overall Statistics
Total Trades
1664
Average Win
0.00%
Average Loss
0.00%
Compounding Annual Return
-0.436%
Drawdown
0.700%
Expectancy
-0.544
Net Profit
-0.438%
Sharpe Ratio
-0.733
Probabilistic Sharpe Ratio
1.936%
Loss Rate
77%
Win Rate
23%
Profit-Loss Ratio
1.01
Alpha
-0.003
Beta
-0.001
Annual Standard Deviation
0.004
Annual Variance
0
Information Ratio
-0.157
Tracking Error
0.128
Treynor Ratio
3.761
Total Fees
$0.00
Estimated Strategy Capacity
$0
Lowest Capacity Asset
SPX W6IHW13YA7VY|SPX 31
# region imports
from AlgorithmImports import *
import typing


# endregion


def get_contract_by_delta(contracts: typing.List[OptionContract], delta) -> OptionContract:
    contracts = sorted(contracts, key=lambda x: x.Strike)
    contract = min(contracts, key=lambda x: abs(x.Greeks.Delta - delta))
    return contract


class CryingFluorescentPinkCaribou(QCAlgorithm):
    spx_symbol: Symbol
    option_symbol: Symbol

    def Initialize(self):
        self.SetStartDate(2015, 1, 1)
        self.SetEndDate(2016, 1, 1)
        self.SetCash(int(50e6))

        index = self.AddIndex('SPX', Resolution.Daily)
        index.VolatilityModel = StandardDeviationOfReturnsVolatilityModel(30)
        self.spx_symbol = index.Symbol
        self.SetWarmup(30, Resolution.Daily)

        option = self.AddIndexOption(self.spx_symbol, Resolution.Daily)
        # ofu: OptionFilterUniverse
        option.SetFilter(
            lambda ofu: ofu.Strikes(10, 60).Expiration(0, 90).CallsOnly().OnlyApplyFilterAtMarketOpen()
        )

        option.PriceModel = OptionPriceModels.BlackScholes()
        self.option_symbol = option.Symbol

    def OnData(self, data: Slice):
        if self.IsWarmingUp:
            return
        chain = data.OptionChains.get(self.option_symbol)
        if not chain:
            return
        unique_expiry = list(set([s.Expiry for s in chain]))
        for expiry in unique_expiry:
            contracts = [s for s in chain if s.Right == OptionRight.Call and s.Expiry == expiry]
            long_call = get_contract_by_delta(contracts, 0.30)
            short_call = get_contract_by_delta(contracts, 0.20)
            if long_call.Strike == short_call.Strike:
                # Probably Greeks are not properly computed
                # self.Debug(f"{self.Time}: {expiry} has wrong greeks. Skipping.")
                continue
            spread = OptionStrategies.BullCallSpread(self.option_symbol, long_call.Strike, short_call.Strike, expiry)
            self.Buy(spread, 1)
            self.log(long_call, short_call)

    def log(self, long: OptionContract, short: OptionContract):
        assert long.Expiry == short.Expiry
        expiry = long.Expiry.strftime("%Y%m%d")
        self.Debug(f"{self.Time} {expiry}C{long.Strike}/{short.Strike}")