首页 / 交易学院 / 小布知识库 / SVM机器学习交易实战入门
SVM机器学习交易实战入门
🤖

SVM机器学习交易实战入门

用支持向量机从指标中提取交易信号

指标策略 难度 · 进阶 2026-01-28 7 分钟阅读
#支持向量机#机器学习#MQL5#交易信号#SVM工具

什么是支持向量机(SVM)

支持向量机(Support Vector Machine,简称SVM)是一种机器学习方法,其核心目标是将输入数据划分为两类。要让SVM生效,必须先用一组带有已知分类结果的训练数据来建立模型。模型建立后,面对新的未知数据,SVM就能依据已学到的边界将其自动归类为其中一类。

从数学角度看,SVM的工作方式是将训练输入映射到多维空间,然后使用回归算法寻找一个能最佳分离两类数据的超平面。所谓超平面,是在N维空间中将空间一分为二的平面:在二维空间里它是一条线(一维超平面),在三维空间里是一个面(二维超平面),在更高维度中则是N-1维结构。SVM本质上是一台输入/输出机器:你喂入一组特征,它返回类别判断。

理论上SVM可接受的输入特征数量从1到无穷,但实际运算能力是瓶颈。若有N个输入特征,算法就要把每组数据映射至N维空间,并找出N-1维分割超平面。这也是为何在MT5中应用SVM时,特征数量要克制,否则训练时间会急剧拉长。

✦ 直观理解
用二维散点图最容易理解SVM:蓝叉和红圈代表两类样本,SVM找一条线将二者分开;新数据点落在线哪一侧,就被判为对应类别。

从二维到高维:SVM如何扩展

上文的二维示例只是为了可视化。真实问题中我们往往使用更多特征。例如你希望用20个输入参数判断某样本属于类型1还是类型2,SVM会在20维空间建模,并寻找19维超平面来分割。人类难以想象三维以上的形态,但算法逻辑与二维完全一致:在对应维度中求解最优分离边界。

高维空间带来的好处是能表达极其复杂的非线性关系,代价是计算量随维度上升。在交易中若直接把多个指标的几十根历史柱作为独立输入,维度会爆炸,因此原文作者建议通过自定义指标压缩,或控制偏移与数量。

案例:用SVM识别Schnick动物

为说明SVM的建模流程,原文虚构了稀有动物Schnick的研究场景。研究员只有少量论文描述,特征杂乱无模式。我们可采集身高、体重、肢体数、眼睛数、前肢长、奔跑速度、鸣叫频率共7个输入,并为每个样本标注是真Schnick还是假。训练数据需同时包含正例与反例,如下表概念所示。

选定输入后,编写函数判定真实属性:若动物同时满足身高1000-1100mm、体重40-50kg、肢8-10、眼3-4、臂400-450mm、速2-2.5m/s、鸣11000-15000Hz,则为真。此函数既用来造训练集,也用来检验SVM准确率。

bool isItASchnick(double height,double weight,double N_legs,double N_eyes,double L_arm,double av_speed,double f_call)
  {
   if(height   < 1000  || height   > 1100)  return(false);
   if(weight   < 40    || weight   > 50)    return(false);
   if(N_legs   < 8     || N_legs   > 10)    return(false);
   if(N_eyes   < 3     || N_eyes   > 4)     return(false);
   if(L_arm    < 400   || L_arm    > 450)   return(false);
   if(av_speed < 2     || av_speed > 2.5)   return(false);
   if(f_call   < 11000 || f_call   > 15000) return(false);
   return(true);
  }

随后生成随机输入并调用上述函数得到输出,填充训练数组。以下代码展示生成过程:在各自范围内随机取值,拷贝进inputs,并用isItASchnick赋outputs。

void genTrainingData(double &inputs[],bool &outputs[],int N)
  {
   double in[];
   ArrayResize(in,N_Inputs);
   ArrayResize(inputs,N*N_Inputs);
   ArrayResize(outputs,N);
   for(int i=0;i<N;i++)
     {
      in[0]=    randBetween(980,1120);
      in[1]=    randBetween(38,52);
      in[2]=    randBetween(7,11);
      in[3]=    randBetween(3,4.2);
      in[4]=    randBetween(380,450);
      in[5]=    randBetween(2,2.6);
      in[6]=    randBetween(10500,15500);
      ArrayCopy(inputs,in,i*N_Inputs,0,N_Inputs);
      outputs[i]=isItASchnick(in[0],in[1],in[2],in[3],in[4],in[5],in[6]);
     }
  }

