主题切换
15.5 跨资产宏观策略
名词解释:跨资产宏观策略(Cross-Asset Macro Strategy)
跨资产宏观策略是基于宏观经济分析,在股票、债券、外汇、商品等多个资产类别中同时进行方向性押注的投资策略。全球宏观对冲基金(如 Bridgewater、Tudor)是这类策略的典型实践者,其核心方法论包括 Carry、Momentum 和 Value 三大风格。
一、全球宏观对冲基金策略
1.1 三大宏观交易风格
全球宏观策略通常可归纳为三种系统性风格:
| 风格 | 逻辑 | 典型交易 | 风险 |
|---|---|---|---|
| Carry(套息) | 持有高收益资产、融低收益资产 | 做多高息货币/做空低息货币(Carry Trade) | 崩盘风险(Crash Risk) |
| Momentum(动量) | 趋势会延续 | 做多过去6-12个月表现最强的资产 | 趋势反转 |
| Value(价值) | 价格会回归公允价值 | 做多低估货币/债券,做空高估货币/债券 | 价值陷阱 |
1.2 外汇 Carry Trade 的量化实现
此处有展示代码展开 ▼
python
import numpy as np
import pandas as pd
from typing import Tuple
def fx_carry_strategy(spot_rates: pd.DataFrame,
interest_rates: pd.DataFrame,
lookback_days: int = 21) -> pd.DataFrame:
"""
系统性外汇套息策略。
每月做多利率最高的3种货币,做空利率最低的3种货币。
参数:
spot_rates: 外汇即期汇率(每列为一种货币对)
interest_rates: 对应货币的短期利率(年化%)
lookback_days: 调仓周期
返回:
策略收益率序列
"""
n_currencies = len(interest_rates.columns)
returns = spot_rates.pct_change().fillna(0)
strategy_returns = []
for t in range(lookback_days, len(interest_rates), lookback_days):
# 当前利率排名
current_rates = interest_rates.iloc[t]
ranked = current_rates.sort_values()
# 高利率货币做多,低利率货币做空
long_currencies = ranked.index[-3:] # 最高利率的3种
short_currencies = ranked.index[:3] # 最低利率的3种
# 下一持仓期的收益
end_idx = min(t + lookback_days, len(returns))
period_returns = returns.iloc[t:end_idx]
# 组合收益(等权多空)
long_return = period_returns[long_currencies].mean(axis=1)
short_return = period_returns[short_currencies].mean(axis=1)
portfolio_return = long_return - short_return
strategy_returns.append(portfolio_return)
# 拼接
strategy_returns = pd.concat(strategy_returns)
strategy_returns = strategy_returns[~strategy_returns.index.duplicated()]
return strategy_returns
# ===== 合成数据最小示例(数据为模拟,机制真实)=====
np.random.seed(17)
_ccys = ['EUR', 'JPY', 'GBP', 'AUD']
_idx = pd.date_range('2023-01-02', periods=250)
_spot = pd.DataFrame({c: [1.1, 150, 1.27, 0.67][i] + np.cumsum(np.random.randn(250) * 0.004)
for i, c in enumerate(_ccys)}, index=_idx)
_rates = pd.DataFrame({c: [3.5, 0.1, 4.8, 4.2][i] + np.random.randn(250) * 0.02
for i, c in enumerate(_ccys)}, index=_idx)
_carry = fx_carry_strategy(_spot, _rates)
print('套息策略累计收益:', round(float((1 + _carry.fillna(0)).prod() - 1), 4))点击展开可浏览运行结果
套息策略累计收益: 0.0135
1.3 宏观动量策略
此处有展示代码展开 ▼
python
import numpy as np
import pandas as pd
def global_macro_momentum(asset_prices: pd.DataFrame,
n_assets: int = 10,
momentum_months: int = 6,
rebalance_freq: str = 'M') -> pd.DataFrame:
"""
全球宏观动量策略:做多过去N个月表现最好的资产。
参数:
asset_prices: 全球资产价格矩阵
(含股票指数、债券指数、商品、外汇)
n_assets: 做多资产数量
momentum_months: 动量回看月数
rebalance_freq: 调仓频率 ('M'=每月)
返回:
策略权重和收益
"""
# 计算动量信号
momentum_signal = asset_prices.pct_change(momentum_months * 21)
# 每月调仓
weights = pd.DataFrame(0.0, index=asset_prices.index,
columns=asset_prices.columns)
if rebalance_freq == 'M':
rebalance_dates = asset_prices.resample('M').last().index
for date in rebalance_dates:
if date in momentum_signal.index:
mom = momentum_signal.loc[date]
top_assets = mom.nlargest(n_assets).index
# 等权配置
weight_value = 1.0 / n_assets
weights.loc[date:, top_assets] = weight_value
# 策略收益
asset_returns = asset_prices.pct_change()
strategy_returns = (weights.shift(1) * asset_returns).sum(axis=1)
return strategy_returns
# ===== 合成数据最小示例(数据为模拟,机制真实)=====
np.random.seed(19)
_assets = ['美股', '美债', '黄金', '原油', '铜', '欧元', '日元', '新兴市场', 'REITs', '商品']
_px = pd.DataFrame({a: 100 * np.cumprod(1 + np.random.randn(500) * 0.01 + 0.0003)
for a in _assets}, index=pd.date_range('2022-01-03', periods=500))
_mom = global_macro_momentum(_px)
print('动量策略累计收益:', round(float((1 + _mom.fillna(0)).prod() - 1), 4))点击展开可浏览运行结果
⚠ 末尾操作失败: Invalid frequency: M. Failed to parse with error message: ValueError("'M' is no longer supported for offsets. Please use 'ME' instead.")二、跨资产相关性的危机特征
2.1 相关性在危机期间的结构性变化
市场在正常时期和危机时期的相关性结构截然不同:
此处有展示代码展开 ▼
python
def crisis_correlation_analysis(asset_returns: pd.DataFrame,
crisis_dates: list = None) -> dict:
"""
分析正常时期 vs 危机时期的跨资产相关性变化。
参数:
asset_returns: 各资产的日收益率
crisis_dates: 危机期间的日期列表
返回:
包含正常和危机时期相关性矩阵的字典
"""
if crisis_dates is None:
# 示例:2008金融危机和2020新冠
crisis_dates = [
('2008-09-01', '2009-03-31'),
('2020-02-19', '2020-03-23')
]
# 正常时期(排除危机)
crisis_mask = pd.Series(False, index=asset_returns.index)
for start, end in crisis_dates:
crisis_mask |= (asset_returns.index >= start) & \
(asset_returns.index <= end)
normal_returns = asset_returns[~crisis_mask]
crisis_returns = asset_returns[crisis_mask]
# 计算相关性
normal_corr = normal_returns.corr()
crisis_corr = crisis_returns.corr()
# 相关性差异
corr_diff = crisis_corr - normal_corr
# 可视化
fig, axes = plt.subplots(1, 3, figsize=(18, 5))
titles = ['正常时期', '危机时期', '差异 (危机 - 正常)']
matrices = [normal_corr, crisis_corr, corr_diff]
for i, (title, mat) in enumerate(zip(titles, matrices)):
im = axes[i].imshow(mat.values, cmap='RdBu_r',
vmin=-1, vmax=1, aspect='auto')
axes[i].set_xticks(range(len(mat.columns)))
axes[i].set_yticks(range(len(mat.columns)))
axes[i].set_xticklabels(mat.columns, rotation=45, ha='right',
fontsize=8)
axes[i].set_yticklabels(mat.columns, fontsize=8)
axes[i].set_title(title)
plt.colorbar(im, ax=axes[i], shrink=0.8)
plt.tight_layout()
plt.show()
# 相关性分散度:危机期间各资产间相关性趋于1
normal_dispersion = np.std(normal_corr.values[np.triu_indices_from(
normal_corr.values, k=1)])
crisis_dispersion = np.std(crisis_corr.values[np.triu_indices_from(
crisis_corr.values, k=1)])
return {
'normal_correlation': normal_corr,
'crisis_correlation': crisis_corr,
'correlation_diff': corr_diff,
'dispersion_normal': normal_dispersion,
'dispersion_crisis': crisis_dispersion,
'diversification_benefit_deterioration': (
normal_dispersion - crisis_dispersion
) / normal_dispersion * 100
}
# ===== 合成数据最小示例(数据为模拟,机制真实)=====
np.random.seed(23)
_rets = pd.DataFrame(np.random.randn(750, 5) * 0.01,
columns=['美股', '美债', '原油', '黄金', '新兴市场'],
index=pd.date_range('2021-01-04', periods=750))
_cr = crisis_correlation_analysis(_rets, crisis_dates=[('2022-02-24', '2022-06-30')])
for _k, _v in _cr.items():
print(f'--- {_k} ---')
print(_v if not hasattr(_v, 'head') else _v.head())点击展开可浏览运行结果
--- normal_correlation ---
美股 美债 原油 黄金 新兴市场
美股 1.000000 0.005912 0.004921 0.060775 -0.044869
美债 0.005912 1.000000 -0.000801 -0.080351 0.008349
原油 0.004921 -0.000801 1.000000 0.039550 -0.023288
黄金 0.060775 -0.080351 0.039550 1.000000 -0.038724
新兴市场 -0.044869 0.008349 -0.023288 -0.038724 1.000000
--- crisis_correlation ---
美股 美债 原油 黄金 新兴市场
美股 1.000000 -0.015313 0.167850 -0.075157 0.065867
美债 -0.015313 1.000000 0.010977 -0.035644 -0.005792
原油 0.167850 0.010977 1.000000 -0.054581 0.054977
黄金 -0.075157 -0.035644 -0.054581 1.000000 -0.104953
新兴市场 0.065867 -0.005792 0.054977 -0.104953 1.000000
--- correlation_diff ---
美股 美债 原油 黄金 新兴市场
美股 0.000000 -0.021225 0.162929 -0.135931 0.110735
美债 -0.021225 0.000000 0.011777 0.044707 -0.014142
原油 0.162929 0.011777 0.000000 -0.094131 0.078265
黄金 -0.135931 0.044707 -0.094131 0.000000 -0.066229
新兴市场 0.110735 -0.014142 0.078265 -0.066229 0.000000
--- dispersion_normal ---
0.03927985820584405
--- dispersion_crisis ---
0.07538520049097441
--- diversification_benefit_deterioration ---
-91.918209317157392.2 动态条件相关模型(DCC-GARCH)
DCC-GARCH 可以刻画时变的相关性,并捕捉相关性在危机期间的突然上升:
此处有展示代码展开 ▼
python
import numpy as np
def simple_dcc_estimate(returns_1: np.ndarray,
returns_2: np.ndarray,
half_life: int = 20) -> np.ndarray:
"""
简化的动态条件相关性估计(指数加权移动平均)。
DCC_t = q12_t / sqrt(q11_t * q22_t)
参数:
returns_1, returns_2: 两个资产的收益率
half_life: EWMA半衰期(天)
返回:
时变相关性序列
"""
alpha = 2.0 / (half_life + 1) # EWMA衰减因子
T = len(returns_1)
q11 = np.zeros(T)
q22 = np.zeros(T)
q12 = np.zeros(T)
dcc = np.zeros(T)
# 初始化:无条件方差/协方差
q11[0] = np.var(returns_1)
q22[0] = np.var(returns_2)
q12[0] = np.cov(returns_1, returns_2)[0, 1]
for t in range(1, T):
q11[t] = (1 - alpha) * q11[t-1] + alpha * returns_1[t-1] ** 2
q22[t] = (1 - alpha) * q22[t-1] + alpha * returns_2[t-1] ** 2
q12[t] = (1 - alpha) * q12[t-1] + alpha * returns_1[t-1] * returns_2[t-1]
dcc[t] = q12[t] / (np.sqrt(q11[t]) * np.sqrt(q22[t]) + 1e-10)
return dcc
# ===== 合成数据最小示例(数据为模拟,机制真实)=====
np.random.seed(29)
_common = np.random.randn(400) * 0.01
_r1 = _common + np.random.randn(400) * 0.005
_r2 = _common + np.random.randn(400) * 0.005
_dcc = simple_dcc_estimate(_r1, _r2, half_life=20)
_dcc_v = _dcc if np.isscalar(_dcc) else (np.asarray(_dcc)[-1] if hasattr(_dcc, '__len__') else _dcc)
print('DCC 动态相关性(最新):', round(float(_dcc_v), 3))点击展开可浏览运行结果
DCC 动态相关性(最新): 0.589
三、汇率、利率、大宗商品的联动
3.1 三元悖论与跨资产传导
"三元悖论"(Impossible Trinity)指出:一个经济体不能同时实现固定汇率、资本自由流动和独立货币政策。这一约束驱动了汇率、利率和资本流动之间的紧密联动:
- 加息 + 资本流入 -> 本币升值 -> 大宗商品(以美元计价)承压
- 资本外流 -> 本币贬值 -> 出口改善 -> 股市受益(出口导向型)
3.2 联动性的量化
此处有展示代码展开 ▼
python
def cross_asset_linkage(fx_changes: np.ndarray,
rate_changes: np.ndarray,
commodity_changes: np.ndarray,
window: int = 60) -> pd.DataFrame:
"""
量化汇率、利率、大宗商品之间的联动关系。
使用VAR模型估计相互影响。
参数:
fx_changes: 汇率变动率
rate_changes: 利率变动(收益率变动)
commodity_changes: 大宗商品价格变动率
window: 滚动窗口
返回:
滚动回归系数DataFrame
"""
T = len(fx_changes)
results = []
for t in range(window, T):
# 局部数据
fx = fx_changes[t-window:t]
rate = rate_changes[t-window:t]
comm = commodity_changes[t-window:t]
# 回归: ΔFX = α + β1 * ΔRates + β2 * ΔCommodity + ε
X = np.column_stack([np.ones(window), rate, comm])
y = fx
beta = np.linalg.lstsq(X, y, rcond=None)[0]
results.append({
'date': t,
'constant': beta[0],
'beta_rate': beta[1],
'beta_commodity': beta[2],
'r_squared': 1 - np.sum((y - X @ beta) ** 2) / np.sum((y - np.mean(y)) ** 2)
})
return pd.DataFrame(results)
# ===== 合成数据最小示例(数据为模拟,机制真实)=====
np.random.seed(31)
_mkt = np.random.randn(500)
_link = cross_asset_linkage(_mkt * 0.003, _mkt * 0.002 + 0.001, _mkt * 0.004, window=60)
print(_link.tail() if hasattr(_link, 'tail') else _link)点击展开可浏览运行结果
date constant beta_rate beta_commodity r_squared 435 495 -0.0003 0.3 0.6 1.0 436 496 -0.0003 0.3 0.6 1.0 437 497 -0.0003 0.3 0.6 1.0 438 498 -0.0003 0.3 0.6 1.0 439 499 -0.0003 0.3 0.6 1.0
四、风险平价在全球宏观中的应用
4.1 风险平价原理
风险平价(Risk Parity)使组合中各资产的风险贡献相等,而非资本权重相等。在全球宏观中,风险平价旨在:
- 跨资产平衡风险:股票、债券、商品、外汇的风险贡献大致相等
- 抗通胀和通缩环境的双重保护:增长环境利好股票/商品,衰退环境利好债券
- 适应不同经济周期:不需要预测周期阶段,自然适应环境变化
4.2 实现
此处有展示代码展开 ▼
python
import numpy as np
import pandas as pd
def global_macro_risk_parity(asset_returns: pd.DataFrame,
lookback: int = 252) -> pd.Series:
"""
全球宏观风险平价组合权重。
各资产权重 ∝ 1 / 波动率
参数:
asset_returns: 全球资产日收益率
lookback: 波动率估计窗口
返回:
风险平价权重
"""
# 滚动波动率
rolling_vol = asset_returns.rolling(lookback).std().iloc[-1]
# 权重 ∝ 1/vol
inv_vol = 1.0 / rolling_vol
weights = inv_vol / inv_vol.sum()
# 波动率缩放:组合目标波动率 10%
portfolio_vol_estimate = np.sqrt(
weights @ asset_returns.rolling(lookback).cov().iloc[-1] @ weights
)
target_vol = 0.10 / np.sqrt(252) # 日度目标波动率
leverage = target_vol / portfolio_vol_estimate
weights = weights * min(leverage, 2.0) # 杠杆上限2倍
return weights
# ===== 合成数据最小示例(数据为模拟,机制真实)=====
np.random.seed(37)
_rp_rets = pd.DataFrame(np.random.randn(500, 5) * 0.008,
columns=['美股', '美债', '黄金', '商品', '新兴市场'],
index=pd.date_range('2022-01-03', periods=500))
_rp = global_macro_risk_parity(_rp_rets)
print('风险平价权重:', _rp if not hasattr(_rp, 'to_string') else _rp.round(3).to_string())点击展开可浏览运行结果
⚠ 末尾操作失败: tuple index out of range
4.3 全天候策略的宏观逻辑
Bridgewater 的"全天候"(All Weather)策略是风险平价的典型应用。它将经济环境按增长和通胀预期分为四种情况,每种情况配置 25% 的风险预算:
| 环境 | 增长超预期 | 增长低于预期 |
|---|---|---|
| 通胀超预期 | 商品、TIPS、新兴市场股票 | 通胀挂钩债券、黄金 |
| 通胀低于预期 | 股票、公司信用债 | 名义国债、通胀挂钩债券 |
跨资产宏观策略的精髓在于理解资产之间的联动关系,以及这些关系如何随经济周期变化。构建此类策略需要强大的风险管理体系来应对相关性破裂和市场恶化——这正是下一个模块要深入探讨的主题。
常见误区
误区1:认为危机时相关性"趋向 1"对所有资产同时发生。 相关性跳变有先后与幅度差异,避险资产(日元、美债)反而负相关,跳变结构本身就是信号。
误区2:风险平价加杠杆就万事大吉。 杠杆放大的是平静期的分散收益,也同步放大尾部相关性跳变时的回撤。
误区3:跨资产联动只看美元。 美元是主导变量之一,但能源供给冲击、区域性资金流同样驱动跨资产相关结构。
误区4:跨资产回测成本设为零。 外汇远期点、商品展期收益、期权隐含成本都不可忽略,否则策略收益大量虚高。
本章要点
- 危机时期相关性发生结构性跳变,静态相关矩阵不可用
- 应使用条件相关模型(DCC、Copula)刻画状态依赖的相关结构
- 全球宏观策略的核心是识别各国政策周期与跨资产传导链
- 风险平价需对尾部相关性做压力测试,并对杠杆设上限