价格行为分析工具包开发(第 35 部分):预测模型训练与部署·综合运用
📘

价格行为分析工具包开发(第 35 部分):预测模型训练与部署·综合运用

第 3/3 篇

◍ 用梯度提升给每个品种单独训信号模型

CSV 里已经堆够了 MT5 历史采集来的行情特征,下一步就是进 Python 把模型跑出来。思路不复杂:为每个交易品种单独训一个梯度提升分类器,同时再训一个跨品种的全局模型,输出都是三分类——BUY / SELL / WAIT,对应前瞻周期后的价格倾向。 梯度提升是顺序建树,后一棵树专门修正前一棵的残差,所以对金融序列里的噪声容忍度偏高,也能啃下特征间的非线性关系。代码里用 scikit-learn 的 Pipeline 把 StandardScaler 和 GradientBoostingClassifier 串起来,训练前先对所有特征做归一化。 参数上注意 n_estimators=400、learning_rate=0.05、max_depth=3、random_state=42:树深压到 3 是为了防过拟合,学习率小意味着要靠 400 轮慢慢收敛。若某个品种清洗后样本不足 400 行,脚本会直接跳过不存模型,这也是实盘前该查的坑。 外汇与贵金属波动受杠杆和突发事件影响,模型给出的只是概率信号,部署后仍需人工复核与风控。 别把样本量门槛当摆设 脚本里 len(d) < 400 就跳过,说明小样本品种训出来的模型基本不可信。上 MT5 拉数据前,先确认你自己关注的品种历史根数够不够,不然训完发现一半没模型。

MQL5 / C++
# class="num">3) TRAIN MODELS
def build_pipe(X, y):
    """
    Construct and fit a pipeline: StandardScaler → GradientBoostingClassifier.
    """
    pipe = Pipeline([
        ("sc", StandardScaler()),
        ("gb", GradientBoostingClassifier(
            n_estimators=class="num">400,      # number of boosting rounds
            learning_rate=class="num">0.05,    # shrinkage factor per tree
            max_depth=class="num">3,           # depth of each tree
            random_state=class="num">42        # reproducibility
        ))
    ])
    pipe.fit(X, y)
    class="kw">return pipe
def train_models():
    """
    Load the CSV, clean it, train per-symbol and global Gradient Boosting models, and save to disk.
    """
    if not Path(CSV_FILE).exists():
        sys.exit("No training_set.csv")
    # Read and sanitize
    df = pd.read_csv(CSV_FILE)
    if "symbol" not in df.columns:
        sys.exit("CSV missing &class="macro">#x27;symbol&class="macro">#x27; column")
    # Ensure numeric features
    for col in FEATURES:
        df[col] = pd.to_numeric(df[col], errors="coerce")
    bad = df[FEATURES].isna().any(axis=class="num">1).sum()
    if bad:
        print(f"Discarding {bad} malformed rows")
        df = df.dropna(subset=FEATURES)
    # Train a Gradient Boosting model for each symbol
    for sym in SYMBOLS:
        d = df[df.symbol == sym]
        if len(d) < class="num">400:
            print("Skip", sym, "(few rows)")
            class="kw">continue
        model = build_pipe(
            d[FEATURES],
            d.label.map({"WAIT": class="num">0, "BUY": class="num">1, "SELL": class="num">2})
        )
        joblib.dump(model, Path(MODEL_DIR) / f"{sym.replace(&class="macro">#x27; &class="macro">#x27;, &class="macro">#x27;_&class="macro">#x27;)}.pkl")
        print("model", sym, "saved")
    # Train and save a global Gradient Boosting model
    global_model = build_pipe(
        df[FEATURES],
        df.label.map({"WAIT": class="num">0, "BUY": class="num">1, "SELL": class="num">2})
    )
    joblib.dump(global_model, GLOBAL_PKL)

训练脚本跑完后的模型落地现象

在 MT5 外接的 Python 分析引擎里直接执行 python engine.py train,终端会先吐出一行 Discarding 1152650 malformed rows,说明原始tick或合成数据里有超过百万行因格式不合被丢弃,这一步没跑干净后面模型会带偏。 紧接着控制台按品种顺序写出 model Boom 900 Index savedmodel Boom 1000 Index savedmodel Boom 500 Index savedmodel Crash 500 Index savedmodel Boom 300 Index saved 等,覆盖 Boom 与 Crash 系列指数,最后以 All models saved 收尾,代表本地多标的模型权重已落盘。 这类输出只证明训练流程通了,不证明任何品种后续一定走出对应暴涨暴跌形态;外汇与合成指数标的杠杆高、跳空频繁,实盘加载前建议在策略测试器用历史数据回放验证各模型信号胜率。

MQL5 / C++
print("global model saved")
python engine.py train
C:\Users\hp\Pictures\Saved Pictures\Analysis EA>python engine.py train
Discarding class="num">1152650 malformed rows
model Boom class="num">900 Index saved
model Boom class="num">1000 Index saved
model Boom class="num">500 Index saved
model Crash class="num">500 Index saved
model Boom class="num">300 Index saved
....................................
....................................
All models saved

「EA 接 Python 后端的实盘联调」

