Overall Statistics
Total Trades
18
Average Win
0%
Average Loss
-0.15%
Compounding Annual Return
-2.381%
Drawdown
2.000%
Expectancy
-1
Net Profit
-1.064%
Sharpe Ratio
-1.25
Probabilistic Sharpe Ratio
6.511%
Loss Rate
100%
Win Rate
0%
Profit-Loss Ratio
0
Alpha
-0.036
Beta
0.041
Annual Standard Deviation
0.018
Annual Variance
0
Information Ratio
-2.698
Tracking Error
0.131
Treynor Ratio
-0.549
Total Fees
$5.50
Estimated Strategy Capacity
$35000000.00
Lowest Capacity Asset
TSLA XONZHCXLNOTI|TSLA UNU3P8Y3WFAD
from QuantConnect.Securities.Option import OptionPriceModels
from datetime import timedelta
import math

class Wheelinginthemoney(QCAlgorithm):

    def sort(self,option_contract):
        #This function is to be used as the key from a sorted() function, it it used to take a list of options contracts and to create a key 
        #first split the Intrinsic and extrinsic value
        option_cost = option_contract.AskPrice
        return float(option_cost)
        
    def get_option_contract_for_option_holding(self, symbol):
        #this funtion takes an option holding as the input and returns an option contract so it can be used for analysis and rolling
        for chain in self.CurrentSlice.OptionChains.Values:
            for opt in chain:
                if opt.Symbol == symbol:
                    return opt
                    
    def AddStocks(self,ticker):
            equity = self.AddEquity(ticker, self.resolution) #Adding
            self.Securities[ticker].SetDataNormalizationMode(DataNormalizationMode.Raw)
            #option = self.AddOption(ticker, self.resolution) #Adding Options Chain
            #option.SetFilter(-0, +10, timedelta(382), timedelta(730))
            #option.PriceModel = OptionPriceModels.CrankNicolsonFD()  #Setting the option pricing models to calculate the Greeks
            return
                    
    def Initialize(self):
        
        self.SetStartDate(2021, 1, 1)
        self.SetEndDate(2021, 6,11)
        self.SetCash(1000000)
        self.resolution = Resolution.Minute
        self.stocks = ["TSLA","VTI","VOO","BRK.B","IVV"]
        self.sell_options = True
        self.sell_down_mode = False
        self.trade = True
        self.SetBrokerageModel(BrokerageName.AlphaStreams)
        
        for ticker in self.stocks:
            self.AddStocks(ticker)

        #assigns the first stock to a variable so it can be used in the date time scheduler
        self.symbol = self.stocks[0]
        
        self.SetWarmUp(7) 
                    
    def OnData(self,slice):
         
        if self.sell_options == False or self.IsWarmingUp or self.IsMarketOpen(self.symbol) == False: return
        
        #in case there are open orders still, we want to cancel them
        
        allCancelledOrders = self.Transactions.CancelOpenOrders()
        
        option_invested = []
        
        for x in self.ActiveSecurities:
            if x.Value.Invested and x.Value.Type == SecurityType.Option:
                option_invested.append(str(x.Value.Symbol.Underlying))
                if len(option_invested) == len(self.stocks):break
            
        option_invested_nodupes = list(dict.fromkeys(option_invested))
    
        #checks if we have options invested in all of the stocks in our self.stocks list, if so then we set self.sell_options to False to not check anything until the next scheduled increment, else buy options.
        #this is mainly for backtest performance
        if len(option_invested_nodupes) == len(self.stocks):
            self.sell_options = False
            return
            
        for x in self.stocks:
            if x not in option_invested_nodupes and self.sell_down_mode == False:
                self.buy_call(slice,x)

    def buy_call(self,slice,underlying):
            symbol = Symbol.Create(underlying, SecurityType.Equity, Market.USA)
            calloption_symbol = self.GetOption(slice,symbol,OptionRight.Call,self.Portfolio[underlying].Price,self.Portfolio[underlying].Price + 100,self.Time + timedelta(40),self.Time + timedelta(100),self.sort,False)
            if calloption_symbol is None: return
            calloption = self.Securities[calloption_symbol.Symbol]
            if calloption is None: return
            
            if len(self.stocks) == 0 or calloption.AskPrice == 0 or self.Portfolio.TotalPortfolioValue == 0 : return
            
            numberofcontracts = 1
            
            if numberofcontracts == 0:
                self.Debug("Not Enough funds to purchase " + str(underlying))
                return
            
            # Sell Put
            self.Log('Buying Call ' + str(calloption))
            #self.Debug(str(self.Securities[symbol].AskPrice))
            self.MarketOrder(calloption.Symbol, numberofcontracts)
            
    def OnOrderEvent(self, orderEvent):
        self.trade
        if orderEvent.Status != "Canceled" :
            self.Debug(orderEvent)
        
    def GetOption(self,slice,underlying,optionright,MinStrike,MaxStrike,MinExpiry,MaxExpiry,sortedfunction,reverse):
        contracts = self.OptionChainProvider.GetOptionContractList(underlying, self.Time)  ## Get list of Options Contracts for a specific time
        if len(contracts) == 0: return
    
        filtered_options = [x for x in contracts if   x.ID.OptionRight == optionright and\
                                                    x.ID.StrikePrice > MinStrike and\
                                                    x.ID.StrikePrice < MaxStrike and\
                                                    x.ID.Date > MinExpiry and\
                                                    x.ID.Date < MaxExpiry]
        
        if len(filtered_options) == 0: return
        added_contracts = []
        for x in filtered_options:
            option = self.AddOptionContract(x, Resolution.Minute)
            optionsymbol = self.Securities[option.Symbol]
            added_contracts.append(optionsymbol)
        
        sorted_options = sorted(added_contracts,key = sortedfunction, reverse = reverse)
        
        selected = sorted_options[0]
        
        for x in sorted_options:
            if x != selected:
                self.RemoveSecurity(x.Symbol)
        return selected