Backtest Period
Markets Traded
Equities / Options
Maximum Drawdown
Period of Rebalancing
Daily
Return (Annual)
Sharpe Ratio
Standard Deviation (Annual)
Original paper
SSRN-id2398223.pdf2469.4KB
Trading rules
- Focus on S&P 100 index stocks for investment universe
- Utilize options on individual stocks and the index itself
- Rely on analyst EPS forecasts from I/B/E/S database
- Calculate mean absolute difference for each firm, scaled by earnings uncertainty (refer to source paper for methodology)
- Sort stocks into quintiles monthly based on belief disagreement
- Buy stocks with highest belief disagreement
- Sell index put as an equally-weighted portfolio of 1-month index put options
- Use Black-Scholes deltas ranging from -0.8 to -0.2 for index put options
Python code
Backtrader
import backtrader as bt
import numpy as np
import pandas as pd
from scipy.stats import norm
class DispersionTradingStrategy(bt.Strategy):
def __init__(self):
self.sorted_data = None
def next(self):
if self.data.datetime.date(ago=0).month != self.data.datetime.date(ago=1).month:
self.sorted_data = self.sort_quintiles_by_disagreement()
self.adjust_positions()
def sort_quintiles_by_disagreement(self):
stocks_data = pd.DataFrame()
for d in self.datas:
if "SP100" not in d._name:
stocks_data[d._name] = d.array("eps_forecasts")
stocks_data['belief_disagreement'] = self.calculate_belief_disagreement(stocks_data)
sorted_stocks = stocks_data.sort_values(by='belief_disagreement', ascending=False)
return sorted_stocks
def calculate_belief_disagreement(self, stocks_data):
# Implement the methodology to calculate the mean absolute difference for each firm,
# scaled by earnings uncertainty as per the source paper.
return belief_disagreement
def adjust_positions(self):
highest_disagreement_stocks = self.sorted_data.head(int(len(self.sorted_data) / 5))
for d in self.datas:
if "SP100" in d._name:
self.sell_index_put(d)
elif d._name in highest_disagreement_stocks.index:
self.buy_stock(d)
def buy_stock(self, data):
size = self.broker.getvalue() * 0.2 / data.close[0]
self.order_target_size(data, size)
def sell_index_put(self, data):
# Implement the logic for selling index put options using Black-Scholes deltas ranging from -0.8 to -0.2.
class DispersionTrading(bt.Cerebro):
def __init__(self):
super().__init__()
def run_strategy(self):
# Load and preprocess data, including options and EPS forecasts from I/B/E/S database.
# Add stocks and index data to the strategy.
self.addstrategy(DispersionTradingStrategy)
self.run()
if __name__ == '__main__':
dispersion_trading = DispersionTrading()
dispersion_trading.run_strategy()
Note: This code provides a template for implementing the Dispersion Trading strategy using Backtrader. You’ll need to fill in the actual calculations for belief disagreement and selling index put options based on the paper’s methodology, as well as loading and preprocessing the necessary data.