Overall Statistics
Total Trades
105
Average Win
6.60%
Average Loss
-1.20%
Compounding Annual Return
47.653%
Drawdown
49.200%
Expectancy
3.740
Net Profit
609.746%
Sharpe Ratio
1.234
Probabilistic Sharpe Ratio
50.436%
Loss Rate
27%
Win Rate
73%
Profit-Loss Ratio
5.52
Alpha
0.213
Beta
1.796
Annual Standard Deviation
0.399
Annual Variance
0.159
Information Ratio
1.16
Tracking Error
0.29
Treynor Ratio
0.274
Total Fees
$639.75
Estimated Strategy Capacity
$0.0000000000000000000000000001
Lowest Capacity Asset
SPY XRX5OFMJ9L5Y|SPY R735QTJ8XC9X
from clr import AddReference
AddReference("System")
AddReference("QuantConnect.Algorithm")
AddReference("QuantConnect.Common")

from System import *
from QuantConnect import *
from QuantConnect.Algorithm import *
from datetime import timedelta
from QuantConnect.Securities.Option import OptionPriceModels

class DCAintoLEAPs(QCAlgorithm):

    def Initialize(self):
        self.SetStartDate(2016, 6, 1)
        self.SetEndDate(2021, 6, 10)
        self.SetWarmUp(90, Resolution.Daily)
        self.UniverseSettings.SetLeverage = 1
        self.num_buys = 24
        self.amt_per_txn = 500000//24

        self.SetCash(500000)
        self.AddEquity("SPY", Resolution.Daily)

        option = self.AddOption("SPY")
        option.PriceModel = OptionPriceModels.CrankNicolsonFD()
        self.option_symbol = option.Symbol
        # set our strike/expiry filter for this option chain
        option.SetFilter(self.UniverseFunc)

        # use the underlying equity as the benchmark
        self.SetBenchmark("SPY")
        
        self.contracts = None
        
        self.Schedule.On(self.DateRules.MonthStart("SPY"), self.TimeRules.AfterMarketOpen("SPY", 10), self.OnDataTrade)
        self.Schedule.On(self.DateRules.WeekStart("SPY"), self.TimeRules.AfterMarketOpen("SPY", 10), self.sell_expiring)


    def UniverseFunc(self, universe):
        return universe.IncludeWeeklys().Strikes(-100000, 100000).Expiration(timedelta(380), timedelta(545))


    def OnData(self,slice):
        if not (self.Time.hour == 9 and self.Time.minute == 38): return
        for kvp in slice.OptionChains:
            if kvp.Key != self.option_symbol: continue
            chain = kvp.Value
            chain = [x for x in chain if x.Right == OptionRight.Call and 380 <= (x.Expiry-self.Time).days <= 545]
            closest_expiry_beyond_1y = sorted(chain,key = lambda x: x.Expiry)[0].Expiry
            chain = [x for x in chain if x.Expiry == closest_expiry_beyond_1y]
            contracts = sorted(chain, key = lambda x: abs(x.Greeks.Delta-0.4))
            self.contracts = contracts
            
    def sell_expiring(self):
            # Sell calls that are expiring within a week
            leaps = [x.Key for x in self.Portfolio if x.Value.Invested and x.Value.Type==SecurityType.Option]
            for x in leaps:
                if (self.Securities[x].Expiry.date() - self.Time.date()).days <= 14:
                    self.Liquidate(x)
        
    def OnDataTrade(self):
            # Buy calls
            if len(self.contracts) == 0: pass
            symbol = self.contracts[0].Symbol
            self.MarketOrder(symbol, (self.amt_per_txn/100)//self.contracts[0].AskPrice)
            x = self.contracts[0]
            columns=['idx', 'type(call 0, put 1)', 'strike', 'expiry', 'ask price', 'bid price', 'delta', x.Symbol.Value,\
            x.Right,float(x.Strike),x.Expiry,float(x.BidPrice),float(x.AskPrice),float(x.Greeks.Delta)]
            self.Log(str(columns))


    def OnOrderEvent(self, orderEvent):
        self.Log(str(orderEvent))