投资宇宙由可供单个投资者使用的证券组成,构建等权重的双动量模块化投资组合。四个模块包括:外国/美国股票(SPY、EFA)、高收益/信用债券(HYG、LQD)、股票/抵押REITs(MBB、VNQ)以及黄金/国债(TLT、GLD)。计算相对动量,选择表现更好的资产,若无正动量,则分配到国库券(BIL)。

策略概述

投资宇宙由之前提到的投资工具所跟随的证券组成,这些工具可供单个投资者使用。投资者构建仅做多、等权重的组合双动量模块化投资组合。

我们创建了以下四个模块:

  1. 外国/美国股票动量模块:MSCI美国和EAFE+股票市场指数,分别由SPY和EFA ETF代表;
  2. 高收益/信用债券风险模块:高收益债券和中级信用债券指数,分别由HYG和LQD ETF代表;
  3. 股票/抵押REITs模块:抵押和股票型房地产投资信托基金,分别由MBB和VNQ ETF代表;
  4. 黄金/国债模块:美国长期国债指数和实物黄金,分别由TLT和GLD ETF代表。

投资者首先计算这些模块中的相对动量——他们根据12个月的相对动量选择并购买表现更好的资产作为该模块的代表。假设模块中没有任何资产相对于国库券(即没有12个月的正绝对动量)有正动量,则将相应部分分配到国库券投资(使用BIL ETF)中作为投资组合的一部分。最终的投资组合在各模块之间应等权重分配,并每月重新平衡。

策略合理性

经济学家对为什么此类策略有效的根本原因感到困惑,学术界对此尚无共识。最被接受的解释来自行为金融学的逻辑,认为代理人并非理性行事,而是情绪化行事,受到多种偏差的影响。绝对动量决定趋势,并利用趋势的持续性,同时结合相对于某些表现较弱的资产类别的相对动量,使多元化更加高效。这种精心创建的投资组合旨在减轻特定风险因素,为投资者提供降低高波动性的同时,仍能获得可观的回报。

论文来源

Risk Premia Harvesting Through Dual Momentum [点击浏览原文]

<摘要>

动量是首要的市场异常,它几乎具有普遍适用性。本文探讨了多资产动量以及什么使其对动量投资者最有效。我们展示了绝对和相对动量都可以提高回报,但绝对动量在降低波动性和回撤方面作用更大。我们发现,将绝对动量和相对动量结合可以带来最佳效果。

回测表现

年化收益率14.9%
波动率13.93%
Beta0.218
夏普比率1.07
索提诺比率0.404
最大回撤-10.92%
胜率82%

完整python代码

from AlgorithmImports import *
#endregion

class AntonaccisDualMomentum(QCAlgorithm):

    def Initialize(self):
        self.SetStartDate(2000, 1, 1)  
        self.SetCash(100000)
        
        period:int = 12 * 21
        self.SetWarmUp(period, Resolution.Daily)

        self.treasury_bill:Symbol = self.AddEquity("BIL", Resolution.Daily).Symbol

        # subscribe assets for each module
        self.equities:List[Symbol] = [self.AddEquity(x, Resolution.Daily).Symbol for x in ["SPY", "EFA"]]
        self.bonds:List[Symbol] = [self.AddEquity(x, Resolution.Daily).Symbol for x in ["HYG", "LQD"]]
        self.reits:List[Symbol] = [self.AddEquity(x, Resolution.Daily).Symbol for x in ["MBB", "VNQ"]]
        self.commodities:List[Symbol] = [self.AddEquity(x, Resolution.Daily).Symbol for x in ["TLT", "GLD"]]

        # traded modules
        self.modules:List[List[Symbol]] = [self.equities, self.bonds, self.reits, self.commodities]

        self.momentum:dict[Symbol, RateOfChange] = {}

        self.momentum_treshold:float = 0.

        for module in self.modules:
            for asset in module:
                # subscribe ROC indicator
                self.momentum[asset] = self.ROC(asset, period, Resolution.Daily)

        self.recent_month:int = -1

    def OnData(self, data:Slice) -> None:
        if self.IsWarmingUp: return

        # monthly rebalance
        if self.Time.month == self.recent_month:
            return
        self.recent_month = self.Time.month
        
        tbill_allocation_count:int = 0
        long:List[Symbol] = []

        for module_index, module in enumerate(self.modules):
            if all(self.momentum[x].IsReady for x in module):
                # select and buy the better-performing asset as representative of the module
                module_perf_values:List[float] = [self.momentum[x].Current.Value for x in module]
                max_module_perf:float = max(module_perf_values)
                best_performing_asset:Symbol = module[module_perf_values.index(max_module_perf)]

                if max_module_perf > self.momentum_treshold:
                    long.append(best_performing_asset)
                else:
                    tbill_allocation_count += 1
        
        # tbill allocation weight relative to total number of modules with ROC data ready
        traded_asset_count:int = (tbill_allocation_count + len(long))
        tbill_allocation:float = tbill_allocation_count / traded_asset_count if traded_asset_count != 0 else 0

        # liquidate
        invested:List[Symbol] = [x.Key for x in self.Portfolio if x.Value.Invested]
        for symbol in invested:
            if symbol not in long + [self.treasury_bill]:
                self.Liquidate(symbol)

        # trade etfs
        for symbol in long:
            if symbol in data and data[symbol]:
                self.SetHoldings(symbol, 1 / traded_asset_count)
        
        # trade tbills
        if self.treasury_bill in data and data[self.treasury_bill]:
            self.SetHoldings(self.treasury_bill, tbill_allocation)

Leave a Reply

Discover more from Quant Buffet

Subscribe now to keep reading and get access to the full archive.

Continue reading