Overall Statistics
Total Trades
67
Average Win
1.32%
Average Loss
-2.43%
Compounding Annual Return
-86.205%
Drawdown
43.100%
Expectancy
-0.207
Net Profit
-26.074%
Sharpe Ratio
-1.162
Probabilistic Sharpe Ratio
6.655%
Loss Rate
49%
Win Rate
51%
Profit-Loss Ratio
0.54
Alpha
-1.071
Beta
3.198
Annual Standard Deviation
0.601
Annual Variance
0.361
Information Ratio
-1.558
Tracking Error
0.523
Treynor Ratio
-0.218
Total Fees
$63.00
Estimated Strategy Capacity
$13000000.00
Lowest Capacity Asset
TSLA 31KPPKCL1VV52|TSLA UNU3P8Y3WFAD
class SampleAlgo(QCAlgorithm):

    def Initialize(self):

        self.SetStartDate(2021, 1, 1)  # Set Start Date
        self.SetEndDate(2021, 2, 25)    # Set End Date et Strategy Cash
        self.SetCash(100000)           # Set Strategy Cash
        self.SetWarmUp(timedelta(1)) # Warm up technical indicators
        
        self.ticker = "TSLA"
        sym = self.AddEquity(self.ticker, Resolution.Minute).Symbol
        self.option = self.AddOption(self.ticker, Resolution.Minute)
        self.optionSymbol = self.option.Symbol
        self.option.SetFilter(self.UniverseFunc)
        self.option.PriceModel = OptionPriceModels.CrankNicolsonFD()
        
        self.open_contracts = list()
        
        self.trading_on = True
        self.currentContract = None
        
        self.Schedule.On(self.DateRules.EveryDay(self.ticker),self.TimeRules.At(10,20),self.sell_contract)
        self.Schedule.On(self.DateRules.EveryDay(self.ticker),self.TimeRules.BeforeMarketClose(self.ticker,20),self.CheckLiquidation)


    def sell_contract(self):

        slice = self.CurrentSlice
        otype='put'

        for i in slice.OptionChains:
            if i.Key != self.optionSymbol: 
                continue
            self.currentContract = self.get_calls_puts(i, otype=otype)
            if self.currentContract is None:
                self.Log('No suitable contract could be found for trading')
                return
            break
        
        if self.currentContract is not None:
            if self.currentContract.Symbol not in [x.Symbol for x in self.open_contracts]:
                
                self.Sell(self.currentContract.Symbol, 1)
                self.open_contracts.append(self.currentContract)

    def UniverseFunc(self, universe):
       # include weekly contracts
       return universe.IncludeWeeklys().Expiration(TimeSpan.FromDays(0),
                                                   TimeSpan.FromDays(30)).Strikes(-15,15)
        
    def get_calls_puts(self, kvp, otype):
        '''
        criteria = 'strike' means ATM options, 'delta' means delta equal to given parameter
        '''
        
        chain = kvp.Value
        
        if otype == 'call':        
            opts = [x for x in chain if x.Right == OptionRight.Call]
        else:
            opts = [x for x in chain if x.Right == OptionRight.Put]
        
        opts = sorted(opts, key = lambda x: x.Expiry)
        if len(opts) == 0: return
        opts = [x for x in opts if x.Expiry==opts[0].Expiry]

        opts = sorted(opts, key=lambda x: abs(x.Strike - self.Securities[self.ticker].Price))
        return opts[0] if len(opts)>0 else None
        
    def CheckLiquidation(self):
        
        to_be_removed = []
        for security in self.open_contracts:
            if self.Time.date() == security.Expiry.date():
                self.Liquidate(security.Symbol,tag='Closed twenty minutes before expiry')
                to_be_removed.append(security)
        
        for security in to_be_removed:
            self.open_contracts.remove(security)