机器学习:支持向量机如何应用于交易·进阶篇
📘

机器学习:支持向量机如何应用于交易·进阶篇

第 2/3 篇

「容错率是 SVM 在噪音数据里存活的底牌」

支持向量机最实用的地方,是它不需要你提前假设数据长什么样。它像个黑匣子,喂进去一堆杂乱的输入输出,自己把内部关系挖出来,尤其适合处理那些人类看一眼就头大的非线性结构。 更狠的是它对误差和噪音的容忍度。比如你拿到一批标的的特征数据,里面混了些离谱记录——某外汇品种波动被标成 200 公斤、15 米高这种明显错乱的字段,硬训就会把模型带歪,新样本分类可能直接错判。SVM 的思路是放弃「完美拟合全部训练点」,转而给模型一定的容错,让异常值可以被忽略。 实测里,在 5000 个训练点的数据集人为塞进 500 个随机误差(即 10% 污染),训出来的带噪 SVM 和干净版相比性能降幅不到 1%。这说明只要容错率设得合理(例如放掉 5% 的点),它就能抓出真实数据的底层模式。外汇和贵金属行情本身噪音极大、滑点异常频发,这种抗造特性对实盘特征工程有参考价值,但高风险依旧,回测稳不等于 live 能复现。 下面这个函数就是往训练集里人为打洞的 MQL5 实现,跑完你能直接对比有无噪音的模型差异。

MQL5 / C++
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| This function takes the correct training inputs and outputs generated
class=class="str">"cmt">//| and inserts N random errors into the data
class=class="str">"cmt">//+------------------------------------------------------------------+ 
class="type">void insertRandomErrors(class="type">class="kw">double &inputs[],class="type">bool &outputs[],class="type">int N)
  {
   class="type">int    nTrainingPoints=ArraySize(outputs); class=class="str">"cmt">// 计算训练点总数
   class="type">int    index;                               class=class="str">"cmt">// 声明整数变量 index 用于随机定位
   class="type">bool   randomOutput;                        class=class="str">"cmt">// 声明布尔变量 randomOutput 存随机标签
   class="type">class="kw">double in[];                                class=class="str">"cmt">// 声明临时double数组存随机生成输入
   ArrayResize(in,N_Inputs);                   class=class="str">"cmt">// 把 in 数组大小调成特征维数 N_Inputs
   for(class="type">int i=class="num">0;i<N;i++)
     {
      in[class="num">0]=    randBetween(class="num">980,class="num">1120);         class=class="str">"cmt">// 随机生成身高类特征
      in[class="num">1]=    randBetween(class="num">38,class="num">52);            class=class="str">"cmt">// 随机生成体重类特征
      in[class="num">2]=    randBetween(class="num">7,class="num">11);             class=class="str">"cmt">// 随机生成腿数类特征
      in[class="num">3]=    randBetween(class="num">3,class="num">4.2);            class=class="str">"cmt">// 随机生成眼睛数类特征
      in[class="num">4]=    randBetween(class="num">380,class="num">450);          class=class="str">"cmt">// 随机生成臂长类特征
      in[class="num">5]=    randBetween(class="num">2,class="num">2.6);            class=class="str">"cmt">// 随机生成平均速度类特征
      in[class="num">6]=    randBetween(class="num">10500,class="num">15500);      class=class="str">"cmt">// 随机生成呼叫频率类特征
      index=(class="type">int)MathRound(randBetween(class="num">0,nTrainingPoints-class="num">1)); class=class="str">"cmt">// 随机挑一个训练点位置准备污染
      if(randBetween(class="num">0,class="num">1)>class="num">0.5) randomOutput=true;             class=class="str">"cmt">// 随机决定污染后的布尔标签
      else                     randomOutput=class="kw">false;
      ArrayCopy(inputs,in,index*N_Inputs,class="num">0,N_Inputs);         class=class="str">"cmt">// 把随机输入写回原训练输入数组对应位置
     }
  }

◍ 用带噪与干净样本对比 SVM 泛化落差

