Scikit-Learn分类模型与ONNX导出:从鸢尾花任务看懂MQL5推理链路(基础篇)
(1/3)· 不写一行C++也能把Python训练的Classifier塞进EA?先搞懂格式与基础模型
用 Scikit-Learn 训分类器再倒进 MT5
机器学习干的事和写死规则不一样:你不用把判别逻辑形式化,计算机会从数据里自己学出映射。分类任务就是给定一组特征,模型输出它属于哪几个固定类别里每个类的概率;回归则是估一个数值。Scikit-learn 里这两类工具都很全,但选哪个模型得看数据本身,不同方法有效性差异很大。 ONNX-ML 是 ONNX 标准里专门给 ML 模型用的子集,能描述分类、回归、聚类等结构,方便跨平台搬模型和跑推理。MetaTrader 5 从支持 ONNX Runtime 之后,就可以直接加载这类导出模型做实时判断。 这篇文章里我们拿 Fisher 鸢尾花数据集做例子,把 Scikit-learn 里的分类模型都跑一遍,再转成 ONNX 塞进 MQL5 程序。完整鸢尾花数据集上会对比原始模型和 ONNX 版的准确性,你能直接开 MT5 照这套流程验证导出后精度掉没掉。
「分类器全家桶与 ONNX 落地路径」
这一节把 MT5 里能接的 Scikit-learn 分类模型一次性铺开,从费舍尔鸢尾花基准数据集起手,覆盖 SVC、LinearSVC、NuSVC 到 27 类树集成与贝叶斯变体,共 27 个可转 ONNX 的主干模型加 6 个不可转模型。 每个主干模型都按三条线走:Python 侧建模型代码、MQL5 侧推理代码、ONNX 中间表示文件,读者开 MT5 后能直接对照目录里的 2.x.2 小节抄处理代码。
- 28 节会横向跑完所有 ONNX 模型算准确率并出对比图,这是验证哪个分类器在外汇小时线标签上泛化更好的硬基准,不是拍脑袋选模型。
DummyClassifier、GaussianProcessClassifier 等 6 个模型卡在 ONNX 转换外,只能留在 Python 回测,实盘 EA 接不进来的部分要心里有数。
◍ 在 MT5 里用 Python 把鸢尾花画出来
鸢尾花数据集是分类任务里的老基准,共 150 个样本,三个品种各 50 条,每条带花萼长、花萼宽、花瓣长、花瓣宽四个厘米级数值特征和一个类别标签。它虽不直接关联行情,但拿来做 ML 流程验证很合适:样本量小、结构清晰,跑通后你能照同样管道接自己的 tick 特征。 MT5 的 MetaEditor 支持建 Python 脚本:文件菜单选新建,在向导里命名如 IRIS.py,库引用先留空即可。脚本写完后点编译,图就会弹在屏幕上,不需要额外配置环境。 散点图能直接看出品种在特征空间里的分离度。花萼长/宽图上,山鸢尾(label 0)聚成一团且普遍更短更宽;花瓣长/宽图上,山鸢尾最短最窄,维吉尼亚(label 2)最长最宽,杂色(label 1)居中——这种线性可分性正是后面训分类器的前提。 下面这段脚本就是前述两张图的来源,逐行拆一下便于你改参数自己跑: # 注释行:画鸢尾花特征散点图,版权与链接信息略 import matplotlib.pyplot as plt —— 引入绘图库,别名 plt from sklearn import datasets —— 从 sklearn 取内置数据集 iris = datasets.load_iris() —— 载入鸢尾花数据对象 X = iris.data —— 取 150×4 的特征矩阵 y = iris.target —— 取 150 个类别标签(0/1/2) sepal_length = X[:, 0] —— 切出第 1 列:花萼长 sepal_width = X[:, 1] —— 切出第 2 列:花萼宽 plt.figure(figsize=(8, 6)) —— 建 8×6 英寸画布 plt.scatter(..., c=y, cmap=plt.cm.Set1, edgecolor='k') —— 按标签着色、黑边描点 plt.xlabel / ylabel / title —— 轴与标题文案 plt.colorbar(label='Iris Species', ticks=[0,1,2]) —— 右侧图例对应三品种 plt.show() —— 渲染显示 后面注释掉的 savefig 是可选项,取消注释能存 PNG;再往下同理切出花瓣长(X[:,2])宽(X[:,3])画第二张。外汇与贵金属交易高风险,此类 ML 练习仅用于工具链熟悉,不代表任何实盘胜率。
# The script shows the scatter plot of the Iris dataset features # Copyright class="num">2023, MetaQuotes Ltd. # [MQL5官方文档] class="kw">import matplotlib.pyplot as plt from sklearn class="kw">import datasets # load the Iris dataset iris = datasets.load_iris() X = iris.data y = iris.target # extract sepal length and sepal width(the first two features) sepal_length = X[:, class="num">0] sepal_width = X[:, class="num">1] # create a scatter plot plt.figure(figsize=(class="num">8, class="num">6)) plt.scatter(sepal_length, sepal_width, c=y, cmap=plt.cm.Set1, edgecolor=&class="macro">#x27;k&class="macro">#x27;) plt.xlabel(&class="macro">#x27;Sepal Length(cm)&class="macro">#x27;) plt.ylabel(&class="macro">#x27;Sepal Width(cm)&class="macro">#x27;) plt.title(&class="macro">#x27;Scatter Plot for Sepal Length and Sepal Width&class="macro">#x27;) plt.colorbar(label=&class="macro">#x27;Iris Species&class="macro">#x27;, ticks=[class="num">0, class="num">1, class="num">2]) plt.show() # save the scatter plot to a file(optional) # plt.savefig(&class="macro">#x27;scatter_plot_sepal_length_width.png&class="macro">#x27;) # Extract petal length and petal width(the third and fourth features) petal_length = X[:, class="num">2] petal_width = X[:, class="num">3] # create a scatter plot plt.figure(figsize=(class="num">8, class="num">6)) plt.scatter(petal_length, petal_width, c=y, cmap=plt.cm.Set1, edgecolor=&class="macro">#x27;k&class="macro">#x27;) plt.xlabel(&class="macro">#x27;Petal Length(cm)&class="macro">#x27;) plt.ylabel(&class="macro">#x27;Petal Width(cm)&class="macro">#x27;) plt.title(&class="macro">#x27;Scatter Plot for Petal Length and Petal Width&class="macro">#x27;) plt.colorbar(label=&class="macro">#x27;Iris Species&class="macro">#x27;, ticks=[class="num">0, class="num">1, class="num">2]) plt.show() # save the scatter plot to a file(optional) # plt.savefig(&class="macro">#x27;scatter_plot_petal_length_width.png&class="macro">#x27;)
scikit-learn 分类器与 ONNX 导出差异
在 Python 3.10.0 + scikit-learn 1.2.2 环境下,可直接列出包内全部 41 个分类器,从 AdaBoostClassifier 到 VotingClassifier。其中需要基础分类器的集成模型(如 Bagging、Stacking)以黄色标记,可独立使用的以普通色显示;绿色代表已成功导出 ONNX,红色代表在 1.2.2 版本转换报错。 不同模型转 ONNX 后输出张量格式并不统一。以鸢尾花任务为例,输入恒为 [None, 4] 的 float 张量;SVC、LinearSVC、NuSVC、RadiusNeighbors、Ridge 及 RidgeCV 共 6 类输出 label(int64) + probabilities(float [None,3]),无需后处理。其余 21 类输出 output_label + output_probability(seq(map(int64,tensor(float)))),必须做后处理取概率最高项才能拿到类编号。 在 MQL5 侧验证时,建议把 PrepareIrisDataset() 等函数移入 iris.mqh,便于对完整鸢尾花集做模型测试。SVC / LinearSVC / NuSVC 三者同属支持向量族:SVC 靠核函数处理非线性,LinearSVC 仅线性分离但大样本更快,NuSVC 用 nu(0~1) 控复杂度与支持向量占比。外汇与贵金属行情序列若接此类模型,须明确高风险——过拟合与特征缩放失当都会让概率输出失真。 开 MT5 跑通一套:先确认你环境里 sklearn 版本,若非 1.2.2 则红色报错模型清单可能变动;用脚本 dump 分类器列表,再挑一个绿色 SVC 导 ONNX 进 MQL5 比对 accuracy,能直接看出原始与导出模型偏差。
「从 Python 训练到 MT5 实跑:三类 SVM 分类器的 ONNX 落地差异」
在 MetaEditor 里跑 Iris_SVMClassifier.py,SVC 模型在鸢尾花数据集上的准确率为 99.33%,导出 ONNX 后数值完全一致。MQL5 侧用同模型对 150 个样本逐一推理,149 个分类正确,仅样本 #84 被错判为 versicolor(实际为 virginica),说明 ONNX 桥接没有精度损耗。 LinearSVC 的原始与 ONNX 准确率均为 96.67%,三类报告里第 1、2 类的 precision/recall 落在 0.94–0.96 区间,比 SVC 稍弱但训练更快、资源占用低。NuSVC 靠 nu 参数(取值 0–1)控制支持向量比例,0.5 约意味着半数样本进支持向量或误差项,调参更依赖交叉验证。 值得在 MT5 里直接验证的一点:ONNX 模型的输入张量固定为 float_input,shape [None,4],输出含 label 与 probabilities(shape [None,3])。用 Netron 打开 svc_iris.onnx,悬停 SVMClassifier 算子能看原始系数,比读代码直观。外汇与贵金属行情若套这类分类思路,需先认清样本外泛化风险高,实盘前务必用历史 tick 重跑一遍准确率。
◍ 半径邻域与岭回归分类器的实战落点
NuSVC 导出的 ONNX 模型在完整 Iris 数据集上准确率 97.33%,与原始模型完全一致;输入张量 float_input 为 float 类型、形状 [None, 4],输出含 label 与 probabilities 两个节点,意味着 MT5 端可直接读概率做多类判别。
Radius Neighbors Classifier 靠半径而非固定 K 值找邻居:半径内的样本多数投票决定类别。它在 Iris 上原始与 ONNX 准确率同为 97.33%,但分类错误数为 4 个(样本 78、107、127、139),说明边界样本对半径敏感,调参时得盯错分样本而非只看总精度。
Ridge Classifier 本质是带 L2 正则的逻辑回归变体,alpha 手动调;RidgeClassifierCV 则用交叉验证自动选 alpha。外汇或贵金属行情特征常高度相关,L2 惩罚能压住多重共线性带来的过拟合,但高风险品种上任何历史精度都不代表未来胜率,上 MT5 前先用脚本跑一遍 ONNX 一致性。
这类分类器若接实时 tick 做状态识别,建议先在本机用 Python 训好导 ONNX,再让 MQL5 脚本加载 Scripts/radius_neighbors_iris.onnx 做推理,比在终端内重算距离省一个数量级算力。