使用 Python 分析天气对农业国家货币的影响·综合运用
🌾

使用 Python 分析天气对农业国家货币的影响·综合运用

(3/3)·从气象 API 到 MT5 行情同步,把五大金融中心的天气异常转成可交易的农产品货币信号

实战向 第 3/3 篇

接上篇,我们已经跑通了单因子的天气—汇率关联,这一篇把数据管道、模型评估和分地区结论全部串起来。很多团队卡在气象数据与报价频率不对齐,导致回测里信号漂亮、实盘里全废,本篇直接给可复用的同步方案。

◍ 五折回测下的三类模型怎么打分

在 5 年历史样本上跑机器学习,最忌讳一次性拟合后直接信。我们用五折滑动窗口把数据切成 5 段轮流验证,每个市场区域都单独建三套模型:价格方向(分类)、价格变动幅度(回归)、波动率(回归)。外汇与贵金属杠杆高、跳空频繁,这种切窗法至少能压住一点过拟合的幻觉。 下面这段 Python 评估函数就是干这事的核心。它遍历所有区域,把方向预测的准确率、变动幅度的 RMSE、波动率的 RMSE 分别打印出来,并保留每折指标方便你算最大最小区间。

MQL5 / C++
class="kw">import matplotlib.pyplot as plt
class="kw">import seaborn as sns
from sklearn.metrics class="kw">import confusion_matrix, classification_report
def evaluate_model_performance(results, region_data):
    """
    Comprehensive model evaluation across all regions
    """
    print(f"\nEvaluating model performance for {len(results)} regions")
    evaluation = {}
    
    for region, models in results.items():
        print(f"\nAnalyzing {region} performance:")
        region_metrics = {
            &class="macro">#x27;direction&class="macro">#x27;: {
                &class="macro">#x27;accuracy&class="macro">#x27;: models[&class="macro">#x27;direction&class="macro">#x27;][&class="macro">#x27;mean_metric&class="macro">#x27;],
                &class="macro">#x27;fold_metrics&class="macro">#x27;: models[&class="macro">#x27;direction&class="macro">#x27;][&class="macro">#x27;metrics&class="macro">#x27;],
                &class="macro">#x27;max_accuracy&class="macro">#x27;: max(models[&class="macro">#x27;direction&class="macro">#x27;][&class="macro">#x27;metrics&class="macro">#x27;]),
                &class="macro">#x27;min_accuracy&class="macro">#x27;: min(models[&class="macro">#x27;direction&class="macro">#x27;][&class="macro">#x27;metrics&class="macro">#x27;])
            },
            &class="macro">#x27;price_change&class="macro">#x27;: {
                &class="macro">#x27;rmse&class="macro">#x27;: models[&class="macro">#x27;price_change&class="macro">#x27;][&class="macro">#x27;mean_metric&class="macro">#x27;],
                &class="macro">#x27;fold_metrics&class="macro">#x27;: models[&class="macro">#x27;price_change&class="macro">#x27;][&class="macro">#x27;metrics&class="macro">#x27;]
            },
            &class="macro">#x27;volatility&class="macro">#x27;: {
                &class="macro">#x27;rmse&class="macro">#x27;: models[&class="macro">#x27;volatility&class="macro">#x27;][&class="macro">#x27;mean_metric&class="macro">#x27;],
                &class="macro">#x27;fold_metrics&class="macro">#x27;: models[&class="macro">#x27;volatility&class="macro">#x27;][&class="macro">#x27;metrics&class="macro">#x27;]
            }
        }
        
        print(f"Direction prediction accuracy: {region_metrics[&class="macro">#x27;direction&class="macro">#x27;][&class="macro">#x27;accuracy&class="macro">#x27;]:.class="num">2%}")
        print(f"Price change RMSE: {region_metrics[&class="macro">#x27;price_change&class="macro">#x27;][&class="macro">#x27;rmse&class="macro">#x27;]:.4f}")
        print(f"Volatility RMSE: {region_metrics[&class="macro">#x27;volatility&class="macro">#x27;][&class="macro">#x27;rmse&class="macro">#x27;]:.4f}")
        
        evaluation[region] = region_metrics
    
    class="kw">return evaluation
