Overall Statistics
Total Trades
79
Average Win
2.60%
Average Loss
-2.54%
Compounding Annual Return
1.895%
Drawdown
2.400%
Expectancy
0.038
Net Profit
1.921%
Sharpe Ratio
0.591
Probabilistic Sharpe Ratio
32.704%
Loss Rate
49%
Win Rate
51%
Profit-Loss Ratio
1.02
Alpha
0.009
Beta
0.019
Annual Standard Deviation
0.033
Annual Variance
0.001
Information Ratio
-1.515
Tracking Error
0.35
Treynor Ratio
1.005
Total Fees
$98.75
from QuantConnect.Securities.Option import OptionPriceModels
from datetime import timedelta
class OptionsAlgorithm(QCAlgorithm):

    def Initialize(self):
        self.SetStartDate(2020, 1, 1)
        #self.SetEndDate(2020, 3, 1)
        self.SetCash(100000)
        
        self.shortDelta = 0.70
        self.longDelta = 0.80
        
        self.equity = self.AddEquity("QQQ", Resolution.Minute)
        option = self.AddOption("QQQ", Resolution.Minute)
        self.symbol = option.Symbol
        
        option.SetFilter(self.UniverseFunc)
        option.PriceModel = OptionPriceModels.CrankNicolsonFD()
        self.SetWarmUp(TimeSpan.FromDays(7))
        self.SetBenchmark(self.equity.Symbol)
        
        self.ema8 = self.EMA(self.equity.Symbol, 8, Resolution.Daily)
        self.sma21 = self.SMA(self.equity.Symbol, 21, Resolution.Daily)
        self.ema21 = self.EMA(self.equity.Symbol, 21, Resolution.Daily)
        self.sma50 = self.SMA(self.equity.Symbol, 50, Resolution.Daily)
        #self.ema50 = self.EMA(self.equity.Symbol, 50, Resolution.Daily)
        #self.sma200 = self.SMA(self.equity.Symbol, 200, Resolution.Daily)

        
        self.SetWarmUp(timedelta(350))

        
        #self.Schedule.On(self.DateRules.EveryDay(), self.TimeRules.AfterMarketOpen(self.equity.Symbol, 120),
        #    self.calculate_signal)
        self.Schedule.On(self.DateRules.EveryDay(), self.TimeRules.AfterMarketOpen(self.equity.Symbol, 30), self.report_portfolio)
        self.Schedule.On(self.DateRules.EveryDay(), self.TimeRules.AfterMarketOpen(self.equity.Symbol, 45), self.CheckForExpiry)

    def CheckForExpiry(self):
        if self.Portfolio.Invested and self.expirydate.date() == self.Time.date():
            self.Liquidate()
            self.Debug(f"Normal End Date: {self.Time}, TotalPortfolioValue: {self.Portfolio.TotalPortfolioValue}")

    def report_portfolio(self):
        if self.Portfolio.Invested: 
            #self.Debug(f"TotalPortfolioValue: {self.Portfolio.TotalPortfolioValue}, TotalMarginUsed: {self.Portfolio.TotalMarginUsed}, MarginRemaining: {self.Portfolio.MarginRemaining}, Cash:  {self.Portfolio.Cash}")
            #shortProfit = 0
            #longProfit = 0
            for key in sorted(self.Portfolio.keys()):

                if self.Portfolio[key].Quantity > 0.0 or self.Portfolio[key].Quantity < 0.0:
                    #if self.Portfolio[key].Quantity > 0.0:
                    #    longProfit = self.Portfolio[key].UnrealizedProfitPercent
                    #if self.Portfolio[key].Quantity < 0.0:
                    #    shortProfit = self.Portfolio[key].UnrealizedProfit                        
                    #self.Debug(f"Symbol/Qty: {key} / {self.Portfolio[key].Quantity}, Avg: {self.Portfolio[key].AveragePrice}, Curr: { self.Portfolio[key].Price}, Profit($): {self.Portfolio[key].UnrealizedProfit}")
                    if key == self.equity.Symbol:
                        self.Liquidate(key)
            #if longProfit + shortProfit != 0:            
                #self.Debug(f"Date/Expiry/Profit: {self.Time}, {self.expirydate}, {longProfit + shortProfit}")
            return

    def OnData(self,slice):
        if not self.ema8.IsReady: return
        if not self.sma21.IsReady: return
        if not self.ema21.IsReady: return
        if not self.sma50.IsReady: return
        #if not self.ema50.IsReady: return
        #if not self.sma200.IsReady: return
        
        self.allChecksPassed = False
        
        if(self.Time.hour == 10 and self.Time.minute == 30):
            if slice.ContainsKey(self.equity.Symbol) and slice[self.equity.Symbol]:
                if self.ema8.Current.Value > self.sma21.Current.Value and self.ema21.Current.Value > self.sma50.Current.Value:
                    if not self.Portfolio.Invested: 
                        #if self.ema8.Current.Value > self.sma21.Current.Value and self.ema21.Current.Value > self.sma50.Current.Value and self.ema50.Current.Value >  self.sma200.Current.Value:
                        #self.Debug(str(self.Time))
                        #self.Debug(f"equity:{slice[self.equity.Symbol].High} ema8:{self.ema8.Current.Value} sma21:{self.sma21.Current.Value} ema21:{self.ema21.Current.Value} sma50:{self.sma50.Current.Value}")
                        self.shortContract = None
                        self.longContract = None
                        for kvp in slice.OptionChains:
                            if kvp.Key != self.symbol: continue
                            chain = kvp.Value
                            contracts = [i for i in chain]
                            if len(contracts) == 0: continue
                            contracts = sorted(contracts, key=lambda x: (x.Expiry, x.Greeks.Delta))
                            self.shortContract = min(contracts, key=lambda x: abs(x.Greeks.Delta-self.shortDelta))
                            self.longContract = min([c for c in contracts if c.Expiry==self.shortContract.Expiry], key=lambda x: abs(x.Greeks.Delta-self.longDelta))
                            #self.Debug(str(self.Time))
                            #self.Debug(f"equity:{slice[self.equity.Symbol].High} ema8:{self.ema8.Current.Value} sma21:{self.sma21.Current.Value} ema21:{self.ema21.Current.Value} sma50:{self.sma50.Current.Value}")
                            self.Debug(f"Start Date: {self.Time}, TotalPortfolioValue: {self.Portfolio.TotalPortfolioValue}")
                            self.Debug(f"Short Strike: {self.shortContract.Strike} Expiry: {self.shortContract.Expiry} Delta: {self.shortContract.Greeks.Delta}")
                            self.Debug(f"Long Strike: {self.longContract.Strike} Expiry: {self.longContract.Expiry} Delta: {self.longContract.Greeks.Delta}")
                            #self.Debug(f"Short Strike: {self.shortContract.Strike}")
                            #self.Debug(f"Long Strike: {self.longContract.Strike}")
                            #self.Debug("Delta: " + str([i.Greeks.Delta for i in contracts]))
                            if self.shortContract != self.longContract:
                                pass
                                self.allChecksPassed = True
                                self.Sell(self.shortContract.Symbol, 5)
                                self.Buy(self.longContract.Symbol, 5)
                                self.expirydate = self.longContract.Expiry
                                break
                else:
                    if self.Portfolio.Invested:
                        self.Liquidate()
                        self.Debug(f"Signal End Date: {self.Time}, TotalPortfolioValue: {self.Portfolio.TotalPortfolioValue}")
                    
    #def calculate_signal(self):
    #    if self.allChecksPassed and not self.Portfolio.Invested:
    #        self.Buy(longContract.Symbol, 1)
    #        self.Sell(shortContract.Symbol, 1)
            
    def UniverseFunc(self, universe):
       # include weekly contracts
       return universe.IncludeWeeklys().Expiration(TimeSpan.FromDays(8),
                                                   TimeSpan.FromDays(8)).Strikes(-40, 40)
    
    #def OnOrderEvent(self, orderEvent):
    #    self.Debug(str(orderEvent))