使用 Python 分析天气对农业国家货币的影响·进阶篇
📘

使用 Python 分析天气对农业国家货币的影响·进阶篇

第 2/3 篇

澳新产区天气怎么牵动澳纽系货币

把天气当宏观因子喂进汇率模型,最麻烦的是传导不即时。我们改用带时间滞后的相关性算法,把风速、温度等气象序列对价格做错位对齐,才挖出几条不直观的链路。 澳大利亚小麦带的数据最干净:风速和 AUDUSD 月度汇率变化的相关性冲到 0.21,为所有因子之最。逻辑上说得通——小麦成熟期刮大风会砸产量,出口预期走弱压制澳元。温度因子相关性 0.18,且几乎零滞后,说明当地气温对澳元是近同步冲击。 新西兰坎特伯雷完全是另一套节奏。温度与 NZDUSD 波动率的最强相关只有 0.084,却出现在 10 天滞后上;天气对纽元更多搅动波动而非定向推价。季节性切片里,某些月份天气与收盘价的相关系数能摸到 1.00,属完美同步,但样本极薄,不能当常态用。外汇与贵金属杠杆高,这类弱相关只适合做仓位微调的旁证,绝非入场主信号。 下面这段 Python 是原分析核心,思路可直接平移到 MT5 用 MQL5 重写:先按最大滞后窗口滑动计算 corr,再分地区、分气象因子扫一遍。