def plot_feature_importance(models, region):
    """
    Visualize feature importance for each model type
    """
    plt.figure(figsize=(class="num">15, class="num">10))
    
    for target, model_info in models.items():
        feature_importance = pd.DataFrame({
            &class="macro">#x27;feature&class="macro">#x27;: model_info[&class="macro">#x27;model&class="macro">#x27;].feature_names_,
            &class="macro">#x27;importance&class="macro">#x27;: model_info[&class="macro">#x27;model&class="macro">#x27;].feature_importances_
        })
        feature_importance = feature_importance.sort_values(&class="macro">#x27;importance&class="macro">#x27;, ascending=False)
逐行拆一下:import 三行是拉画图与 sklearn 评估工具;evaluate_model_performance 函数先打印区域总数,再循环每个区域取三类模型的均值与每折指标,方向类额外算 max/min 准确率,最后返回嵌套字典。plot_feature_importance 则开 15x10 画布,把每个目标的 feature_importances_ 排降序,便于肉眼看哪些因子在盯盘里真正管用。 实操上,你把这个脚本接在自己 MT5 导出的 5 年 CSV 上,若某区域方向准确率均值低于 52%,大概率该品种噪声盖过信号,贵金属夜盘常出这情况,此时别硬上模型信号。

MQL5 / C++
class="kw">import matplotlib.pyplot as plt
class="kw">import seaborn as sns
from sklearn.metrics class="kw">import confusion_matrix, classification_report
def evaluate_model_performance(results, region_data):
    """
    Comprehensive model evaluation across all regions
    """
    print(f"\nEvaluating model performance for {len(results)} regions")
    evaluation = {}
    
    for region, models in results.items():
        print(f"\nAnalyzing {region} performance:")
        region_metrics = {
            &class="macro">#x27;direction&class="macro">#x27;: {
                &class="macro">#x27;accuracy&class="macro">#x27;: models[&class="macro">#x27;direction&class="macro">#x27;][&class="macro">#x27;mean_metric&class="macro">#x27;],
                &class="macro">#x27;fold_metrics&class="macro">#x27;: models[&class="macro">#x27;direction&class="macro">#x27;][&class="macro">#x27;metrics&class="macro">#x27;],
                &class="macro">#x27;max_accuracy&class="macro">#x27;: max(models[&class="macro">#x27;direction&class="macro">#x27;][&class="macro">#x27;metrics&class="macro">#x27;]),
                &class="macro">#x27;min_accuracy&class="macro">#x27;: min(models[&class="macro">#x27;direction&class="macro">#x27;][&class="macro">#x27;metrics&class="macro">#x27;])
            },
            &class="macro">#x27;price_change&class="macro">#x27;: {
                &class="macro">#x27;rmse&class="macro">#x27;: models[&class="macro">#x27;price_change&class="macro">#x27;][&class="macro">#x27;mean_metric&class="macro">#x27;],
                &class="macro">#x27;fold_metrics&class="macro">#x27;: models[&class="macro">#x27;price_change&class="macro">#x27;][&class="macro">#x27;metrics&class="macro">#x27;]
            },
            &class="macro">#x27;volatility&class="macro">#x27;: {
                &class="macro">#x27;rmse&class="macro">#x27;: models[&class="macro">#x27;volatility&class="macro">#x27;][&class="macro">#x27;mean_metric&class="macro">#x27;],
                &class="macro">#x27;fold_metrics&class="macro">#x27;: models[&class="macro">#x27;volatility&class="macro">#x27;][&class="macro">#x27;metrics&class="macro">#x27;]
            }
        }
        
        print(f"Direction prediction accuracy: {region_metrics[&class="macro">#x27;direction&class="macro">#x27;][&class="macro">#x27;accuracy&class="macro">#x27;]:.class="num">2%}")
        print(f"Price change RMSE: {region_metrics[&class="macro">#x27;price_change&class="macro">#x27;][&class="macro">#x27;rmse&class="macro">#x27;]:.4f}")
        print(f"Volatility RMSE: {region_metrics[&class="macro">#x27;volatility&class="macro">#x27;][&class="macro">#x27;rmse&class="macro">#x27;]:.4f}")
        
        evaluation[region] = region_metrics
    
    class="kw">return evaluation
