Original paper
Abstract
We empirically analyze rational investors' optimal response to asset price bubbles. We define bubbles as a sudden acceleration of price growth beyond the growth in fundamental value given by an asset pricing model. Our new bubble detection method requires only a limited time-series of historical returns. We apply our method to US industries and find strong statistical and economic support for the riding bubbles hypothesis: when an investor detects a bubble, her optimal portfolio weight increases significantly. A dynamic riding bubble strategy that uses only real-time information earns abnormal annual returns of 3% to 8%.
Keywords:Â bubbles, limits to arbitrage, market efficiency, structural breaks
Trading rules
- Investment scope: Industry-specific equity funds (or ETFs) as proxies for equity industry indices.
- Use 10 years of historical data to derive industry alpha with the CAPM formula (though other methods like the Fama/French 3 factor approach are acceptable).
- Identify industry bubbles by looking for notably significant alphas (referenced academic paper suggests a 97.5% confidence level, but alternative levels can be applied).
- Long positions: Allocate funds to industries showing bubble tendencies using an equal distribution strategy across such industries.
- Don’t invest if no signs of bubbles are found.
- Monthly data examination, alpha calculation, and portfolio rebalancing.
Python code
Backtrader
import backtrader as bt
import pandas as pd
import numpy as np
import statsmodels.api as sm
from scipy import stats
class IndustryBubbleStrategy(bt.Strategy):
def __init__(self):
self.industries = self.datas
def next(self):
long_positions = []
significance_threshold = 0.975
for industry in self.industries:
prices = industry.get(size=120)
market_returns = prices / prices.shift(1) - 1
industry_returns = industry.get(size=120) / industry.get(size=120).shift(1) - 1
X = sm.add_constant(market_returns)
model = sm.OLS(industry_returns, X).fit()
alpha = model.params[0]
t_stat = model.tvalues[0]
p_value = model.pvalues[0]
if p_value < (1 - significance_threshold) and t_stat > 0:
long_positions.append(industry)
if long_positions:
position_size = 1 / len(long_positions)
for industry in long_positions:
self.order_target_percent(industry, target=position_size)
else:
for industry in self.industries:
self.order_target_percent(industry, target=0.0)
if __name__ == "__main__":
cerebro = bt.Cerebro()
data = bt.feeds.PandasData(dataname=pd.DataFrame(), timeframe=bt.TimeFrame.Months)
for industry in industry_etfs:
cerebro.adddata(data)
cerebro.addstrategy(IndustryBubbleStrategy)
cerebro.run()
Please note that this code snippet assumes you have data for each industry ETF (or fund) in a variable called industry_etfs
. Replace it with the appropriate data source.