这段启动函数把支持向量机在 MT5 里的训练与测试流程跑通了:先生成 5000 组训练样本与 5000 组测试样本,分别喂给两台 SVM,一台用无误差数据,另一台在原始数据上插入 500 个随机错误后再训练。 两台机器都设了 OP_TOLERANCE=0.05,也就是把分类误差容忍度压到 5% 以内;特征维度通过 setInputs 的第三个参数固定为 7。训练完用同样的 5000 点测试集测精度,分别存到 t1 和 t2,最后 Print 出保留两位小数后的百分比。 插入随机错误的做法直接模拟了实盘价格行为数据里的毛刺——你开 MT5 把这段代码跑一遍,大概率会看到 handle2 的准确率明显低于 handle1,这就说明噪声对 SVM 信号过滤的侵蚀。外汇与贵金属行情高波动、假突破多,这类模型上线前必须自己压一轮噪声压力测试。 deinitSVMachine 那行别删,MT5 里不手动释放 SVM 句柄容易拖慢终端内存,尤其你在策略测试器里反复跑的时候。

MQL5 / C++
   outputs[index]=randomOutput;                     class=class="str">"cmt">// Copy the new random output generated into the training output array
   }
}
class="type">void OnStart()
  {
  class="type">class="kw">double inputs[];                    class=class="str">"cmt">// Empty class="type">class="kw">double array to be used for creating training inputs
  class="type">bool   outputs[];                   class=class="str">"cmt">// Empty class="type">bool array to be used for creating training inputs
  class="type">int    N_TrainingPoints=class="num">5000;       class=class="str">"cmt">// Defines the number of training samples to be generated
  class="type">int    N_TestPoints=class="num">5000;           class=class="str">"cmt">// Defines the number of samples to be used when testing
  genTrainingData(inputs,outputs,N_TrainingPoints); class=class="str">"cmt">// Generates the inputs and outputs to be used for training the svm
  class="type">int handle1=initSVMachine();                       class=class="str">"cmt">// Initializes a new support vector machine and returns a handle
  setInputs(handle1,inputs,class="num">7);                       class=class="str">"cmt">// Passes the inputs(without errors) to the support vector machine
  setOutputs(handle1,outputs);                       class=class="str">"cmt">// Passes the outputs(without errors) to the support vector machine
  setParameter(handle1,OP_TOLERANCE,class="num">0.05);           class=class="str">"cmt">// Sets the error tolerance parameter to <class="num">5%
  training(handle1);                                class=class="str">"cmt">// Trains the support vector machine class="kw">using the inputs/outputs passed
  insertRandomErrors(inputs,outputs,class="num">500);            class=class="str">"cmt">// Takes the original inputs/outputs generated and adds random errors to the data
  class="type">int handle2=initSVMachine();                       class=class="str">"cmt">// Initializes a new support vector machine and returns a handle
  setInputs(handle2,inputs,class="num">7);                       class=class="str">"cmt">// Passes the inputs(with errors) to the support vector machine
  setOutputs(handle2,outputs);                       class=class="str">"cmt">// Passes the outputs(with errors) to the support vector machine
  setParameter(handle2,OP_TOLERANCE,class="num">0.05);           class=class="str">"cmt">// Sets the error tolerance parameter to <class="num">5%
  training(handle2);                                class=class="str">"cmt">// Trains the support vector machine class="kw">using the inputs/outputs passed
  class="type">class="kw">double t1=testSVM(handle1,N_TestPoints);           class=class="str">"cmt">// Tests the accuracy of the trained support vector machine and saves it to t1
  class="type">class="kw">double t2=testSVM(handle2,N_TestPoints);           class=class="str">"cmt">// Tests the accuracy of the trained support vector machine and saves it to t2
  Print("The SVM accuracy is ",NormalizeDouble(t1,class="num">2),"% (class="kw">using training inputs/outputs without errors)");
  Print("The SVM accuracy is ",NormalizeDouble(t2,class="num">2),"% (class="kw">using training inputs/outputs with errors)");
  deinitSVMachine();                                 class=class="str">"cmt">// Cleans up all of the memory used in generating the SVM to avoid memory leak
  }

演示版只能进策略测试器跑