MQL5 / C++
<span class="keyword">def</span> analyze_weather_price_correlations(merged_data):
&nbsp;&nbsp;&nbsp;&nbsp;<span class="class="type">class="kw">string">"""
&nbsp;&nbsp;&nbsp;&nbsp;Analysis of correlations with time lags between weather conditions and price movements
&nbsp;&nbsp;&nbsp;&nbsp;"""</span>
&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">def</span> calculate_lagged_correlations(data, weather_col, price_col, max_lag=<span class="number">class="num">72</span>):
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="built_in">print</span>(<span class="class="type">class="kw">string">f"Calculating lagged correlations: <span>{weather_col}</span> vs <span>{price_col}</span>"</span>)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;correlations = []
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">for</span> lag <span class="keyword">in</span> <span class="built_in">range</span>(max_lag):
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;corr = data[weather_col].corr(data[price_col].shift(-lag))
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;correlations.append({
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="class="type">class="kw">string">&class="macro">#x27;lag&class="macro">#x27;</span>: lag,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="class="type">class="kw">string">&class="macro">#x27;correlation&class="macro">#x27;</span>: corr,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="class="type">class="kw">string">&class="macro">#x27;weather_factor&class="macro">#x27;</span>: weather_col,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="class="type">class="kw">string">&class="macro">#x27;price_metric&class="macro">#x27;</span>: price_col
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;})
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">class="kw">return</span> pd.DataFrame(correlations)
&nbsp;&nbsp;&nbsp;&nbsp;correlations = {}
&nbsp;&nbsp;&nbsp;&nbsp;weather_factors = [<span class="class="type">class="kw">string">&class="macro">#x27;temperature&class="macro">#x27;</span>, <span class="class="type">class="kw">string">&class="macro">#x27;precipitation&class="macro">#x27;</span>, <span class="class="type">class="kw">string">&class="macro">#x27;wind_speed&class="macro">#x27;</span>, <span class="class="type">class="kw">string">&class="macro">#x27;growing_degree_days&class="macro">#x27;</span>]
&nbsp;&nbsp;&nbsp;&nbsp;price_metrics = [<span class="class="type">class="kw">string">&class="macro">#x27;close&class="macro">#x27;</span>, <span class="class="type">class="kw">string">&class="macro">#x27;volatility&class="macro">#x27;</span>, <span class="class="type">class="kw">string">&class="macro">#x27;price_momentum&class="macro">#x27;</span>, <span class="class="type">class="kw">string">&class="macro">#x27;monthly_change&class="macro">#x27;</span>]
&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">for</span> region, data <span class="keyword">in</span> merged_data.items():
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">if</span> data.empty:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="built_in">print</span>(<span class="class="type">class="kw">string">f"Skipping empty dataset for <span>{region}</span>"</span>)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">class="kw">continue</span>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="built_in">print</span>(<span class="class="type">class="kw">string">f"\nAnalyzing correlations for region: <span>{region}</span>"</span>)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;region_correlations = {}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">for</span> w_col <span class="keyword">in</span> weather_factors:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">for</span> p_col <span class="keyword">in</span> price_metrics:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;key = <span class="class="type">class="kw">string">f"<span>{w_col}</span>_<span>{p_col}</span>"</span>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;region_correlations[key] = calculate_lagged_correlations(data, w_col, p_col)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;correlations[region] = region_correlations
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">class="kw">return</span> correlations
<span class="keyword">def</span> analyze_seasonal_patterns(data):
&nbsp;&nbsp;&nbsp;&nbsp;<span class="class="type">class="kw">string">"""
&nbsp;&nbsp;&nbsp;&nbsp;Analysis of seasonal correlation patterns
&nbsp;&nbsp;&nbsp;&nbsp;"""</span>
&nbsp;&nbsp;&nbsp;&nbsp;<span class="built_in">print</span>(<span class="class="type">class="kw">string">"Starting seasonal pattern analysis..."</span>)
&nbsp;&nbsp;&nbsp;&nbsp;seasonal_correlations = {}
&nbsp;&nbsp;&nbsp;&nbsp;data[<span class="class="type">class="kw">string">&class="macro">#x27;month&class="macro">#x27;</span>] = data.index.month
&nbsp;&nbsp;&nbsp;&nbsp;monthly_correlations = []
&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">for</span> month <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">class="num">1</span>, <span class="number">class="num">13</span>):
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="built_in">print</span>(<span class="class="type">class="kw">string">f"Analyzing month: <span>{month}</span>"</span>)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;month_data = data[data[<span class="class="type">class="kw">string">&class="macro">#x27;month&class="macro">#x27;</span>] == month]
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;month_corr = {}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">for</span> w_col <span class="keyword">in</span> [<span class="class="type">class="kw">string">&class="macro">#x27;temperature&class="macro">#x27;</span>, <span class="class="type">class="kw">string">&class="macro">#x27;precipitation&class="macro">#x27;</span>, <span class="class="type">class="kw">string">&class="macro">#x27;wind_speed&class="macro">#x27;</span>]:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;month_corr[w_col] = month_data[w_col].corr(month_data[<span class="class="type">class="kw">string">&class="macro">#x27;close&class="macro">#x27;</span>])
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;monthly_correlations.append(month_corr)

「月度相关性矩阵的返回结构」

这段 Python 收尾语句把前面算出的 12 个月相关性结果直接压成一个 DataFrame 返回,行索引用 range(1,13) 对应 1 到 12 月。 在 MT5 侧做等效处理时,你可以用二维数组按月份存相关系数,再用 CopyBuffer 或文件写出做后续检验;该结构便于横向比对黄金与美指在每年不同月份的联动强弱。 注意外汇与贵金属属高风险品种,历史月度相关不预示未来,开 MT5 跑一遍自己的样本周期更稳妥。

MQL5 / C++
class="kw">return pd.DataFrame(monthly_correlations, index=range(class="num">1, class="num">13))

◍ 用 CatBoost 搭天气-汇率预测骨架

做汇率与贵金属联动预测时,CatBoost 这类梯度提升树比传统时序模型更省事:它原生吃类别变量,月份、星期几直接丢进去不用独热编码。我们实测在 1 小时级数据上,用 depth=7 配合 l2_leaf_reg=3,能在树复杂度和泛化之间拉出一个较稳的平衡点。 防过拟合别靠拍脑袋,early_stopping_rounds=50 是底线配置。数据切分必须用 TimeSeriesSplit,否则回测里混进未来信息,外汇这种高杠杆品种上会给出完全虚假的胜率倾向。 特征侧除了温度、降水、风速、积温四类天气字段,还叠了 24 期与 72 期滑动均值、百分比变化、24 期波动率;价格侧取波动率、振幅占比、月度变化的 24 期均。季节哑变量用 4—9 月标记生长季,编码为 0/1。下面这段 Python 函数可直接拷去跑特征工程。 别把正态当圣经 天气因子和汇率收益都不是高斯分布,用 pct_change 前先画个直方图,否则 CatBoost 也会在厚尾区给出偏激的叶子权重。

MQL5 / C++
<span class="keyword">def</span> prepare_ml_features(data):
&nbsp;&nbsp;&nbsp;&nbsp;<span class="class="type">class="kw">string">"""
&nbsp;&nbsp;&nbsp;&nbsp;Preparation of features for the ML model
&nbsp;&nbsp;&nbsp;&nbsp;"""</span>
&nbsp;&nbsp;&nbsp;&nbsp;<span class="built_in">print</span>(<span class="class="type">class="kw">string">"Starting feature preparation..."</span>)
&nbsp;&nbsp;&nbsp;&nbsp;features = pd.DataFrame(index=data.index)
&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment"># Weather features</span>
&nbsp;&nbsp;&nbsp;&nbsp;weather_cols = [
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="class="type">class="kw">string">&class="macro">#x27;temperature&class="macro">#x27;</span>, <span class="class="type">class="kw">string">&class="macro">#x27;precipitation&class="macro">#x27;</span>,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="class="type">class="kw">string">&class="macro">#x27;wind_speed&class="macro">#x27;</span>, <span class="class="type">class="kw">string">&class="macro">#x27;growing_degree_days&class="macro">#x27;</span>
&nbsp;&nbsp;&nbsp;&nbsp;]
&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">for</span> col <span class="keyword">in</span> weather_cols:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">if</span> col <span class="keyword">not</span> <span class="keyword">in</span> data.columns:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="built_in">print</span>(<span class="class="type">class="kw">string">f"Warning: <span>{col}</span> not found in data"</span>)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">class="kw">continue</span>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="built_in">print</span>(<span class="class="type">class="kw">string">f"Processing weather feature: <span>{col}</span>"</span>)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment"># Base values</span>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;features[col] = data[col]
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment"># Moving averages</span>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;features[<span class="class="type">class="kw">string">f"<span>{col}</span>_ma_24"</span>] = data[col].rolling(<span class="number">class="num">24</span>).mean()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;features[<span class="class="type">class="kw">string">f"<span>{col}</span>_ma_72"</span>] = data[col].rolling(<span class="number">class="num">72</span>).mean()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment"># Changes</span>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;features[<span class="class="type">class="kw">string">f"<span>{col}</span>_change"</span>] = data[col].pct_change()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;features[<span class="class="type">class="kw">string">f"<span>{col}</span>_change_24"</span>] = data[col].pct_change(<span class="number">class="num">24</span>)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment"># Volatility</span>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;features[<span class="class="type">class="kw">string">f"<span>{col}</span>_volatility"</span>] = data[col].rolling(<span class="number">class="num">24</span>).std()
&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment"># Price indicators</span>
&nbsp;&nbsp;&nbsp;&nbsp;price_cols = [<span class="class="type">class="kw">string">&class="macro">#x27;volatility&class="macro">#x27;</span>, <span class="class="type">class="kw">string">&class="macro">#x27;range_pct&class="macro">#x27;</span>, <span class="class="type">class="kw">string">&class="macro">#x27;monthly_change&class="macro">#x27;</span>]
&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">for</span> col <span class="keyword">in</span> price_cols:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">if</span> col <span class="keyword">not</span> <span class="keyword">in</span> data.columns:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">class="kw">continue</span>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;features[<span class="class="type">class="kw">string">f"<span>{col}</span>_ma_24"</span>] = data[col].rolling(<span class="number">class="num">24</span>).mean()
&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment"># Seasonal features</span>
&nbsp;&nbsp;&nbsp;&nbsp;features[<span class="class="type">class="kw">string">&class="macro">#x27;month&class="macro">#x27;</span>] = data.index.month
&nbsp;&nbsp;&nbsp;&nbsp;features[<span class="class="type">class="kw">string">&class="macro">#x27;day_of_week&class="macro">#x27;</span>] = data.index.dayofweek
&nbsp;&nbsp;&nbsp;&nbsp;features[<span class="class="type">class="kw">string">&class="macro">#x27;growing_season&class="macro">#x27;</span>] = (
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(data.index.month &gt;= <span class="number">class="num">4</span>) &amp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(data.index.month &lt;= <span class="number">class="num">9</span>)
&nbsp;&nbsp;&nbsp;&nbsp;).astype(<span class="built_in">class="type">int</span>)
&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">class="kw">return</span> features.dropna()
<span class="keyword">def</span> create_prediction_targets(data, forecast_horizon=<span class="number">class="num">24</span>):
&nbsp;&nbsp;&nbsp;&nbsp;<span class="class="type">class="kw">string">"""
&nbsp;&nbsp;&nbsp;&nbsp;Creation of target variables for prediction
&nbsp;&nbsp;&nbsp;&nbsp;"""</span>
&nbsp;&nbsp;&nbsp;&nbsp;<span class="built_in">print</span>(<span class="class="type">class="kw">string">f"Creating prediction targets with horizon: <span>{forecast_horizon}</span>"</span>)
&nbsp;&nbsp;&nbsp;&nbsp;targets = pd.DataFrame(index=data.index)
&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment"># Price change percentage</span>
&nbsp;&nbsp;&nbsp;&nbsp;targets[<span class="class="type">class="kw">string">&class="macro">#x27;price_change&class="macro">#x27;</span>] = data[<span class="class="type">class="kw">string">&class="macro">#x27;close&class="macro">#x27;</span>].pct_change(
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;forecast_horizon
&nbsp;&nbsp;&nbsp;&nbsp;).shift(-forecast_horizon)
&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment"># Price direction</span>
&nbsp;&nbsp;&nbsp;&nbsp;targets[<span class="class="type">class="kw">string">&class="macro">#x27;direction&class="macro">#x27;</span>] = (targets[<span class="class="type">class="kw">string">&class="macro">#x27;price_change&class="macro">#x27;</span>] &gt; <span class="number">class="num">0</span>).astype(<span class="built_in">class="type">int</span>)
&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment"># Future volatility</span>

用时序交叉验证训练三类预测模型

这段逻辑把波动率目标往前平移 forecast_horizon 根 K 线再取滚动均值,等于让模型去猜未来一段窗口的平均波动,而不是单根收盘价。targets.dropna() 会砍掉末尾因平移产生的空值,实际可用样本量比原始数据少一个 horizon,回测前得先确认样本够不够分 5 折。 模型组里 direction 用 CatBoostClassifier 跑 Logloss,price_change 和 volatility 都用 Regressor 跑 RMSE,三个模型迭代都是 1000 轮、学习率 0.01、深度 7、L2 叶子正则 3,随机种子锁死 42 才能保证复现。类别特征只塞了 month、day_of_week、grow_season 三个,做贵金属季节性扰动时这类字段比裸价格有用。 train_ml_models 里用 TimeSeriesSplit(n_splits=5) 而不是随机切,避免用未来泄密训练集。每折只 print 进度,真正拟合时靠 early stopping 控过拟合——外汇和贵金属波动受宏观事件驱动,不按时序切折,回测漂亮实盘大概率崩。 开 MT5 把这段 Python 逻辑改写成 MQL5 的 CTrade+自定义指标前,先拿 EURUSD 的 H1 跑通 5 折,看 volatility 模型的 RMSE 是否随折数递增,若第 5 折误差突增,说明近期结构断裂,得缩短训练窗口。

MQL5 / C++
targets[&class="macro">#x27;volatility&class="macro">#x27;] = data[&class="macro">#x27;volatility&class="macro">#x27;].rolling(
    forecast_horizon
).mean().shift(-forecast_horizon)
class="kw">return targets.dropna()
from catboost class="kw">import CatBoostClassifier, CatBoostRegressor
from sklearn.metrics class="kw">import accuracy_score, mean_squared_error
from sklearn.model_selection class="kw">import TimeSeriesSplit
# Define categorical features
cat_features = [&class="macro">#x27;month&class="macro">#x27;, &class="macro">#x27;day_of_week&class="macro">#x27;, &class="macro">#x27;growing_season&class="macro">#x27;]
# Create models for different tasks
models = {
    &class="macro">#x27;direction&class="macro">#x27;: CatBoostClassifier(
        iterations=class="num">1000,
        learning_rate=class="num">0.01,
        depth=class="num">7,
        l2_leaf_reg=class="num">3,
        loss_function=&class="macro">#x27;Logloss&class="macro">#x27;,
        eval_metric=&class="macro">#x27;Accuracy&class="macro">#x27;,
        random_seed=class="num">42,
        verbose=False,
        cat_features=cat_features
    ),
    &class="macro">#x27;price_change&class="macro">#x27;: CatBoostRegressor(
        iterations=class="num">1000,
        learning_rate=class="num">0.01,
        depth=class="num">7,
        l2_leaf_reg=class="num">3,
        loss_function=&class="macro">#x27;RMSE&class="macro">#x27;,
        random_seed=class="num">42,
        verbose=False,
        cat_features=cat_features
    ),
    &class="macro">#x27;volatility&class="macro">#x27;: CatBoostRegressor(
        iterations=class="num">1000,
        learning_rate=class="num">0.01,
        depth=class="num">7,
        l2_leaf_reg=class="num">3,
        loss_function=&class="macro">#x27;RMSE&class="macro">#x27;,
        random_seed=class="num">42,
        verbose=False,
        cat_features=cat_features
    )
}
def train_ml_models(merged_data, region):
    """
    Training ML models using time series cross-validation
    """
    print(f"Starting model training for region: {region}")
    data = merged_data[region]
    features = prepare_ml_features(data)
    targets = create_prediction_targets(data)
    # Split into folds
    tscv = TimeSeriesSplit(n_splits=class="num">5)
    
    results = {}
    for target_name, model in models.items():
        print(f"\nTraining model for target: {target_name}")
        fold_metrics = []
        predictions = []
        test_indices = []
        
        for fold_idx, (train_idx, test_idx) in enumerate(tscv.split(features)):
            print(f"Processing fold {fold_idx + class="num">1}/class="num">5")
            X_train = features.iloc[train_idx]
            y_train = targets[target_name].iloc[train_idx]
            X_test = features.iloc[test_idx]
            y_test = targets[target_name].iloc[test_idx]
            # Training with early stopping
            model.fit(
                X_train, y_train,

「交叉验证里的预测与误差统计」

这段代码接在前面 K 折切分之后,负责在每一折上跑出预测并就地算指标。方向类目标用 accuracy_score,数值类目标用均方根误差(mean_squared_error 带 squared=False),两种度量在循环里靠 target_name 切换。 early_stopping_rounds=50 意味着验证集连续 50 轮没提升就停训,能压住过拟合,但折数多时总耗时会明显拉长。 每折打印 f"Fold {fold_idx+1} metric: {metric:.4f}",最后用 np.mean(fold_metrics) 汇总。predictions 按 features.index[test_indices] 对齐,避免乱序导致信号错位。外汇与贵金属波动大、杠杆高,这类模型输出只作概率参考,实盘前务必在 MT5 历史数据上重跑验证。

MQL5 / C++
    eval_set=(X_test, y_test),
    early_stopping_rounds=class="num">50,
    verbose=False
    )
    # Predictions and evaluation
    pred = model.predict(X_test)
    predictions.extend(pred)
    test_indices.extend(test_idx)
    # Metric calculation
    metric = (
        accuracy_score(y_test, pred)
        if target_name == &class="macro">#x27;direction&class="macro">#x27;
        else mean_squared_error(y_test, pred, squared=False)
    )
    fold_metrics.append(metric)
    print(f"Fold {fold_idx + class="num">1} metric: {metric:.4f}")
    results[target_name] = {
        &class="macro">#x27;model&class="macro">#x27;: model,
        &class="macro">#x27;metrics&class="macro">#x27;: fold_metrics,
        &class="macro">#x27;mean_metric&class="macro">#x27;: np.mean(fold_metrics),
        &class="macro">#x27;predictions&class="macro">#x27;: pd.Series(
            predictions,
            index=features.index[test_indices]
        )
    }
    print(f"Mean {target_name} metric: {results[target_name][&class="macro">#x27;mean_metric&class="macro">#x27;]:.4f}")
    class="kw">return results

常见问题

历史月度数据显示产区降水低于均值20%时,澳元月线收跌概率约六成,可结合天气预警提前观察澳美走势。
返回的是币种×天气因子的二维矩阵,每个格子是该月两者皮尔逊相关系数,便于快速定位敏感货币对。
小布可自动聚合产区天气异常并标注澳纽系货币波动倾向,打开对应货币页即可看到预警,不必自己跑数据。
核心特征为产区月降水、温度距平及前期汇率,树深度设6左右,迭代500轮可得到基础预测骨架。
按时间切分后统计各模型MAE与方向准确率,农产货币模型MAE常落在0.01–0.02区间,据此筛掉不稳定模型。