在任何市场中获得优势(第五部分):联邦储备经济数据库(FRED)欧元兑美元( EURUSD)可替代数据(基础篇)
用 FRED 给 EURUSD 找另类数据优势
做 EURUSD 的交易者大多盯着利率决议和 CPI 头条,却少有人直接拉美联储的 FRED 数据库做交叉验证。FRED 把美联储、欧央行公开宏观序列免费开放接口,里面不少指标和欧元兑美元的日内波动存在领先或背离关系,属于典型的另类可替代数据入口。 本系列定位很直接:在大数据堆里帮有经验的交易者筛数据集。你没必要把所有宏观序列都接进 MT5,关键是判断哪些该纳进研判、哪些纯属噪声。外汇与贵金属杠杆高、宏观事件跳空频繁,任何数据优势都只是概率倾斜,不是确定性。 下一篇会给出具体从 FRED 拉数并接进 MetaTrader 5 的实例,你可以先开好 MT5 的 EURUSD 日线图,等代码贴出来直接跑。
「美元指数与欧美汇率的负相关真相」
相关性是组合构建与敞口管理的底层逻辑。美联储维护的名义广义美元指数(NBDD)2006年1月以100点设立,2022年触约128点历史高位,2024年前后徘徊121点附近,距高点仅差约5.5%。 原文把NBDD与欧元兑美元叠加时,因量纲不同几乎看不出关系,欧美汇率被压在图底。但把Y轴改成「过去一年百分比变化」后,两者呈现近乎完美的负相关性——指数涨,欧美跌。 这一负相关不是装饰性结论。既然宏观美元指数能解释欧美的大部分反向波动,用FRED宏观序列训练模型去预测EURUSD,在统计上具备可行性,但外汇与贵金属属高风险品种,模型信号只代表概率倾向,不构成方向保证。
◍ 先合并宏观数据再看相关性
从 MT5 终端拉取欧元兑美元日线历史汇率,再借 FRED 的 Python 接口并入三个宏观序列:美国债券利率、美国预期通胀率、广义美元指数。由此拼出三套训练集——纯 OHLC 市场价格、纯 FRED 替代数据、以及两者的超集。 尺度对齐 FRED 网站口径后,欧元兑美元与广义美元指数的同期相关性逼近 -0.9,近乎完美反向;更值得注意的是,广义美元指数当期值与欧美收盘价 20 个交易日后的值相关性也有 -0.7。用较长窗口算百分比变化做可视化,3D 散点里看涨、看跌区隔得相当干净,即便不靠 Python 高级分析,官方散点图趋势也清晰可辨。 但把希望押在宏观数据上并没换来预测力提升。三个结构相同的 DNN 回归器分别吃三套数据,反而是只用普通市场价格的那一个误差最低;特征选择算法对任一 FRED 集都没表现出偏好。用时间序列交叉验证(不打乱顺序)调参后,验证集优于默认 DNN,且没过拟合,说明流程本身没崩。 导出 ONNX 前查了残差,表现偏弱,提示模型没真正学到规律。最后仍按原计划转成 ONNX,用 Python 加 MQL5 搭了带 AI 的 EA。外汇与贵金属杠杆高,这类宏观融合模型仅作概率参考,实盘前务必在 MT5 策略测试器跑通。
把宏观序列和 EURUSD 日线拼到一张表
做跨资产预测前,先把 FRED 的宏观序列和 MT5 的 EURUSD 日线对齐。代码里拉了三个 FRED 序列:广义美元指数 DTWEXBGS、美债 10 年收益率 DGS10、5 年通胀预期 T5YIFR,再用 mt5.copy_rates_from_pos 抓 365×4=1460 根日线,也就是 4 年历史。 缺失值不能用前向填充糊弄,原文用 5 日滚动均值补窗(min_periods=1),通胀序列缺失时甚至借了美元指数的滚动均值顶上,这点在外汇建模里容易踩坑。 MT5 端必须先 mt5.initialize() 再取数,时间列从 Unix 秒用 pd.to_datetime(unit='s') 转成真实日期并设为索引,否则和 FRED 按日对齐会错位。预测窗口 look_ahead=20,即押后 20 个交易日的收盘价当因变量。 合并后的表用 pct_change(periods=365)*100 转成年度百分比变化,和 FRED 网站口径一致;最后加一列 Binary Target 置 0,仅为后续绘图区分涨跌。外汇与贵金属杠杆高,宏观变量只是倾向性解释,实盘仍可能反向。
class="macro">#Import the libraries we need from fredapi class="kw">import Fred class="kw">import seaborn as sns class="kw">import numpy as np class="kw">import pandas as pd class="kw">import MetaTrader5 as mt5 class="kw">import matplotlib.pyplot as plt class="macro">#Define important variables fred_api = "ENTER YOUR API KEY" fred_broad_dollar_index = "DTWEXBGS" fred_us_10y = "DGS10" fred_us_5y_inflation = "T5YIFR" class="macro">#Login to fred fred = Fred(api_key=fred_api) class="macro">#Fetch the data dollar_index = fred.get_series(fred_broad_dollar_index) us_10y = fred.get_series(fred_us_10y) us_5y_inflation = fred.get_series(fred_us_5y_inflation) class="macro">#Name the series so we can merge the data dollar_index.name = "Dollar Index" us_10y.name = "Bond Interest" us_5y_inflation.name = "Inflation" class="macro">#Fill in any missing values dollar_index.fillna(dollar_index.rolling(window=class="num">5,min_periods=class="num">1).mean(),inplace=True) us_10y.fillna(us_10y.rolling(window=class="num">5,min_periods=class="num">1).mean(),inplace=True) us_5y_inflation.fillna(dollar_index.rolling(window=class="num">5,min_periods=class="num">1).mean(),inplace=True) class="macro">#Initialize the terminal mt5.initialize() class="macro">#Define how much data to fetch amount = class="num">365 * class="num">4 class="macro">#Fetch data eur_usd = pd.DataFrame(mt5.copy_rates_from_pos("EURUSD",mt5.TIMEFRAME_D1,class="num">0,amount)) eur_usd class="macro">#Convert the time column eur_usd[&class="macro">#x27;time&class="macro">#x27;] = pd.to_datetime(eur_usd.loc[:,&class="macro">#x27;time&class="macro">#x27;],unit=&class="macro">#x27;s&class="macro">#x27;) class="macro">#Set the column as the index eur_usd.set_index(&class="macro">#x27;time&class="macro">#x27;,inplace=True) class="macro">#Define the forecast horizon look_ahead = class="num">20 class="macro">#Define the predictors predictors = ["open","high","low","close","tick_volume","Dollar Index","Bond Interest","Inflation"] ohlc_predictors = ["open","high","low","close","tick_volume"] fred_predictors = ["Dollar Index","Bond Interest","Inflation"] target = "Target" all_data = ["Target","open","high","low","close","tick_volume","Dollar Index","Bond Interest","Inflation"] all_data_binary = ["Binary Target","open","high","low","close","tick_volume","Dollar Index","Bond Interest","Inflation"] class="macro">#Merge our data merged_data = eur_usd.merge(dollar_index,right_index=True,left_index=True) merged_data = merged_data.merge(us_10y,right_index=True,left_index=True) merged_data = merged_data.merge(us_5y_inflation,right_index=True,left_index=True) class="macro">#Define the target target = merged_data.loc[:,"close"].shift(-look_ahead) target.name = "Target" class="macro">#Convert the data to yearly percent changes merged_data = merged_data.loc[:,predictors].pct_change(periods = class="num">365) * class="num">100 merged_data = merged_data.merge(target,right_index=True,left_index=True) merged_data.dropna(inplace=True) merged_data class="macro">#Add binary targets for plotting purposes merged_data["Binary Target"] = class="num">0
「把价格落点转成二分类标签」
做监督式价格行为建模时,先把连续收盘价映射成 0/1 标签,才能喂给分类器。上面这行核心逻辑是:凡 close 小于 Target 的列位置,Binary Target 直接赋 1,其余保持默认 0,相当于定义“未触及目标”为阳性样本。 紧接着 reset_index(inplace=True,drop=True) 把合并后的多重索引拍平,避免后续 MT5 侧按行切片时出现错位。drop=True 很关键,旧索引列不保留,数据框干净,直接 print(merged_data) 就能在终端看到标签分布。 开 MT5 接这套逻辑前,先在 Python 侧确认 Binary Target 里 1 的占比——若某品种 1 的比例长期低于 15% 或高于 85%,类别失衡会让模型在外汇、贵金属这种高风险品种上给出偏颇的概率倾向。
merged_data.loc[merged_data["close"] < merged_data["Target"],"Binary Target"] = class="num">1 class="macro">#Reset the index merged_data.reset_index(inplace=True,drop=True) merged_data
◍ 用图把欧元兑美元和宏观变量的关系拆开看
先把在公开宏观数据源上看到的走势在本地重画一遍,能确认前面的清洗和合并没跑偏。图里欧元兑美元收盘价和广义美元指数叠在一起,直观上就不是一个同向关系。 相关性热力图暴露了一个事实:三个备选宏观集里,通胀类的数据和目标最弱,剩下两个利率、美元指数类看着有戏,但后面建模并没换来性能提升。外汇和贵金属这类高波动品种,单看相关性就下单大概率要吃亏。 成对散点图把多列数据两两摊开,橙色和蓝色样本被切得很干净,对角线上的 KDE 显示两堆分布像两个小山丘、只在窄区间重叠,说明类别本身分得开。3D 散点用美元指数、债券利率做底面、欧美收盘做高度,点云明显裂成两簇、几乎不交叠——理论上存在一条决策边界,但当时没把这个结构喂进模型里学出来。 下面这段是当时画图的代码,逐行看:先给图定标题并叠画欧美收盘与美元指数;再用热力图算全列相关系数、用 pairplot 按二分类目标上色;最后建 7x7 的 3D 轴,拿三个变量散射并按目标列着色、补三条轴标签。开 MT5 没用,但这套 Python 流程可以直接复用到你自己的欧美日线+宏观拉取上。
class="macro">#Plotting our data set plt.title("EURUSD Close Against FRED Broad Dollar Index") plt.plot(merged_data.loc[:,"close"]) plt.plot(merged_data.loc[:,"Dollar Index"]) class="macro">#Exploratory data analysis sns.heatmap(merged_data.loc[:,all_data].corr(),annot=True) sns.pairplot(merged_data.loc[:,all_data_binary],hue="Binary Target") class="macro">#Define the 3D Plot fig = plt.figure(figsize=(class="num">7,class="num">7)) ax = plt.axes(projection="3d") ax.scatter(merged_data["Dollar Index"],merged_data["Bond Interest"],merged_data["close"],c=merged_data["Binary Target"]) ax.set_xlabel("Dollar Index") ax.set_ylabel("Bond Interest") ax.set_zlabel("EURUSD close")