double randBetween(double t1,double t2)
  {
   return((t2-t1)*((double)MathRand()/(double)32767)+t1);
  }

训练与测试SVM模型

利用SVM学习工具库(应用市场下载),初始化机器、设输入/输出、设容错率、执行训练。容错率OP_TOLERANCE设为0.05表示允许5%训练点不符。训练完用新随机点测试,对比预测与真实标签计算准确率。

void OnStart()
  {
   double inputs[]; bool outputs[];
   int N_TrainingPoints=5000;
   int N_TestPoints=5000;
   genTrainingData(inputs,outputs,N_TrainingPoints);
   int handle1=initSVMachine();
   setInputs(handle1,inputs,7);
   setOutputs(handle1,outputs);
   setParameter(handle1,OP_TOLERANCE,0.05);
   training(handle1);
  }

测试函数循环生成样本,调用classify获取预测,与isItASchnick真实值比对,返回正确率百分比。

double testSVM(int handle,int N)
  {
   double in[]; int N_correct=0; bool Predicted_Output,Actual_Output;
   ArrayResize(in,N_Inputs);
   for(int i=0;i<N;i++)
     {
      in[0]=randBetween(980,1120); in[1]=randBetween(38,52); in[2]=randBetween(7,11);
      in[3]=randBetween(3,4.2); in[4]=randBetween(380,450); in[5]=randBetween(2,2.6); in[6]=randBetween(10500,15500);
      Actual_Output=isItASchnick(in[0],in[1],in[2],in[3],in[4],in[5],in[6]);
      Predicted_Output=classify(handle,in);
      if(Actual_Output==Predicted_Output) N_correct++;
     }
   return(100*((double)N_correct/(double)N));
  }

SVM的容错优势与噪音处理

SVM最大优势之一是对数据误差和噪音鲁棒。它不要求事先理解数据行为,而是自行提取模式,并可通过容错率忽略异常值。在Schnick案例中,人为向5000点训练集注入500个随机错误后,准确率下降不足1%。

这是因为训练时SVM寻求符合大部分(如95%)数据的模型,而非强行拟合全部点。以下代码展示如何插入随机误差:随机选索引,用随机输入和随机布尔覆盖原数据。

void insertRandomErrors(double &inputs[],bool &outputs[],int N)
  {
   int nTrainingPoints=ArraySize(outputs); int index; bool randomOutput; double in[];
   ArrayResize(in,N_Inputs);
   for(int i=0;i<N;i++)
     {
      in[0]=randBetween(980,1120); in[1]=randBetween(38,52); in[2]=randBetween(7,11);
      in[3]=randBetween(3,4.2); in[4]=randBetween(380,450); in[5]=randBetween(2,2.6); in[6]=randBetween(10500,15500);
      index=(int)MathRound(randBetween(0,nTrainingPoints-1));
      if(randBetween(0,1)>0.5) randomOutput=true; else randomOutput=false;
      ArrayCopy(inputs,in,index*N_Inputs,0,N_Inputs);
      outputs[index]=randomOutput;
     }
  }
⚠ 常见坑
若训练输出中true/false极度不平衡(如100个里仅1个true),SVM会快速但低效地收敛到总判false,失去分类意义。务必保证训练集多样性。

SVM在MT5交易中的应用逻辑

技术分析与Schnick案例类似:用历史数据预测未来。市场充满噪音,SVM正适合提取复杂模式。典型流程为:监控多指标→找各自触发条件→综合评估信号。SVM学习工具把该过程自动化:用指标句柄生成输入,用模拟历史交易生成输出。

生成训练输入需调用setIndicatorHandles传递句柄数组、偏移offset与点数N。offset是当前柱到起始柱的距离,N是训练点规模。例如offset=4、N=6只用白框柱;offset=8、N=8用蓝框柱。随后genInputs()据此提取特征。

训练输出通过模拟假设交易产生:OP_TRADE选BUY/SELL;止损止盈以点计;duration以小时限定时长,避免横盘误判。只有期限内平仓盈利才记成功。

输入特征选择的关键原则