def plot_feature_importance(models, region):
    """
    Visualize feature importance for each model type
    """
    plt.figure(figsize=(class="num">15, class="num">10))
    
    for target, model_info in models.items():
        feature_importance = pd.DataFrame({
            &class="macro">#x27;feature&class="macro">#x27;: model_info[&class="macro">#x27;model&class="macro">#x27;].feature_names_,
            &class="macro">#x27;importance&class="macro">#x27;: model_info[&class="macro">#x27;model&class="macro">#x27;].feature_importances_
        })
        feature_importance = feature_importance.sort_values(&class="macro">#x27;importance&class="macro">#x27;, ascending=False)

把模型解释拆开看:特征重要性与季节准确率

这段 Python 代码承担三件实事:画 Top10 特征柱状图、按月统计方向预测准确率、绘天气与价格相关性热力图。它不直接下单,但能告诉你哪类因子在拖模型后腿。 plt.subplot(3,1, list(models.keys()).index(target)+1) 把多模型排成纵向三栏,sns.barplot 取 feature_importance.head(10) 画每个模型的前 10 重要特征。若某贵金属模型里 'real_rate' 排第一,说明利率预期比季节性权重更大,调参应优先动它。 visualize_seasonal_patterns 里 monthly_accuracy 用 range(1,13) 建 12 个月索引,对每月预测与 (close.pct_change()>0) 的真实涨跌算 accuracy_score。曾经某外汇对 7 月准确率掉到 0.42、2 月升到 0.61,这种季节性塌陷靠肉眼看 equity 曲线很难察觉。 plot_correlation_heatmap 用 RdYlBu 配 center=0 画相关系数,annot=True 标到小数点后两位。若 EURUSD 与某天气变量的格子里写 0.71,说明两者同向性强,可作为小布 AIGC 筛选特征的旁路验证。外汇与贵金属杠杆高,这类统计关系只作概率参考,实盘前务必在 MT5 用历史数据复跑一遍。

MQL5 / C++
plt.subplot(class="num">3, class="num">1, list(models.keys()).index(target) + class="num">1)
sns.barplot(x=&class="macro">#x27;importance&class="macro">#x27;, y=&class="macro">#x27;feature&class="macro">#x27;, data=feature_importance.head(class="num">10))
plt.title(f&class="macro">#x27;{target.capitalize()} Model - Top class="num">10 Important Features&class="macro">#x27;)

plt.tight_layout()
plt.show()
def visualize_seasonal_patterns(results, region_data):
    """
    Create visualization of seasonal patterns in predictions
    """
    for region, data in region_data.items():
        print(f"\nVisualizing seasonal patterns for {region}")
        
        # Create monthly aggregation of accuracy
        monthly_accuracy = pd.DataFrame(index=range(class="num">1, class="num">13))
        data[&class="macro">#x27;month&class="macro">#x27;] = data.index.month
        
        for month in range(class="num">1, class="num">13):
            month_predictions = results[region][&class="macro">#x27;direction&class="macro">#x27;][&class="macro">#x27;predictions&class="macro">#x27;][
                data.index.month == month
            ]
            month_actual = (data[&class="macro">#x27;close&class="macro">#x27;].pct_change() > class="num">0)[
                data.index.month == month
            ]
            
            accuracy = accuracy_score(
                month_actual,
                month_predictions
            )
            monthly_accuracy.loc[month, &class="macro">#x27;accuracy&class="macro">#x27;] = accuracy
        
        # Plot seasonal accuracy
        plt.figure(figsize=(class="num">12, class="num">6))
        monthly_accuracy[&class="macro">#x27;accuracy&class="macro">#x27;].plot(kind=&class="macro">#x27;bar&class="macro">#x27;)
        plt.title(f&class="macro">#x27;Seasonal Prediction Accuracy - {region}&class="macro">#x27;)
        plt.xlabel(&class="macro">#x27;Month&class="macro">#x27;)
        plt.ylabel(&class="macro">#x27;Accuracy&class="macro">#x27;)
        plt.show()
def plot_correlation_heatmap(correlation_data):
    """
    Create heatmap visualization of correlations
    """
    plt.figure(figsize=(class="num">12, class="num">8))
    sns.heatmap(
        correlation_data,
        cmap=&class="macro">#x27;RdYlBu&class="macro">#x27;,
        center=class="num">0,
        annot=True,
        fmt=&class="macro">#x27;.2f&class="macro">#x27;
    )
    plt.title(&class="macro">#x27;Weather-Price Correlation Heatmap&class="macro">#x27;)
    plt.tight_layout()
    plt.show()

「三地气象模型对澳纽加元的交叉验证」

把小麦带、坎特伯雷、加拿大草原三处的天气信号分别接回 AUDUSD、NZDUSD 与 USDCAD 相关品种,方向预测平均准确率落在 56.92%–62.81% 区间,均明显脱离随机基准。其中新西兰坎特伯雷对 NZDUSD 的峰值准确率冲到 75.44%,但最低一折掉到 54.39%,说明气象因子在某些气候异常周会失灵。 价格变动预测的 RMSE 三地差异显著:加拿大草原仅 0.0159,澳大利亚小麦带 0.0303,新西兰 0.0281。波动率 RMSE 全部压在 0.0015–0.0023 窄带内,意味着模型对波动幅度的刻画比绝对价格位移更稳。 外汇与贵金属受宏观扰动极多,气象派生信号仅作辅助概率参考,实盘须自担高风险。开 MT5 把这三组 RMSE 当阈值,对比你本地回测的残差分布,若明显宽于 0.03 就该怀疑特征泄漏。

◍ 农业货币汇率的月度命中率窗口

把模型逐月准确率拉出来看,农业相关货币对存在明显的季节聚集。AUDUSD 在 12 月至次年 2 月命中率偏高,对应小麦灌浆到成熟的关键期;NZDUSD 在牛奶高产季更稳;USDCAD 则在草原作物旺盛生长阶段表现更好。 这种分布不是噪声,而是天气通过农产品供给预期传导到汇率的价格行为痕迹。外汇与贵金属杠杆高、波动剧烈,此类季节性只提高概率倾向,不构成方向保证。 下面这段 Python 把分地区结果按月份拆开算准确率并打印,再画图对比,思路可直接搬进 MT5 的 Python 桥接环境验证。

MQL5 / C++
def analyze_model_seasonality(results, data):
    """
    Analyze seasonal performance patterns of the models
    """
    print("Starting seasonal analysis of model performance")
    seasonal_metrics = {}
    
    for region, region_results in results.items():
        print(f"\nAnalyzing {region} seasonal patterns:")
        
        # Extract predictions and actual values
        predictions = region_results[&class="macro">#x27;direction&class="macro">#x27;][&class="macro">#x27;predictions&class="macro">#x27;]
        actuals = data[region][&class="macro">#x27;close&class="macro">#x27;].pct_change() > class="num">0
        
        # Calculate monthly accuracy
        monthly_acc = []
        for month in range(class="num">1, class="num">13):
            month_mask = predictions.index.month == month
            if month_mask.any():
                acc = accuracy_score(
                    actuals[month_mask], 
                    predictions[month_mask]
                )
                monthly_acc.append(acc)
                print(f"Month {month} accuracy: {acc:.class="num">2%}")
        
        seasonal_metrics[region] = pd.Series(
            monthly_acc, 
            index=range(class="num">1, class="num">13)
        )
    
    class="kw">return seasonal_metrics

def plot_seasonal_performance(seasonal_metrics):
    """
    Visualize seasonal performance patterns
    """
    plt.figure(figsize=(class="num">15, class="num">8))
    
    for region, metrics in seasonal_metrics.items():
        plt.plot(metrics.index, metrics.values, label=region, marker=&class="macro">#x27;o&class="macro">#x27;)
    
    plt.title(&class="macro">#x27;Model Accuracy by Month&class="macro">#x27;)
    plt.xlabel(&class="macro">#x27;Month&class="macro">#x27;)
    plt.ylabel(&class="macro">#x27;Accuracy&class="macro">#x27;)
    plt.legend()
    plt.grid(True)
    plt.show()
逐行看:函数先打印启动信息并建空字典存结果;循环每个地区,取预测方向与真实涨跌(收盘价环比为正);按月跑掩码,有样本就用 accuracy_score 算准度并收进列表;最后包成以月份为索引的序列返回。绘图函数则把各地区月度准确率连成折线,标好坐标轴并显示网格,一眼能看出哪几个月偏离基线。 开 MT5 接 Python 跑一遍,把你常做的农业货币对塞进 results,就能知道自己的策略是不是也吃季节饭。

MQL5 / C++
def analyze_model_seasonality(results, data):
    """
    Analyze seasonal performance patterns of the models
    """
    print("Starting seasonal analysis of model performance")
    seasonal_metrics = {}
    
    for region, region_results in results.items():
        print(f"\nAnalyzing {region} seasonal patterns:")
        
        # Extract predictions and actual values
        predictions = region_results[&class="macro">#x27;direction&class="macro">#x27;][&class="macro">#x27;predictions&class="macro">#x27;]
        actuals = data[region][&class="macro">#x27;close&class="macro">#x27;].pct_change() > class="num">0
        
        # Calculate monthly accuracy
        monthly_acc = []
        for month in range(class="num">1, class="num">13):
            month_mask = predictions.index.month == month
            if month_mask.any():
                acc = accuracy_score(
                    actuals[month_mask], 
                    predictions[month_mask]
                )
                monthly_acc.append(acc)
                print(f"Month {month} accuracy: {acc:.class="num">2%}")
        
        seasonal_metrics[region] = pd.Series(
            monthly_acc, 
            index=range(class="num">1, class="num">13)
        )
    
    class="kw">return seasonal_metrics
def plot_seasonal_performance(seasonal_metrics):
    """
    Visualize seasonal performance patterns
    """
    plt.figure(figsize=(class="num">15, class="num">8))
    
    for region, metrics in seasonal_metrics.items():
        plt.plot(metrics.index, metrics.values, label=region, marker=&class="macro">#x27;o&class="macro">#x27;)
    
    plt.title(&class="macro">#x27;Model Accuracy by Month&class="macro">#x27;)
    plt.xlabel(&class="macro">#x27;Month&class="macro">#x27;)
    plt.ylabel(&class="macro">#x27;Accuracy&class="macro">#x27;)
    plt.legend()
    plt.grid(True)
    plt.show()

画得少,看得清

把天气变量接进汇率预测,回测给出的命中率并不玄学:AUDUSD 平均 62.67%、NZDUSD 62.81%、USDCAD 56.92%,且集中在农业周期的关键窗口。 实操上不用盯全年的气象图——AUDUSD 只在 12 至 2 月看风速与温度,NZDUSD 抓乳制品旺季做中短期,USDCAD 挑播种与收割季择机,信号密度够用就好。 模型精度依赖数据常更,尤其市场剧烈波动时旧样本会快速失效;外汇与贵金属杠杆高、回撤快,上述关联只是概率倾向,真要上 MT5 验证建议先用策略测试器跑一轮再谈仓位。

把跨源对齐交给小布
这些诊断小布盯盘的 AIGC 已内置,打开对应品种页即可看到天气异常与 AUDUSD、NZDUSD、USDCAD 的偏离提示,你只需判断要不要动手。

常见问题

两者时间戳粒度不同,气象多为 hourly 而报价有 tick 聚合,普通 join 会丢掉大量非整点样本,merge_asof 按最近时间戳向后匹配更稳。
可以,小布盯盘的品种页已内置气象异常与汇率偏离的对照视图,省去自己跑 Meteostat 与 MT5 同步的重复劳动。
加拿大草原区播种与收割季的 5—9 月概率上关联更强,但需结合降水强度过滤假信号。
澳新与加拿大的作物周期和金融风险敞口不同,统一评估会掩盖区域特异性,分地区看更贴近实盘。