Overall Statistics
Total Trades
223
Average Win
0.47%
Average Loss
-0.90%
Compounding Annual Return
4.201%
Drawdown
27.600%
Expectancy
0.425
Net Profit
50.959%
Sharpe Ratio
0.371
Probabilistic Sharpe Ratio
1.854%
Loss Rate
6%
Win Rate
94%
Profit-Loss Ratio
0.52
Alpha
0.051
Beta
0.003
Annual Standard Deviation
0.134
Annual Variance
0.018
Information Ratio
0.845
Tracking Error
0.586
Treynor Ratio
14.487
Total Fees
$18702.00
from QuantConnect.Securities.Option import OptionPriceModels
from datetime import timedelta


class HorizontalDynamicCoil(QCAlgorithm):

    def Initialize(self):
        self.SetStartDate(2011, 1, 1)  # Set Start Date
        self.SetCash(1000000)  # Set Strategy Cash
        
        self.SQQQOption = self.AddOption("SQQQ")
        self.SQQQOption.PriceModel = OptionPriceModels.CrankNicolsonFD()
        self.SQQQOption.SetFilter(-50, 0, timedelta(8), timedelta(15))
        self.SQQQOption.SetLeverage(100)
        
        
        # self.TMVOption = self.AddOption("TMV")
        # self.TMVOption.PriceModel = OptionPriceModels.CrankNicolsonFD()
        # self.TMVOption.SetFilter(-50, 0, timedelta(5), timedelta(15))
        
        
        self.LongOption = self.ShortOption = False
        self.NumContracts = 0
        
        self.SetBenchmark('SQQQ')
        
        self.long_delta = float(self.GetParameter("long_delta"))
        self.short_delta = float(self.GetParameter("short_delta"))
        self.DefaultOrderProperties.TimeInForce = TimeInForce.Day

    def OnData(self, data):
        if self.Time.hour == 15 and self.Time.minute == 30:
            option_invested = [x for x in self.Portfolio if x.Value.Invested and x.Value.Type==SecurityType.Option]
            equity_invested = [x.Key for x in self.Portfolio if x.Value.Invested and x.Value.Type!=SecurityType.Option]
            
            if len(equity_invested) > 0:
                self.Debug(equity_invested[0])
                self.Liquidate(equity_invested[0])
                
            if len(option_invested) < 2:
                self.LongOption = self.ShortOption = False
                for option in option_invested:
               
                    if int(option.Value.IsLong) == 1:
                        if (option.Key.ID.Date - self.Time).days < 128:
                            self.Debug(f'Closed {-option.Value.Quantity} contracts Strike {option.Key.ID.StrikePrice} Underlying {self.Securities[option.Key.ID.Underlying.Symbol].Price} {self.Time}')
                            self.MarketOrder(option.Key, -option.Value.Quantity)
                        else:
                            self.LongOption = True
                            
                    elif int(option.Value.IsLong) == 0:
                        if (option.Key.ID.Date - self.Time).days < 1 and (option.Key.ID.StrikePrice > self.Securities[option.Key.ID.Underlying.Symbol].Price):
                            self.Debug(f'Closed {-option.Value.Quantity} contracts Strike {option.Key.ID.StrikePrice} Underlying {self.Securities[option.Key.ID.Underlying.Symbol].Price} {self.Time}')
                            self.MarketOrder(option.Key, -option.Value.Quantity)
                        else:
                            self.ShortOption = True
                    
                            
                
                if self.ShortOption is False:
                    self.ShortOptions(data) 
                # if self.LongOption is False:
                #     self.LongOptions(data)
                # self.CalendarSpread(data)
                # self.LongOptions(data)
            
            
    def CalendarSpread(self, data):
        for i in data.OptionChains:
            
            chain = i.Value
            # filter the call options contracts
            puts = [x for x in chain if x.Right == OptionRight.Put] 
                
            if self.LongOption is False:
                long_contract = sorted(sorted(puts, 
                
                                              key = lambda x: abs(x.Greeks.Delta - self.long_delta)), 
                                              key = lambda x: x.Expiry, reverse=True)[0]
                                              
                if abs(long_contract.Greeks.Delta - self.long_delta) < 0.1: 
                    mid_price = (long_contract.AskPrice + long_contract.BidPrice) / 2
                    self.NumContracts = int(100000 / 100.0 / mid_price)
                    self.MarketOrder(long_contract.Symbol, self.NumContracts)
                    self.Debug(f'Num contracts {self.NumContracts} Mid Price {mid_price:.2f} Strike {long_contract.Strike} Underlying {long_contract.UnderlyingLastPrice} Delta {long_contract.Greeks.Delta} TTE {long_contract.Expiry - self.Time} Expiry {long_contract.Expiry}')

            if self.ShortOption is False:
                
                short_contract = sorted(sorted(puts, 
                                        key = lambda x: abs(x.Greeks.Delta - self.short_delta)), 
                                        key = lambda x: x.Expiry)[0]
                if (short_contract.Expiry - self.Time).days <= 7 and abs(short_contract.Greeks.Delta - self.short_delta) < 0.049:
                    self.MarketOrder(short_contract.Symbol, -self.NumContracts)
                    mid_price = (short_contract.AskPrice + short_contract.BidPrice) / 2
                    self.Debug(f'Num contracts {self.NumContracts} Mid Price {mid_price:.2f} Strike {short_contract.Strike} Underlying {short_contract.UnderlyingLastPrice} Delta {short_contract.Greeks.Delta} TTE {short_contract.Expiry - self.Time} Expiry {short_contract.Expiry}')

            
    def ShortOptions(self, data):
        for i in data.OptionChains:
            
            chain = i.Value
            # filter the call options contracts
            puts = [x for x in chain if x.Right == OptionRight.Put] 
            
            # puts = [put for put in puts ]
            # sorted the contracts according to their expiration dates and choose the ATM options
            short_contract = sorted(sorted(puts, 
                                        key = lambda x: abs(x.Greeks.Delta - self.short_delta)), 
                                        # key = lambda x: abs((x.Strike - x.UnderlyingLastPrice) / x.Strike + 0.1)), 
                                        key = lambda x: x.Expiry)[0]
                                             
            TTE = short_contract.Expiry - self.Time
            if abs(short_contract.Greeks.Delta - self.short_delta) > 0.049 or TTE.days >= 15: return
            # TTE = short_contract.Expiry - self.Time
            # if TTE.days >= 8 or TTE.days <= 3: return
            
            
            mid_price = (short_contract.AskPrice + short_contract.BidPrice) / 2
            
            num_contracts = int(1000000 / 100.0 / short_contract.Strike)
            self.Debug(f'Num contracts {num_contracts} Mid Price {mid_price:.2f} Strike {short_contract.Strike} Underlying {short_contract.UnderlyingLastPrice} Delta {short_contract.Greeks.Delta} TTE {TTE} Expiry {short_contract.Expiry}')
            # self.LimitOrder(short_contract.Symbol, -num_contracts, mid_price)
            self.MarketOrder(short_contract.Symbol, -num_contracts)
            
    def LongOptions(self, data):
        for i in data.OptionChains:
            
            chain = i.Value
            # filter the call options contracts
            puts = [x for x in chain if x.Right == OptionRight.Put] 
            
            # sorted the contracts according to their expiration dates and choose the ATM options
            long_contract = sorted(sorted(puts, 
                                        # key = lambda x: abs((x.Strike - x.UnderlyingLastPrice) / x.Strike + 0.2)), 
                                        key = lambda x: abs(x.Greeks.Delta - self.long_delta)), 
                                        key = lambda x: x.Expiry, reverse=True)[0]
                                            
                                        
            
            if abs(long_contract.Greeks.Delta - self.long_delta) > 0.1: return
            
            mid_price = (long_contract.AskPrice + long_contract.BidPrice) / 2
            
            num_contracts = int(100000 / 100.0 / mid_price)
            self.Debug(f'Num contracts {num_contracts} Mid Price {mid_price} Strike {long_contract.Strike} Underlying {long_contract.UnderlyingLastPrice} Delta {long_contract.Greeks.Delta} TTE {long_contract.Expiry - self.Time} Expiry {long_contract.Expiry}')
            # self.LimitOrder(self.put, -num_contracts, mid_price)
            self.MarketOrder(long_contract.Symbol, num_contracts)