
美元、黄金、美债收益率这三者之间的关系几乎是每个做宏观对冲或者大类资产配置的人绕不开的课题。我从几年前开始用 tushare 拉数据做复盘最初只是想验证一下美元涨黄金跌这个朴素认知到底靠不靠谱后来越挖越深发现三者之间的联动远比想象中复杂——有时候同向有时候背离关键取决于当时市场交易的主逻辑是什么。这篇内容就把我整套分析框架拆开讲清楚数据怎么取、指标怎么算、相关性怎么滚动观察、背离怎么解读以及实操中踩过的那些坑。适合有一定 Python 基础、想用免费数据源做宏观量化分析的朋友也适合单纯想搞明白为什么美债收益率一涨黄金就哆嗦的投资者。全文基于 tushare 这个数据接口展开所有代码可直接复现。1. 分析框架的整体设计与指标选型逻辑1.1 为什么选这三个变量而不是别的做宏观分析最怕的就是变量选太多最后变成什么都相关、什么都解释不了。美元指数、黄金价格、美债收益率这三个变量恰好构成了一个相对闭合的逻辑环。美元指数代表的是全球美元流动性的松紧和相对购买力黄金是以美元计价的零息资产美债收益率则是美元的无风险利率锚。三者背后共同指向一个核心变量实际利率预期。我试过把原油、铜、美股指数都加进来结果发现噪音太大反而干扰了对主线的判断。后来砍到这三个配合一个通胀预期代理变量比如 TIPS 收益率或者盈亏平衡通胀率整个框架就清爽多了。这里要说明的是tushare 本身不直接提供 TIPS 数据但可以通过美债名义收益率减去通胀预期来近似或者用 CPI 同比做粗略替代这部分后面会讲具体处理方式。选这三个变量的另一个好处是数据可得性强。tushare 的us_tycr接口能拿到美债收益率曲线fx_daily能拿美元指数黄金虽然 tushare 的覆盖不如专业商品数据源全但通过fx_daily里的 XAUUSD 或者用国内黄金 ETF 价格做代理也能凑合。对于个人研究者来说数据能稳定拿到比数据多重要得多。1.2 三者联动的理论骨架先把理论逻辑理一遍不然后面看相关性数字会一头雾水。黄金和美元是负相关的这个逻辑很直白黄金以美元计价美元走强意味着买同样一盎司黄金需要更少的美元反之亦然。但这个负相关不是铁律在避险情绪主导的时候美元和黄金可能同时上涨——比如市场恐慌时资金既买美元又买黄金这时候负相关就失效了。黄金和美债收益率也是负相关的核心在于机会成本。黄金不生息持有黄金的机会成本就是放弃的无风险收益。当美债收益率上升持有黄金的机会成本增加资金倾向于流向生息资产黄金承压。但这里有个关键细节真正驱动黄金的是实际利率也就是名义利率减去通胀预期。如果名义利率上升是因为通胀预期上升更快那实际利率可能反而下降这时候黄金和名义收益率可能同向上涨。2021年到2022年那波就是典型名义收益率飙升但黄金没怎么跌因为通胀预期也在飙。美元和美债收益率通常是正相关的因为收益率上升吸引资本流入推升美元。但这个关系在美联储独立性和财政风险被质疑的时候会扭曲比如收益率上升是因为市场担心债务可持续性那美元反而可能走弱。提示理论关系只是先验假设实操中必须用滚动窗口去验证当前市场到底在交易哪条逻辑不能拿静态理论硬套。1.3 数据频率与时间窗口的选择tushare 的us_tycr接口提供的是日频数据fx_daily也是日频。日频数据做宏观分析其实偏噪音我一般会重采样到周频或者月频来看趋势。周频是个不错的折中既保留了足够的样本量又过滤掉了日内和日间的随机波动。时间窗口方面我习惯用 60 个交易日约三个月做滚动相关这个窗口足够捕捉中期逻辑切换又不至于太迟钝。如果做更长周期的配置分析会拉到 250 个交易日约一年。短于 20 个交易日的窗口我基本不用噪音太大相关性数字一天一变没有参考价值。这里有个实操细节滚动相关计算时如果窗口内有缺失值pandas 的rolling().corr()会直接跳过导致不同窗口的样本数不一致。我的做法是先做前向填充forward fill但限制最多填充 3 天超过 3 天的缺失就标记为 NaN 并剔除该窗口。这样能避免用陈旧数据污染相关性计算。2. tushare 数据获取与清洗的实操要点2.1 接口调用与权限准备tushare 的接口调用需要 token这个在官网注册后就能拿到。免费账户有积分限制us_tycr和fx_daily这两个接口对积分要求不算高一般注册后做点任务就能解锁。我建议先把 token 存在环境变量里不要硬编码在脚本里方便后续切换和管理。import os import tushare as ts import pandas as pd import numpy as np # 从环境变量读取 token token os.environ.get(TUSHARE_TOKEN) ts.set_token(token) pro ts.pro_api()调用美债收益率接口时us_tycr返回的是不同期限的收益率字段包括date、m1、m3、m6、y1、y2、y3、y5、y7、y10、y20、y30等。我一般关注y10十年期和y2两年期前者是市场定价锚后者更反映货币政策预期。两者的利差10Y-2Y是经典的衰退指标虽然这两年它的信号意义被质疑但作为辅助参考还是有价值。# 获取美债收益率数据 df_tycr pro.us_tycr(start_date20180101, end_date20241231) df_tycr[date] pd.to_datetime(df_tycr[date]) df_tycr df_tycr.sort_values(date).reset_index(dropTrue)美元指数通过fx_daily获取代码是USDX。这里要注意tushare 的fx_daily返回的字段是trade_date、ts_code、close等需要做透视或者筛选。# 获取美元指数 df_usdx pro.fx_daily(ts_codeUSDX, start_date20180101, end_date20241231) df_usdx[trade_date] pd.to_datetime(df_usdx[trade_date]) df_usdx df_usdx.sort_values(trade_date).reset_index(dropTrue)黄金数据稍微麻烦一点。tushare 的fx_daily里有没有 XAUUSD 取决于数据源覆盖如果没有可以用国内黄金 ETF比如 518880的日线数据做代理通过fund_daily接口获取。代理的缺点是受汇率和国内溢价影响但做趋势分析够用。# 用黄金 ETF 做代理 df_gold pro.fund_daily(ts_code518880.SH, start_date20180101, end_date20241231) df_gold[trade_date] pd.to_datetime(df_gold[trade_date]) df_gold df_gold.sort_values(trade_date).reset_index(dropTrue)2.2 数据对齐与缺失值处理三个数据源的时间轴不一定完全对齐尤其是中美交易日历差异。美债和美元指数是美市数据黄金 ETF 是 A 股数据节假日不同步是常态。我的处理方式是先做外连接outer join然后按日期排序对缺失值做前向填充但限制填充天数。# 合并数据 df pd.merge(df_tycr[[date, y10, y2]], df_usdx[[trade_date, close]], left_ondate, right_ontrade_date, howouter) df pd.merge(df, df_gold[[trade_date, close]], left_ondate, right_ontrade_date, howouter, suffixes(_usdx, _gold)) df df.sort_values(date).reset_index(dropTrue) # 重命名列 df df.rename(columns{close_usdx: usdx, close_gold: gold}) # 前向填充限制 3 天 df[[y10, y2, usdx, gold]] df[[y10, y2, usdx, gold]].ffill(limit3) # 剔除仍有缺失的行 df df.dropna(subset[y10, y2, usdx, gold]).reset_index(dropTrue)这里有个坑我踩过如果不限制填充天数遇到长假比如春节或者圣诞会用一周前的数据填充导致相关性计算出现虚假的平滑。限制 3 天能有效缓解这个问题代价是损失一些样本但对于宏观分析来说样本质量比数量重要。2.3 数据标准化与收益率计算做相关性分析前需要决定用价格水平还是收益率。价格水平做相关容易受趋势影响出现伪相关。我一般用对数收益率既平滑了量纲差异又更符合金融数据的统计特性。# 计算对数收益率 for col in [y10, y2, usdx, gold]: df[f{col}_ret] np.log(df[col] / df[col].shift(1)) # 剔除第一行 df df.dropna().reset_index(dropTrue)注意美债收益率本身已经是利率取对数收益率在经济含义上有点别扭但做统计相关性时问题不大。如果要做更严谨的分析可以直接用收益率的一阶差分df[y10].diff()这个看个人偏好。我两种都试过结论差异不大对数收益率在后续做回归时更方便解释弹性。注意黄金 ETF 价格受人民币汇率影响如果要做纯美元金价分析需要把人民币汇率因素剥离或者直接用美元金价数据源。这一步在 tushare 里比较难直接实现属于框架的已知局限。3. 滚动相关性与动态联动的计算实现3.1 滚动相关矩阵的构建滚动相关是这套分析的核心。静态相关只能告诉你历史上平均来看是什么关系滚动相关才能告诉你现在是什么关系。我一般会同时算三个配对黄金-美元、黄金-美债收益率、美元-美债收益率。window 60 # 60 个交易日 # 滚动相关 df[corr_gold_usdx] df[gold_ret].rolling(window).corr(df[usdx_ret]) df[corr_gold_y10] df[gold_ret].rolling(window).corr(df[y10_ret]) df[corr_usdx_y10] df[usdx_ret].rolling(window).corr(df[y10_ret])算完之后我习惯把这三条相关性曲线画在一张图上用不同颜色区分零轴加一条虚线。这样一眼就能看出什么时候逻辑发生了切换。比如 2020 年 3 月流动性危机期间三条相关性全部异常黄金-美元负相关一度转正这就是典型的避险模式。3.2 相关性符号翻转的识别相关性符号翻转是最有价值的信号。我写了一个简单的函数来标记翻转点def detect_sign_flip(series, threshold0.1): 检测相关性符号翻转threshold 用于过滤噪音 sign np.sign(series) flip sign.diff().abs() 0 # 只保留绝对值超过阈值的翻转 valid series.abs() threshold return flip valid df[flip_gold_usdx] detect_sign_flip(df[corr_gold_usdx]) df[flip_gold_y10] detect_sign_flip(df[corr_gold_y10])这个函数的意义在于当黄金-美元相关性从负转正往往意味着市场进入避险主导模式这时候传统的美元涨黄金跌逻辑失效需要切换分析框架。2022 年俄乌冲突初期、2023 年硅谷银行事件期间都出现过这种翻转。3.3 滚动 Beta 与弹性系数光看相关性不够还要看弹性。相关性只告诉你方向是否一致Beta 告诉你一个变量变动 1% 时另一个变量变动多少。我用滚动窗口做一元线性回归来估计 Betadef rolling_beta(y, x, window): 计算滚动 Beta betas [] for i in range(len(y)): if i window: betas.append(np.nan) else: y_win y[i-window:i] x_win x[i-window:i] # 简单线性回归 cov np.cov(y_win, x_win)[0, 1] var np.var(x_win) betas.append(cov / var if var ! 0 else np.nan) return pd.Series(betas, indexy.index) df[beta_gold_usdx] rolling_beta(df[gold_ret], df[usdx_ret], 60) df[beta_gold_y10] rolling_beta(df[gold_ret], df[y10_ret], 60)Beta 的解读如果beta_gold_usdx是 -1.5意味着美元收益率每变动 1%黄金收益率反向变动 1.5%。这个数字在实操中比相关性更有指导意义因为它直接告诉你对冲比例。比如你持有黄金多头想用美元多头对冲Beta 告诉你需要对冲多少仓位。提示滚动 Beta 在窗口边界处会有跳变建议做 5 日移动平均平滑后再使用避免被单日异常值误导。4. 背离识别与市场状态分类的实战应用4.1 三类典型背离的识别背离是这套框架里最有实战价值的部分。我总结了三种典型背离第一种是美元涨黄金也涨这通常发生在避险情绪主导时。识别方法是看corr_gold_usdx是否转正且持续超过 5 个交易日。如果同时corr_gold_y10也转正说明市场在交易避险通胀双重逻辑这时候黄金的货币属性压过了商品属性。第二种是美债收益率涨黄金不跌这通常发生在通胀预期上升快于名义利率时。识别方法是看corr_gold_y10是否从负转正同时观察 CPI 同比或者盈亏平衡通胀率是否在上升。2021 年下半年到 2022 年初就是这种状态。第三种是美元和美债收益率背离这通常发生在财政风险或者货币政策独立性被质疑时。识别方法是看corr_usdx_y10是否转负。这种背离比较少见但一旦出现往往预示着更大的宏观变局。# 背离标记 df[divergence_1] (df[corr_gold_usdx] 0) (df[corr_gold_usdx].rolling(5).min() 0) df[divergence_2] (df[corr_gold_y10] 0) (df[corr_gold_y10].rolling(5).min() 0) df[divergence_3] (df[corr_usdx_y10] 0) (df[corr_usdx_y10].rolling(5).max() 0)4.2 市场状态的四象限分类把三个相关性组合起来可以做一个简单的市场状态分类状态黄金-美元黄金-美债美元-美债典型环境常态负负正经济平稳实际利率主导避险正正正市场恐慌流动性偏好通胀负正正通胀预期上升实际利率下行混乱任意任意负财政风险或政策不确定性这个分类表是我自己复盘时用的不是学术标准但实操中很好用。比如看到避险状态就知道黄金和美元可以同时持有作为对冲看到通胀状态就知道黄金的配置价值上升因为实际利率在下降。4.3 状态切换的预警信号状态切换往往有前兆。我观察下来最常见的预警信号是相关性绝对值的快速收敛——比如corr_gold_usdx从 -0.6 快速收敛到 -0.1这通常意味着原有逻辑在弱化新的逻辑在酝酿。另一个信号是波动率上升我用 20 日滚动标准差来衡量如果三个变量的波动率同时上升状态切换的概率大幅增加。# 波动率 df[vol_gold] df[gold_ret].rolling(20).std() df[vol_usdx] df[usdx_ret].rolling(20).std() df[vol_y10] df[y10_ret].rolling(20).std() # 波动率共振信号 df[vol_resonance] (df[vol_gold] df[vol_gold].rolling(60).mean()) \ (df[vol_usdx] df[vol_usdx].rolling(60).mean()) \ (df[vol_y10] df[vol_y10].rolling(60).mean())这个共振信号在 2020 年 3 月、2022 年 9 月、2023 年 3 月都触发过事后看都是状态切换的关键节点。当然它不是精确的择时信号更像是一个提高警惕的提示。5. 常见问题排查与实操避坑指南5.1 数据层面的典型问题问题一美债收益率数据出现负值或者异常跳变。这种情况在 2020 年疫情期间出现过短端收益率接近零数据源偶尔会返回异常值。处理方式是设置合理区间过滤比如十年期收益率在 0.3% 到 6% 之间超出范围的标记为缺失。问题二黄金 ETF 和美元金价走势背离。这通常是因为人民币汇率波动或者国内溢价变化。如果背离持续超过一周建议检查汇率数据或者直接换用美元金价数据源。tushare 里如果找不到合适的美元金价可以考虑用其他免费数据源补充但要注意数据频率和时区对齐。问题三滚动相关在窗口边界跳变。这是数学特性决定的无法完全消除。缓解方式是做平滑处理或者用指数加权移动相关EWM替代简单滚动相关。EWM 对近期数据赋予更高权重更适合捕捉逻辑切换。# 指数加权移动相关 df[ewm_corr_gold_usdx] df[gold_ret].ewm(span60).corr(df[usdx_ret])5.2 分析层面的常见误区误区一把相关性当因果。相关性高不代表有因果关系可能只是共同受第三个变量驱动。比如黄金和美元负相关背后可能是实际利率在驱动两者。做分析时要时刻问自己这个相关性背后的驱动逻辑是什么误区二用全样本相关做决策。全样本相关是历史平均可能掩盖了近期逻辑切换。我见过有人用 2010 年到 2020 年的全样本相关做 2023 年的决策结果完全失效。必须用滚动窗口看当前状态。误区三忽略非线性关系。黄金和美元的关系在极端行情下可能非线性比如美元指数突破关键点位后黄金的敏感度会变化。处理方式是分段回归或者用非参数方法比如分位数回归来捕捉尾部特征。5.3 常见问题速查表问题现象可能原因排查方向解决方法相关性全为正数据未做收益率处理检查是否用了价格水平改用对数收益率相关性频繁翻转窗口太短检查 window 参数拉长到 60 或 120Beta 异常大异常值影响检查原始数据缩尾处理或剔除异常值状态分类频繁切换阈值太敏感检查阈值设置提高阈值或加确认期黄金数据与金价背离汇率或溢价对比美元金价换数据源或剥离汇率提示缩尾处理winsorize是处理金融数据异常值的常用方法把超过 1% 和 99% 分位数的值替换为分位数边界值能有效降低异常值对回归的影响。6. 从相关性到策略信号的转化思路6.1 信号构建的基本逻辑相关性分析本身不直接产生交易信号需要转化。我的转化逻辑是当相关性状态与理论预期一致时按理论逻辑配置当出现背离时降低仓位或者切换对冲方式。具体来说如果当前处于常态状态黄金-美元负、黄金-美债负、美元-美债正那么可以做多黄金的同时做多美元作为对冲因为两者负相关能降低组合波动。如果切换到避险状态那么黄金和美元可以同时做多因为两者正相关这时候对冲反而会削弱收益。6.2 仓位管理的参考框架仓位管理我一般用波动率倒数加权。先算每个资产的 20 日滚动波动率然后按波动率的倒数分配权重这样能让每个资产对组合的风险贡献大致相等。# 波动率倒数加权 df[w_gold] (1 / df[vol_gold]) / (1/df[vol_gold] 1/df[vol_usdx] 1/df[vol_y10]) df[w_usdx] (1 / df[vol_usdx]) / (1/df[vol_gold] 1/df[vol_usdx] 1/df[vol_y10]) df[w_y10] (1 / df[vol_y10]) / (1/df[vol_gold] 1/vol_usdx] 1/df[vol_y10])注意美债收益率本身不是可交易资产实际操作中会用国债期货或者债券 ETF 来替代。这里的权重只是分析框架不是直接可执行的仓位。6.3 回测验证的注意事项如果要把这套框架做回测有几个坑必须避开。第一是前视偏差滚动相关和 Beta 只能用当前时点之前的数据计算不能用未来数据。第二是交易成本宏观策略换手率不高但也不能忽略。第三是样本外验证至少留出 30% 的数据做样本外测试避免过拟合。我自己的回测结果显示单纯基于相关性状态的择时信号夏普比率并不高大概在 0.5 到 0.8 之间。但如果把相关性信号作为过滤条件叠加趋势跟踪或者动量信号效果会好很多。这说明相关性分析更适合做风险管理和状态识别而不是独立的 alpha 来源。6.4 框架的扩展方向这套框架还可以往几个方向扩展。一是加入更多资产比如铜、原油、比特币看它们在状态切换时的表现。二是加入宏观基本面数据比如 PMI、CPI、非农就业做相关性状态的基本面归因。三是用机器学习方法做状态分类比如隐马尔可夫模型或者聚类算法自动识别市场状态减少人工阈值设定的主观性。不过我要提醒一句扩展不等于堆砌。每加一个变量都要问自己它是否提供了增量信息是否让框架更清晰而不是更混乱我见过太多人把框架搞得无比复杂最后自己都解释不清楚每个变量的作用。保持简洁是这套框架能持续用下去的关键。我个人在实际操作中的体会是tushare 这套数据接口做宏观相关性分析性价比很高但数据清洗和对齐的工作量占了整个项目的六成以上。真正花在分析上的时间反而不多。所以如果你打算复现这套框架建议先把数据管道搭稳再做分析不然会在数据问题上反复消耗精力。另外相关性状态切换的信号最好配合价格行为确认不要单独使用这是我踩过几次坑之后最深的教训。