选输入特征比选模型更关键。与Schnick类似,要挑各类别间差异稳定、跨时间一致的指标。例如裸用移动平均线值作输入很差:价格从0.55涨到1.10后,旧均值模式失效,SVM只认0.55附近信号。反之MACD等动量指标与绝对价位无关,更适合。

还要注意特征快照长度。MACD常需近5柱看趋势,可写自定义指标压成单值传入,或初始化5个MACD实例以不同偏移传5个句柄。后者输入多、训练慢,需权衡。

在EA中部署SVM:svTrader示例

原文提供svTrader EA(下载见https://www.mql5.com/zh/code/1229),其初始化两个SVM分别抓买卖信号,将7个标准指标句柄数组传入,生成历史输入输出并训练,之后实时分类发信号并手动止损止盈。OnInit内核心片段如下(因原文截断,仅示前置):

#import "svMachineTool.ex5"
enum ENUM_TRADE {BUY,SELL};
enum ENUM_OPTION {OP_MEMORY,OP_MAXCYCLES,OP_TOLERANCE};
int  initSVMachine(void);
void setIndicatorHandles(int handle,int &indicatorHandles[],int offset,int N);
void setParameter(int handle,ENUM_OPTION option,double value);
bool genOutputs(int handle,ENUM_TRADE trade,int StopLoss,int TakeProfit,double duration);
bool genInputs(int handle);
bool setInputs(int handle,double &Inputs[],int nInputs);
bool setOutputs(int handle,bool &Outputs[]);
bool training(int handle);
bool classify(int handle,double &iput[]);
void deinitSVMachine(void);
#import

int OnInit()
  {
   int handles[];ArrayResize(handles,7);
   handles[0]=iBearsPower(Symbol(),0,bears_period);
   handles[1]=iBullsPower(Symbol(),0,bulls_period);
   handles[2]=iATR(Symbol(),0,ATR_period);
   handles[3]=iMomentum(Symbol(),0,mom_period,PRICE_TYPICAL);
   handles[4]=iMACD(Symbol(),0,MACD_fast_period,MACD_slow_period,MACD_signal_period,PRICE_TYPICAL);
   handles[5]=iStochastic(Symbol(),0,Stoch_Kperiod,Stoch_Dperiod,Stoch_slowing,MODE_SMA,STO_LOWHIGH);
   handles[6]=iForce(Symbol(),0,Force_period,MODE_SMA,VOLUME_TICK);
   handleB=initSVMachine();
   setIndicatorHandles(handleB,handles,0,N_DataPoints);
   setParameter(handleB,OP_TOLERANCE,Tolerance_Value);
   genInputs(handleB);
   genOutputs(handleB,BUY,stopLoss,takeProfit,hours);

高级用法:自定义输入输出

SVM工具允许高级用户绕开指标,直接传自定义双精度输入数组与布尔输出数组。输入格式为扁平长数组:若3特征×5点,则长15,顺序A1B1C1A2B2C2…并声明N_Inputs=3。输出为等长布尔数组。任何类型须先转double。

约束:数组长度须为N_Inputs整数倍;输入组数须等于输出数;训练集真假比应均衡。除生成信号,还可用于仓位管理、成交概率等。但需自担过拟合风险。

⚠ 编译错误提示
原文评论区有人遇OP_TOLERANCE未声明错误,因库版本差异。若用新版svMachineTool.ex5,请核对ENUM_OPTION定义或改用对应常量名。

常见问题

下载应用市场'支持向量机学习工具',在EA中用initSVMachine初始化,setIndicatorHandles传指标句柄与offset/N,genInputs取特征,genOutputs用模拟买卖止损止盈生成标签,training训练后classify实时分类发信号。
调用setParameter(handle,OP_TOLERANCE,0.05)表示允许5%训练点不符。值越大越抗噪音但边界越粗,默认可试0.1(10%),需据数据质量调。
MA绝对值随价格水平漂移,数月前与当前差异巨大,SVM只学到旧价位模式而失效。应选MACD等相对动量指标,或取MA斜率/比值等平稳特征。
确保输入双精度数组长=N_Inputs×样本数,输出布尔数组长=样本数,且二者样本数相等。如N_Inputs=3、输入长15则输出须长5,否则报背离错。
此为库版本差异。检查导入的svMachineTool.ex5头文件ENUM_OPTION定义,若新版改名则用新常量,或下载原文配套旧版库(见https://www.mql5.com/zh/articles/584附件)。