The strategy sells liquid S&P 500 put options on expiration Fridays, excluding those with low volume, holds equally-weighted positions over the weekend, and closes them the following Monday.

I. STRATEGY IN A NUTSHELL

The strategy involves selling liquid S&P 500 Index put options with at least 100 contracts traded over the past five days. Positions are opened every expiration Friday (third Friday of the month) and closed after the weekend (Monday or next trading day).

II. ECONOMIC RATIONALE

The negative weekend returns of options may arise from higher nontrading risk, heightened aversion to unlimited downside, and persistent market mispricing. Traders often overlook nontrading periods, causing inconsistent time decay and exploitable inefficiencies.

III. SOURCE PAPER

Option Mispricing Around Nontrading Periods [Click to Open PDF]

Jones, Shemesh

<Abstract>

We find that option returns are significantly lower over nontrading periods, the vast majority of which are weekends. Our evidence suggests that nontrading returns cannot be explained by risk, but are rather the result of widespread and highly persistent option mispricing driven by the incorrect treatment of non-smoothness in stock return variance. The size of the effect implies that the broad spectrum of finance research involving option prices should account for nontrading effects and non-smoothness in variance more generally. Our study further suggests how alternative industry practices could improve the effciency of option markets in a meaningful way.

IV. BACKTEST PERFORMANCE

Annualised Return21.26%
VolatilityN/A
Beta0.008
Sharpe RatioN/A
Sortino Ratio-0.505
Maximum DrawdownN/A
Win Rate55%

V. FULL PYTHON CODE

from AlgorithmImports import *
class TradingOptionsDuringExpirationWeekends(QCAlgorithm):
    def Initialize(self):
        self.SetStartDate(2011, 1, 1)
        self.SetCash(100000)
        
        self.symbol = self.AddEquity("SPY", Resolution.Minute).Symbol
        
        # Next expiry date.
        self.expiry_date = None
        
        option = self.AddOption("SPY", Resolution.Minute)
        option.SetFilter(-20, 20, 25, 35)
        self.Schedule.On(self.DateRules.EveryDay(self.symbol), self.TimeRules.AfterMarketOpen(self.symbol, 1), self.Close)
        
    def OnData(self, slice):
        # Open new trades only on market close.
        if not (self.Time.hour == 15 and self.Time.minute == 59):
            return
        
        if self.expiry_date:
            if self.Time.date() < self.expiry_date.date(): 
                return
            
        for i in slice.OptionChains:
            chains = i.Value
            if not self.Portfolio.Invested:
                puts = list(filter(lambda x: x.Right == OptionRight.Put, chains))
                if not puts: return
            
                underlying_price = self.Securities[self.symbol].Price
                expiries = [i.Expiry for i in puts]
                # Determine expiration date nearly one month.
                expiry = min(expiries, key=lambda x: abs((x.date()-self.Time.date()).days-30))
                strikes = [i.Strike for i in puts]
                # determine at-the-money strike
                strike = min(strikes, key=lambda x: abs(x-underlying_price))
                atm_put = [i for i in puts if i.Expiry == expiry and i.Strike == strike]
                if atm_put:
                    if not self.expiry_date:
                        self.expiry_date = atm_put[0].Expiry
                        return
                    
                    options_q = int(self.Portfolio.MarginRemaining / (underlying_price * 100))
                    if not (self.Time.month == 8 and self.Time.year == 2015):
                        self.Sell(atm_put[0].Symbol, options_q)
                        self.expiry_date = atm_put[0].Expiry
            
            if self.Portfolio.Invested:
                self.Liquidate(self.symbol)
                
    def Close(self):
        if self.Portfolio.Invested:
            self.Liquidate()

VI. Backtest Performance

Leave a Reply

Discover more from Quant Buffet

Subscribe now to keep reading and get access to the full archive.

Continue reading