多资产市场广度动量策略
登录后收藏学术论文
Protective Asset Allocation (PAA): A Simple Momentum-Based Alternative for Term Deposits
保护性资产配置(PAA);一种基于简单动量的定期存款替代方案 [点击查看论文]
- NLVrije Universiteit Amsterdam
- ?VU University Amsterdam
- ?TrendXplorer
策略概要
该策略涉及12种跨不同资产类别的ETF:美国股票(SPY、QQQ、IWM)、全球股票(VGK、EWJ)、新兴市场(EEM)、另类资产(GSG、GLD、IYR)和债券(HYG、LQD、TLT、IEF)。资产基于12个月的动量指标(MOM > 0)进行选择。投资者使用保护因子2计算债券比例(BF)。选择动量为正的前6名资产作为风险投资组合。风险资产的比例计算为(1-BF)/BF,投资组合中的资产等权重。
II. 策略合理性
该策略在熊市期间提供比传统双重动量策略更高的保护,因为它倾向于将更高比例的资金转移到低风险资产中。因此,即使PAA策略在原始回报方面表现不如传统双重动量策略,它也往往能实现更好的风险特征,即显著更低的跌幅和标准差。
回测表现
波动率7.9%
夏普比率1
索提诺比率0.28
最大回撤-8.8%
胜率66%
完整 Python 代码
from AlgorithmImports import *
from collections import deque
class MultiAssetMarketBreadthMomentum(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2008, 1, 1)
self.SetCash(100_000)
self.symbols: List[str] = [
'SPY', 'QQQ', 'IWM', 'VGK', 'EWJ', 'EEM', 'GSG', 'GLD', 'IYR', 'HYG', 'LQD', 'TLT'
]
self.safe_bond: str = 'IEF'
period: int = 12 * 21
self.data: Dict[str, deque] = {}
self.sma: Dict[str, SimpleMovingAverage] = {}
for symbol in self.symbols:
self.AddEquity(symbol, Resolution.Daily)
self.data[symbol] = deque(maxlen = period)
self.sma[symbol] = self.SMA(symbol, period, Resolution.Daily)
history: DataFrame = self.History(self.Symbol(symbol), period, Resolution.Daily)
if not history.empty:
closes: Series = history.loc[symbol].close
for time, close in closes.items():
self.sma[symbol].Update(time, close)
self.AddEquity(self.safe_bond, Resolution.Daily)
self.last_month: int = -1
def OnData(self, slice: Slice) -> None:
if self.last_month == self.Time.month:
return
self.last_month = self.Time.month
mom: Dict[str, float] = {}
for symbol in self.symbols:
symbol_obj: Symbol = self.Symbol(symbol)
# SMA data is ready.
if self.sma[symbol].IsReady:
if symbol_obj in slice.Bars:
price: float = slice.Bars[symbol_obj].Value
if price != 0:
mom[symbol] = price / self.sma[symbol].Current.Value - 1
else:
return # Wait for every asset.
if len(mom) != 0:
# Bond fraction calc.
good_assets: List = sorted([x[0] for x in mom.items() if x[1] > 0], key = lambda x: x[1], reverse = True)[:6]
N: int = len(self.symbols)
n: int = len(good_assets)
a: int = 2
n1: float = a*N/4
BF: float = (N-n)/(N-n1)
bond_share: float = (1-BF)/BF
# Trade execution.
self.Liquidate()
# Risky part.
# "leverage" ratio in case there's two parts of portfolio - risky as well as safe part.
ratio: float = 0.5 if bond_share != 0 else 1
for symbol in good_assets:
self.SetHoldings(symbol, ratio * (1/n))
# Bond part.
self.SetHoldings(self.safe_bond, ratio * bond_share)