“该策略使用失业率缺口因子在全球五个国家配置10年期债券期货,通过等权重调整每月重新平衡,以实现系统化投资。”

I. 策略概要

该策略投资于澳大利亚、加拿大、德国、英国和美国的10年期政府债券期货,使用失业率缺口因子(9个月变化、1个月变化或3年缺口)。配置策略可以遵循底部、中位数或顶部版本,或单一因子方法。因子投资组合通过按比例买卖债券期货来构建,基于将指标与横截面平均值(根据离散度调整)进行比较得出的横截面分数。通过对各国进行等权重配置来消除方向性偏差,并每日调整。投资组合每月重新平衡,利用失业率缺口趋势进行系统性债券投资决策。

II. 策略合理性

失业率与债券之间存在直观的联系,因为中央银行利用短期利率来影响产出增长并控制失业率。长期利率受债务/GDP的影响,失业率间接与GDP挂钩。虽然没有明确的基本面原因解释为什么失业率缺口能够预测债券期货,但统计和机器学习分析表明它是一个可靠的因子。在投资组合构建中,失业率缺口优于纯粹的失业率,产生更高的信息比率,使其成为债券投资策略的有效工具。

III. 来源论文

Beyond Carry and Momentum in Government Bonds [点击查看论文]

<摘要>

本文回顾了近期关于政府债券因子投资的文献,特别是关于价值和防御性投资的定义。作者使用机器学习技术,识别了政府债券期货的关键驱动因素和最真正相关的因子组。除了利差和动量之外,他们提出了一种防御性投资方法,该方法考虑了政府债券的避险性质。这两种主要风格可以辅以价值和反转因子,以实现独立于利率广泛变动的回报。

IV. 回测表现

年化回报1.3%
波动率10.1%
β值-0.002
夏普比率0.13
索提诺比率N/A
最大回撤-40%
胜率53%

V. 完整的 Python 代码

import numpy as np
from AlgorithmImports import *
import data_tools
class UnemploymentGapFactorinFixedIncome(QCAlgorithm):
    def Initialize(self):
        self.SetStartDate(2000, 1, 1)
        self.SetCash(100000)
        
        self.symbols = {
                        "ASX_XT1"       : "RBA/H05_GLFSURSA",   # 10 Year Commonwealth Treasury Bond Futures, Continuous Contract #1 (Australia)
                        "MX_CGB1"       : "UKONS/ZXDZ_M",       # Ten-Year Government of Canada Bond Futures, Continuous Contract #1 (Canada)
                        "EUREX_FGBL1"   : "UKONS/ZXDK_M",       # Euro-Bund (10Y) Futures, Continuous Contract #1 (Germany)
                        "LIFFE_R1"      : "UKONS/YCNO_M",       # Long Gilt Futures, Continuous Contract #1 (U.K.)
                        "CME_TY1"       : "UKONS/ZXDX_M"        # 10 Yr Note Futures, Continuous Contract #1 (USA)
                        }
        # Monthly unemployment data.
        self.data = {}
        self.period = 3 * 12
        
        for symbol in self.symbols:
            data = self.AddData(data_tools.QuantpediaFutures, symbol, Resolution.Daily)
            data.SetFeeModel(data_tools.CustomFeeModel())
            data.SetLeverage(5)
            
            unempl_symbol = self.symbols[symbol]
            if unempl_symbol == 'ASX_XT1':
                data = self.AddData(data_tools.UnemploymentDataAUD, unempl_symbol, Resolution.Daily)
            else:
                data = self.AddData(data_tools.UnemploymentData, unempl_symbol, Resolution.Daily)
            self.data[symbol] = RollingWindow[float](self.period)
            
        first_key = [x for x in self.symbols.keys()][0]
        self.Schedule.On(self.DateRules.MonthStart(self.symbols[first_key]), self.TimeRules.At(0, 0), self.Rebalance)
    
    def OnData(self, data):
        # store monthly rates
        for symbol in self.symbols:
            unempl_symbol = self.symbols[symbol]
            if unempl_symbol in data and data[unempl_symbol]:
                unempl_rate = data[unempl_symbol].Value
                if unempl_rate != 0:
                    self.data[symbol].Add(unempl_rate)
    
    def Rebalance(self):
        # Difference from MA.
        ma_diff = {}
        for symbol in self.symbols:
            if self.Securities[symbol].GetLastData() and (self.Time.date() - self.Securities[symbol].GetLastData().Time.date()).days < 5:
                # Unemployment data is ready to calculate MA.
                if self.data[symbol].IsReady:
                    # Calculate difference from MA.
                    ma = np.mean([x for x in self.data[symbol]])
                    if ma != 0:
                        current_value = self.data[symbol][0]
                        ma_diff[symbol] = current_value - ma
    
        if len(ma_diff) != 0:
            # Difference weighting.
            avg_diff = np.mean([x[1] for x in ma_diff.items()])
            diff_from_avg = { symbol: diff - avg_diff for symbol, diff in ma_diff.items() }
            
            total_diff = sum([abs(x[1]) for x in diff_from_avg.items()])
            weight = { symbol: diff / total_diff for symbol, diff in diff_from_avg.items() }
    
            for symbol, w in weight.items():
                self.SetHoldings(symbol, w)
        else:
            self.Liquidate()

发表评论

了解 Quant Buffet 的更多信息

立即订阅以继续阅读并访问完整档案。

继续阅读