训练进程用 Ctrl+C 掐掉之后,直接跑 python engine.py serve 把推理服务起起来,它会加载训好的模型并开始吐实时信号。MT5 这边要把对应品种的 EA 挂上去,再去 工具 → 选项 → 智能交易系统 里勾选允许 WebRequest,把 Python 服务地址加进白名单,否则 EA 连不上后端。 HTTP 200 代表后端正常收包解析。实测每个 EA 实例都能拿到 200,且在 50 毫秒内回建议。比如 Crash 1000 Index 在 00:31:59.717 返回买入概率 0%、卖出 2.6%、强度仅 3%,没过阈值所以 EA 给的是 WAIT;而 37 毫秒后的 Boom 1000 Index 返回买入 99.4%、强度 0.99,直接触发 OPEN BUY。 日志里有时 OPEN 指令进了 MT5 日志但图表不画箭头,这跟信号强度有关,不是连接故障。外汇与指数差价合约波动剧烈、杠杆风险高,这类信号仅作概率参考,实盘前务必在模拟盘验证延迟与白名单配置。

MQL5 / C++
python engine.py serve
<span class="number">class="num">2025.07</span><span class="number">.class="num">30</span> <span class="number">class="num">00</span>:<span class="number">class="num">31</span>:<span class="number">class="num">59.717</span> Spike DETECTOR(<span>Crash <span class="number">class="num">1000</span> Index,M1</span>)&nbsp;&nbsp;&nbsp;&nbsp;[SpikeEA] &lt;&lt;&lt; HTTP <span class="number">class="num">200</span> – {<span class="class="type">class="kw">string">"Pbuy"</span>:<span class="number">class="num">0.0</span>,<span class="class="type">class="kw">string">"Psell"</span>:<span class="number">class="num">0.026</span>,<span class="class="type">class="kw">string">"scale_in"</span>:null
,<span class="class="type">class="kw">string">"side"</span>:<span class="class="type">class="kw">string">"NONE"</span>,<span class="class="type">class="kw">string">"signal"</span>:<span class="class="type">class="kw">string">"WAIT"</span>,<span class="class="type">class="kw">string">"strength"</span>:<span class="number">class="num">0.03</span>
<span class="number">class="num">2025.07</span><span class="number">.class="num">30</span> <span class="number">class="num">00</span>:<span class="number">class="num">31</span>:<span class="number">class="num">59.754</span> Spike DETECTOR <span>(Boom <span class="number">class="num">1000</span> Index,M1)</span>&nbsp;&nbsp;&nbsp;&nbsp; [SpikeEA] &lt;&lt;&lt; HTTP <span class="number">class="num">200</span> – {<span class="class="type">class="kw">string">"Pbuy"</span>:<span class="number">class="num">0.994</span>,<span class="class="type">class="kw">string">"Psell"</span>:<span class="number">class="num">0.0</span>,<span class="class="type">class="kw">string">"scale_in"</span>:null
,<span class="class="type">class="kw">string">"side"</span>:<span class="class="type">class="kw">string">"BUY"</span>,<span class="class="type">class="kw">string">"signal"</span>:<span class="class="type">class="kw">string">"OPEN"
, </span><span class="class="type">class="kw">string">"strength"</span>:<span class="number">class="num">0.99</span>
<span class="number">class="num">2025.07</span><span class="number">.class="num">25</span> <span class="number">class="num">19</span>:<span class="number">class="num">55</span>:<span class="number">class="num">01.445</span> Spike DETECTOR(Boom <span class="number">class="num">1000</span> Index,M1)&nbsp;&nbsp;&nbsp;&nbsp; [SpikeEA] &lt;&lt;&lt; HTTP <span class="number">class="num">200</span> – {<span class="class="type">class="kw">string">"Pbuy"</span>:<span class="number">class="num">0.999</span>,<span class="class="type">class="kw">string">"Psell"</span>:<span class="number">class="num">0.0</span>,<span class="class="type">class="kw">string">"scale_in"</span>:null
,<span class="class="type">class="kw">string">"<span>side"</span></span><span>:<span class="class="type">class="kw">string">"BUY"</span>,<span class="class="type">class="kw">string">"signal"</span>:<span class="class="type">class="kw">string">"OPEN"</span>,<span class="class="type">class="kw">string">"strength"</span>:<span class="number">class="num">1.0</span></span>

◍ 别急着下结论

把 MQL5 的 EA 当成特征管线、Python 的 engine.py 当作模型服务端,这条跨语言流水线真正跑通后,实盘里梯度提升模型能在 50 毫秒内把 BUY/SELL/WAIT 回传给 MT5,EA 再按信号下单。 对已经用 EA 采齐了价格脉冲、MACD 背离、RSI、ATR、卡尔曼滤波斜率这些特征的账户,下面两条命令就是起服务的全部动作,collect 与 history 都可跳过: python engine.py train python engine.py serve 外汇与贵金属杠杆高、滑点跳空频繁,这套信号只是概率倾向,不是保本指令;真要上生产,建议先调超参数、加新指标,或把 Python 服务容器化再做跨品种验证。

MQL5 / C++
python engine.py train
python engine.py serve

常见问题

要分开。不同品种波动结构差异大,建议每个品种单独切样本、单独定特征和树深,共享一套代码但独立存模型文件。
落地时常见阈值过滤更严、实时特征延迟补齐导致样本被丢弃。先比对离线回测与实盘特征快照,确认不是数据错位再调阈值。
可以。小布能按品种拉出近期信号触发与价格背离情况,标出模型可能失效的时段,你重点复核这些就行。
先测本地回环延迟,限制每根 K 线只发一次请求并加超时重试。若仍高延迟,把特征计算前置到 EA 端,后端只做推理。
别急着下结论。先按震荡/趋势分段统计命中率,若震荡段持续偏低,加一个波动率门控过滤再决定去留。