Overall Statistics
Total Trades
184
Average Win
0.40%
Average Loss
-0.26%
Compounding Annual Return
4.129%
Drawdown
2.100%
Expectancy
0.079
Net Profit
1.880%
Sharpe Ratio
0.73
Probabilistic Sharpe Ratio
41.196%
Loss Rate
58%
Win Rate
42%
Profit-Loss Ratio
1.54
Alpha
0
Beta
0
Annual Standard Deviation
0.058
Annual Variance
0.003
Information Ratio
0.73
Tracking Error
0.058
Treynor Ratio
0
Total Fees
$164.00
import clr
clr.AddReference("System")
clr.AddReference("QuantConnect.Algorithm")
clr.AddReference("QuantConnect.Indicators")
clr.AddReference("QuantConnect.Common")
import numpy as np
from System import *
from QuantConnect import *
from QuantConnect.Algorithm import *
from QuantConnect.Indicators import *
from QuantConnect.Securities.Option import OptionPriceModels
from datetime import datetime, timedelta 
import decimal as d





class EODOptions(QCAlgorithm):

    def Initialize(self):
        
        self.SetStartDate(2020, 8, 1) # Set Start Date
        self.SetEndDate(2021, 1, 19) # Set End Date
        self.SetCash(30000) # Set Strategy Cash
        self.spy = self.AddEquity("SPY", Resolution.Minute)
        self.spy.SetDataNormalizationMode(DataNormalizationMode.Raw)        
        self.SetBrokerageModel(BrokerageName.InteractiveBrokersBrokerage)

        options = self.AddOption("SPY")     
        options.SetFilter(lambda universe: universe.IncludeWeeklys().Strikes(-3, 3).Expiration(timedelta(1), timedelta(3)))
        #Pricemodel for Options
        options.PriceModel = OptionPriceModels.CrankNicolsonFD()
        # set the warm-up period for the pricing model
        self.SetWarmUp(TimeSpan.FromDays(6))
        # set the benchmark to be the initial cash
        self.SetBenchmark(lambda x: 30000)

#####Execution model
    def OnData(self, data):
        underlying_symbol = "SPY"
        
        if not data.Bars.ContainsKey("SPY"): return         
        
##########Sell 2nd Candle of Day
        if data.Time.hour == 9 and data.Time.minute == 32:            
            self.Liquidate()

##########Buy the next closest expiry that isn't today at the EOD
        if data.Time.hour == 15 and data.Time.minute == 58:            

            contract_call_symbol = self.OptionsFilter (underlying_symbol, 1, OptionRight.Call)
            if contract_call_symbol is None:
                return
    
            self.MarketOrder(contract_call_symbol.Symbol, 1)
            
###########Options Selection    
    def OptionsFilter(self, underlying_symbol, expiry_days, option_right):
        for kvp in self.CurrentSlice.OptionChains:
            chain = kvp.Value
            key = kvp.Key # which chain it is
            contracts = [i for i in chain]
            if len(contracts) == 0: continue
            contracts_filtered_for_right = [i for i in contracts if i.Right == option_right]
            
            Greater_than_one_dollar = [i for i in contracts_filtered_for_right if (i.AskPrice + i.BidPrice)/2 > .25 and (i.AskPrice + i.BidPrice)/2 < 1.75]
            if len(Greater_than_one_dollar) == 0: return
            
            desired_expiration = self.Time + timedelta(days = expiry_days)
            
            at_least_one_day_out = [i for i in Greater_than_one_dollar if desired_expiration < i.Expiry]
            closest_expiry = sorted(at_least_one_day_out, key=lambda c : abs(c.Expiry - desired_expiration), reverse=False)
            if len(closest_expiry) == 0: return
            
            closest_expiry_date = closest_expiry[0].Expiry
            contracts_with_desired_expiry = [i for i in Greater_than_one_dollar if i.Expiry == closest_expiry_date]
            if len(contracts_with_desired_expiry) == 0: return
            Sorted_by_Highest_leverage = sorted(contracts_with_desired_expiry, key=lambda x: x.Greeks.Gamma, reverse = True)
            if len(Sorted_by_Highest_leverage) == 0: return
            if len(Sorted_by_Highest_leverage) > 0:
                contract = Sorted_by_Highest_leverage[0]                
            return contract