| Overall Statistics |
|
Total Trades
110
Average Win
3.04%
Average Loss
-3.47%
Compounding Annual Return
2.049%
Drawdown
33.200%
Expectancy
0.151
Net Profit
31.741%
Sharpe Ratio
0.199
Probabilistic Sharpe Ratio
0.057%
Loss Rate
39%
Win Rate
61%
Profit-Loss Ratio
0.87
Alpha
0.03
Beta
-0.055
Annual Standard Deviation
0.124
Annual Variance
0.015
Information Ratio
-0.349
Tracking Error
0.23
Treynor Ratio
-0.448
Total Fees
$778.13
Estimated Strategy Capacity
$16000000.00
Lowest Capacity Asset
XLK RGRPZX100F39
|
# https://quantpedia.com/strategies/riding-industry-bubbles/
#
# The investment universe consists of equity industry funds (or ETFs) which are proxy for equity industry indexes. Investor uses 10 years of
# past data to calculate industry’s alpha based on CAPM model (from the regression model industry_return = alpha + beta*market return, it is
# possible to use alternative models like the Fama/French 3 factor model). A bubble in an industry is detected if the industry’s alpha is
# statistically significant (source academic paper uses 97,5% significance threshold, but it is possible to use other values). Investor is
# long in each industry experiencing a bubble by applying 1/N rule (investment is divided equally between industries in bubble). If no bubble
# is detected then he/she makes no investment. Data examination, alpha calculation and portfolio rebalancing is done on monthly basis.
#
# QC Implementation:
import numpy as np
import statsmodels.api as sm
class RidingIndustryBubbles(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2008, 1, 1)
self.SetCash(100000)
self.spy = 'SPY'
self.symbols = ['XLF', 'XLV', 'XLP', 'XLY', 'XLI', 'XLE', 'XLB', 'XLK', 'XLU']
self.period = 10 * 12 * 21
self.SetWarmUp(self.period)
# Daily price data.
self.data = {}
for symbol in self.symbols + [self.spy]:
data = self.AddEquity(symbol, Resolution.Daily)
self.data[symbol] = RollingWindow[float](self.period)
self.Schedule.On(self.DateRules.MonthStart(self.symbols[0]), self.TimeRules.AfterMarketOpen(self.symbols[0]), self.Rebalance)
def OnData(self, data):
# Store daily price data.
for symbol in self.symbols + [self.spy]:
symbol_obj = self.Symbol(symbol)
if symbol_obj in data and data[symbol_obj]:
self.data[symbol].Add(data[symbol_obj].Value)
def Rebalance(self):
if not self.data[self.spy].IsReady: return
market_closes = [x for x in self.data[self.spy]]
separete_months = [market_closes[x:x+21] for x in range(0, len(market_closes),21)]
market_monthly_returns = []
for month in separete_months:
month_of_prices = [x for x in month]
market_monthly_returns.append(month_of_prices[0] / month_of_prices[-1] - 1)
# Prepared for regression.
market_monthly_returns = np.array(market_monthly_returns).T
market_monthly_returns = sm.add_constant(market_monthly_returns)
t_stat = {}
for symbol in self.symbols:
if self.data[symbol].IsReady:
closes = [x for x in self.data[symbol]]
separete_months = [closes[x:x+21] for x in range(0, len(closes),21)]
etf_monthly_returns = []
for month in separete_months:
month_of_prices = [x for x in month]
etf_monthly_returns.append(month_of_prices[0] / month_of_prices[-1] - 1)
# alpha t-stat calc.
model = sm.OLS(etf_monthly_returns, market_monthly_returns)
results = model.fit()
alpha_tstat = results.tvalues[0]
alpha_pvalue = results.pvalues[0]
t_stat[symbol] = (alpha_tstat, alpha_pvalue)
long = []
if len(t_stat) != 0:
long = [x[0] for x in t_stat.items() if x[1][0] >= 2 and x[1][1] >= 0.025] # The result is statistically significant, by the standards of the study, when p ≤ α
# Trade execution.
invested = [x.Key.Value for x in self.Portfolio if x.Value.Invested]
for symbol in invested:
if symbol not in long:
self.Liquidate(symbol)
for symbol in long:
self.SetHoldings(symbol, 1 / len(long))