上面那套支持向量机调用的完整脚本,在代码库能拿到,但想在 MT5 终端里直接挂脚本运行,前提是你从应用商店买过「支持向量机学习工具」的完整授权,否则终端会拒跑。 没付费只装了演示版的话,权限被砍到只能用策略测试程序。为了拿演示版验证 Schnick 这套逻辑,我把原脚本改成了 EA 形态,这样就能在策略测试器里加载参数跑,不必碰终端脚本权限。 两条获取路径差异很直接:完整版对应「终端脚本+已购工具」,演示版对应「策略测试器 EA+演示工具」。外汇与贵金属行情波动剧烈、杠杆风险高,用演示版回测得到的结果仅代表历史样本概率,不等于实盘表现。

「把 SVM 当猎手:从动物分类到行情信号」

前面那个 schnick 动物的例子看着像玩具,但它和市场里的支持向量机用法共享同一套逻辑:用历史样本训练出边界,再拿去判别新样本。技术分析本质上也是拿历史报价去推未来走势的可能方向,区别只在于市场里塞满了噪音、报价误差和统计离群点,而这恰恰让 SVM 这类带容错边界的算法有了用武之地。 不少技术交易系统的骨架其实很直白:同时盯几个指标,先找出每个指标跟盈利交易沾边的触发条件,等它们多数亮灯时再统一评估。SVM 学习工具就是顺着这个思路长的——它把多指标状态塞进特征空间,让超平面去切出「信号区」和「非信号区」。 在 MT5 里跑这套之前,得先弄清一件事:训练用的输入和输出到底是怎么造出来的。输入通常是多指标在某一根 K 线时的数值组合,输出则取决于这根 K 线之后 N 根是否出现了你定义的「成功波动」。边界画歪了,后面 EA 调用的信号全废。 外汇和贵金属杠杆高、滑点随机,SVM 给出的只是概率倾向而非确定性入口;上实盘前务必用策略测试器跑完样本外数据再谈信任。

◍ 把指标句柄喂给支持向量机

指标句柄初始化完成后,下一步是调用 setIndicatorHandles() 把句柄送进自定义 SVM。这个函数接收一个整型数组,里面装的是已初始化指标的句柄,同时还需要两个参数:偏移值(offset)和训练数据点数量 N。 偏移值代表当前柱到训练起始柱的距离,N 决定取多少根柱来构造样本。原文图示很直白:offset=4、N=6 时,SVM 只抓取白色方框内的 6 根柱做输入输出;offset=8、N=8 时,则只用蓝色方框内的 8 根柱。外汇与贵金属行情噪声大、跳空频繁,偏移设太小容易让样本被近期噪声主导,实盘前建议在 MT5 里换几个 offset 对比样本分布。 句柄和参数传进去之后,就能调 genInputs() 生成训练输入集。这一步不跑训练,只是按你给的句柄和窗口把特征矩阵拼出来,后面才能丢给 SVM 学。

训练输出靠历史成交模拟来标定

支持向量机的训练输出不是凭空来的,而是拿历史价格回放假设交易,再判定这笔单子最终是成还是败。系统用几个参数告诉学习器该怎么算‘成功’,否则模型无从对齐信号与结果。 第一个开关是 OP_TRADE,只能取 BUY 或 SELL。设为 BUY 时,生成输出只评估‘假设做多’的胜率;设为 SELL 则只盯‘假设做空’。这意味着你训练的是单边判定器,而不是双向通吃模型。 每笔假设单用 Stop Loss 与 Take Profit 约束边界,单位都是点。止损和限利直接框死每笔模拟的退出条件,避免因为没退出规则导致标签漂移。 交易期限按小时计,只有在该时限内平仓盈利的才记为成功。这个上限专门用来掐掉慢速横盘里磨出来的假信号——横太久才盈利的样本不喂给模型,能压住 SVM 在震荡市的过拟合倾向。外汇与贵金属杠杆高,历史回测结论只代表概率,实盘仍需严控风险。

常见问题

靠容错率机制允许少量样本判错,在噪声里不强制拟合,泛化更稳。实盘前用带噪与干净样本对比泛化落差即可验证。
把指标句柄输出的特征值按时间窗整理成向量,作为 SVM 输入。训练输出用历史成交模拟标定多空标签。
小布可把指标特征自动整理并跑 SVM 类判定,直接在品种页给出偏多空信号倾向,省去手写代码。
演示版未开放实盘接口,仅能在策略测试器验证逻辑。真要上线需自行接行情与下单通道。
可把不同行情态当动物种类,SVM 找边界区分。重点是边界容错,不是精确记住每根 K 线。