您应当知道的 MQL5 向导技术(第 08 部分):感知器(基础篇)
用 MQL5 向导搭一个单层感知器
在 MT5 里写策略不一定从零敲代码。MQL5 向导的「交易信号」模块允许你直接挂一个单层感知器(Perceptron)作为开仓判定器,省掉自己实现前向传播的过程。 感知器的核心是把多个输入特征做加权求和,再过一个符号函数得到 -1 / 0 / 1 的输出,分别对应做空、观望、做多。外汇与贵金属杠杆高、滑点随机,这类线性分类器只适合捕捉弱趋势,别指望它识别拐点。 向导生成的信号类默认读取收盘价、均线差等 5~8 个特征,权重在回测中按错误驱动更新。实盘前建议把历史样本切成 2020–2023 三年,看其在 EURUSD H1 上的样本外准确率是否稳定高于 52%,否则过拟合概率偏大。
◍ 为什么交易者开始看向感知器
MQL5 向导的 Expert-Signal 类放在 Include\Expert\Signal 目录下,每个实例既能单独跑,也能在向导里互相拼装成 EA。本文走的是后者:用现成信号文件搭智能交易系统,初步编码量压到最低,还能给每个信号配权重,在单个 EA 里同时测多个信号。 Alglib 的感知器类在 Include\Math\Alglib\dataanalysis.mqh 里,接口是一张相互勾连的大网,第一次翻容易懵。我们挑关键类拆,目标不是背 API,而是能自己导航着改。 用 Alglib 或向导开发 EA,核心动机都是一个——快速验证思路。一个想法 x 或一组输入 y,到底值不值得认真写成交易系统?先用这套跑一遍,比拍脑袋强。 传统分析在外汇和贵金属这种高波动品种上常掉链子。市场受的影响远超新闻稿,变量间关系大多非线性且反复无常。相关性、PCA、线性回归都是好工具,但抓不住复杂动态;技术分析靠历史数据,难把情绪和消费偏差实时算进去。基本面看长期内在价值,可短期价格动作不对,杠杆一加风险就裸奔。外汇/贵金属属高风险,杠杆会放大这两种传统方式的盲区。 行为金融和神经网络 AI 是两条新路。前者借心理学解释投资者行为,后者是前者的计算形态,本文重点在后者。ChatGPT 带火 AI 后,彭博 BloombergGPT、Salesforce EinsteinGPT 都已落地;今天不聊 GPT,只聊它的极简祖宗——感知器。 数据过载和反哺算力在同步涨。一分钟 OHLC 已是技术员的底线周期,经纪商报价频率还更高;英伟达靠 GPU 需求冲向最大芯片商。存储和算力上来,算法交易变多,其中神经网络占比越来越重。 神经网络擅长啃大数据、抓非线性形态,还能通过深度学习让隐藏层专业化,在湍流行情里自适应。金融市场外,它读新闻、量情绪、评临床试验都行——交易上,先记住它「可能」比线性模型更贴实盘分布。
「Alglib 里跑通一个感知器要看哪几个类」
在 Alglib 的神经网络类库里,真正落地一个基础感知器只需要盯住四个核心类:CMLPBase 管网络结构初始化,CMLPTrain 管训练器与数据集装配,CMLPTrainer 在调用 MLPTrainNetwork 时承接实际训练,CMultilayerPerceptron 则是前向验算的载体。其余像报告处理、数据集常规化辅助类都是配角,主流程绕不开这四块。 CMLPBase 的关键动作是设定隐藏层数与每层神经元数;CMLPTrain 则要明确输入维度和输出维度,并把训练矩阵喂进去——矩阵第一列放自变量,最后一列放分类标签(感知器典型输出是布尔值)。隐藏层数量在运行时可设 0 到 2,所以哪怕你只写单隐层感知器,底层仍叫多层感知器。 前向馈送的主函数是 MLPProcess,内部先走 MLPInternalProcessVector 做输入常规化:用每列均值和标准差把数值压到 0–1 区间,这步必须手工从训练集算好 means 和 sigmas 再派给网络。m_structinfo 数组存着神经元总数、激活类型、权重总数等骨架信息,每层神经元还能用 MLPSetNeuronInfo 单独指定激活函数。 训练端 Alglib 主要给两种解法。Levenberg-Marquardt(LM)借 Hessian 矩阵估曲率,小型数据集、简单架构下收敛快且不易卡局部极小,代价是算 Hessian 很吃算力;LBFGS 用有限内存近似 Hessian,大数据和复杂网络更省资源,但受初始权重影响大、可能收敛慢或陷局部极小。实际外汇与贵金属信号建模属高风险场景,两种算法的选择倾向先看数据规模再定。 下面这段 DSNormalize 是常规化计算的可直接抄的代码,它先调 DSNormalizeC 求出均值和标准差,再逐列把原值减均值除以标准差写回矩阵。
class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void CBdSS::DSNormalize(CMatrixDouble &xy,const class="type">int npoints, const class="type">int nvars,class="type">int &info,CRowDouble &means, CRowDouble &sigmas) { class=class="str">"cmt">//--- function call DSNormalizeC(xy,npoints,nvars,info,means,sigmas); class=class="str">"cmt">//--- calculation for(class="type">int j=class="num">0; j<nvars; j++) { class=class="str">"cmt">//--- change values for(class="type">int i=class="num">0; i<npoints; i++) xy.Set(i,j,(xy.Get(i,j)-means[j])/sigmas[j]); } } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Normalize | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void CBdSS::DSNormalize(CMatrixDouble &xy,const class="type">int npoints, const class="type">int nvars,class="type">int &info,class="type">class="kw">double &means[], class="type">class="kw">double &sigmas[]) { CRowDouble Means,Sigmas; DSNormalize(xy,npoints,nvars,info,Means,Sigmas); Means.ToArray(means); Sigmas.ToArray(sigmas); }
把感知器塞进信号类的实操路径
用 MQL5 向导拼 EA 时,信号类、尾随类、资金管理类是必须三选齐的零件;本文聚焦的信号类负责产出方向判断,尾随类管止损跟随,资金管理类算手数。向导里按高亮的 7 个步骤走完,三者会被无缝织进同一套智能系统。 在自定义信号类里落地单层感知器,先声明关键类实例,再重写 LongCondition / ShortCondition。验证函数(Validation)实际承担了初始化职责:输入维度从可优化参数读入,输出维度因是分类任务至少设 2,本文为图省事直接写死 2——训练与向前推算都会回吐两个概率,多空相加恒为 1。 训练矩阵 m_xy 按列常规化到 -1.0 至 +1.0 是硬要求,否则每根新 K 线 Process 里调内置归一函数会失真。WriteWeights / ReadWeights 这对方法把跑赢基准的权重落盘,下次启动直接读盘续训,避开默认函数每根柱线随机初始化权重的坑。 网络结构按隐藏层数量分支创建,激活函数与层偏置可精细到单神经元;本文只做简化配置。Process 在新柱触发,先用历史点训网络再填引用变量 Y 出信号,刚起步和续训走不同函数,否则权重反复随机化,外汇与贵金属这类高波动品种上模型倾向失效。
class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| | class=class="str">"cmt">//+------------------------------------------------------------------+ class CSignalPerceptron : class="kw">public CExpertSignal { class="kw">protected: class="type">int m_hidden; class=class="str">"cmt">// 隐藏层数量 class="type">int m_features; class=class="str">"cmt">// 输入特征数量 class="type">int m_hidden_1_size; class=class="str">"cmt">// 第一隐藏层神经元数 class="type">int m_hidden_2_size; class=class="str">"cmt">// 第二隐藏层神经元数 class="type">int m_training_points; class=class="str">"cmt">// 每根柱训练点数 class="type">int m_training_restarts; class=class="str">"cmt">// 训练重启次数 class="type">int m_activation_type; class=class="str">"cmt">// 激活函数类型 class="type">class="kw">double m_hidden_1_bias; class=class="str">"cmt">// 第一隐藏层偏置 class="type">class="kw">double m_hidden_2_bias; class=class="str">"cmt">// 第二隐藏层偏置