Quant BuffetRelax, Not Over Thinking

Daily Box Office Earnings and Aggregate Stock Returns

Log in to collect

Academic paper

Is it Time for Popcorn? Daily Box Office Earnings and Aggregate Stock Returns

AuthorsSeda Oz; Steve Fortin

Institute
  • CAUniversity of Waterloo
  • ?University of Waterloo - School of Accounting and Finance

Strategy in a nutshell

Uses box office earnings growth to trade stocks. If weekly earnings rise >15%, go long; otherwise, go short. Leverages consumer sentiment as a short-term market signal.

Economic rationale

Box office reflects discretionary spending and GDP-linked consumption. Strong earnings indicate positive investor sentiment; weak earnings signal caution. Predictive effect lasts about 4 days, requiring high-turnover trading.

Backtest performance

Annualised return27.13%
Beta-0.363
Sortino ratio-1.486
Win rate31%

Full Python code

from AlgorithmImports import *
#endregion
class DailyBoxOfficeEarningsandAggregateStockReturns(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2010, 1, 1)
self.SetCash(100000)

self.symbol = self.AddEquity("SPY", Resolution.Daily).Symbol

# Daily box data indexed by date.
self.daily_box_data = {}

# Import daily box data.
# Data source: https://www.boxofficemojo.com/daily/2020/?view=year
daily_box_string_data = self.Download('data.quantpedia.com/backtesting_data/economic/daily_box_earnings.csv')
lines = daily_box_string_data.split('\r\n')
for line in lines[1:]:
    split_line = line.split(';')
    date = datetime.strptime(split_line[0], "%Y-%m-%d").date()
    
    if split_line[5] == '-':
        weekly_change = None
    else:
        weekly_change = float(split_line[5])
    
    self.daily_box_data[date] = weekly_change

def OnData(self, data):
date_to_lookup = (self.Time - timedelta(days = 1)).date()

if date_to_lookup in self.daily_box_data:
    weekly_change = self.daily_box_data[date_to_lookup]
    if weekly_change:
        if weekly_change > 15:
            self.SetHoldings(self.symbol, 1)
        else:
            self.SetHoldings(self.symbol, -1)
else:
    self.Liquidate()