使用经典机器学习方法预测汇率:逻辑回归(logit)模型和概率回归(probit)模型(基础篇)
📘

使用经典机器学习方法预测汇率:逻辑回归(logit)模型和概率回归(probit)模型(基础篇)

第 1/3 篇

◍ 用 logit 与 probit 给汇率做概率预判

在 MT5 里做汇率方向预测,逻辑回归(logit)和概率回归(probit)是两条最朴素的经典机器学习路径。两者都把行情特征压缩成一个 0 到 1 之间的概率值:接近 1 代表下一根 K 线上涨倾向较高,接近 0 则下跌概率偏大。 logit 用 logistic 函数把线性组合映射到概率,probit 则换成正态累积分布函数。对外汇和贵金属这类高波动品种,输出的是条件概率而非确定信号,实盘仍需配合仓位与止损。 一篇 2025 年 7 月 21 日发布于 MT5 社区的 EA 文章给出参考实现,原文显示基础版在回测中获 509 次访问与 9 条互动,说明该类模型在零售交易者中确有可验证的受众需求。 开 MT5 新建 EA,把收盘价斜率、波动率分位等特征喂进这两类模型,先跑 EURUSD 的 M15 看概率输出是否和反转点吻合,比直接信信号更靠谱。

「从二选一开始的行情预测切入」

做外汇或贵金属预测,最容易陷进模型堆里出不来。把问题压到最薄——「明天收盘价比今天高还是低」——就自然落到二元分类上。逻辑回归(logit)和概率回归(probit)结构简单、资料多,是有监督学习里最该先跑通的两类。 有监督学习本质是学一个映射:输入 {x} 是特征,输出 {y} 是标签。这里我们只判两种状态,涨标 1、跌标 0,即 y ∊ {1,0}。特征用标准化且带指定滞后的价格增量,也就是价格模式,凑成 {x,y} 训练集去估参数。 基于训好的分类器,预测模型落地成一个叫 LogitExpert 的 EA。MT5 里加载它,先用历史数据跑一遍,看二分类命中率是否明显高过 0.5 的随机线,再谈调滞后阶数。外汇贵金属杠杆高,模型仅给概率倾向,不构成方向保证。

线性概率崩在边界,logit与probit怎么兜底

线性概率模型把成功概率写成解释变量的线性组合:P = w0*1 + w1x1 + … + wkxk。它最致命的问题是预测值会跑出 [0,1] 区间,比如样本外推时算出一宗贵金属突破概率 1.3,根本没法当概率用。 probit 用标准正态累积分布 F(·) 把线性输出 x_n w 压回 [0,1],logit 则用逻辑函数 L(z)=exp(z)/(1+exp(z))。两者激活曲线在 [-1.2, 1.2] 内几乎重合,所以只要前激活值不极端,两个模型给的方向概率差不了多少。 实际盯盘里,把特征向量(如动量、波动率分位)代进去算 μ_n,就能得到下一根 K 线上涨的倾向概率。外汇与贵金属杠杆高、跳空频繁,μ_n 接近 0 或 1 时两个模型分歧会拉大,这时候别只看一个点,最好用 MT5 把两种激活都跑一遍比对。

◍ 训练集怎么从K线里抠出来

建模前得先把特征做出来并标准化,再喂给寻优函数。GetDataset 就干这个活:InpCount_ 是训练样本数,lag_ 是用作特征的滞后价格增量个数,X 算特征、y 算标签,start 是从第几根 K 线起采。 拿滞后收益当特征最直观。lag_ 设 4,特征就是 {return-4, return-3, return-2, return-1},实际能用的样本数是 (InpCount_ - lag_),少掉的那几根被滞后窗口吃掉了。 代码里先 CopyRates 取 OHLC,y 从 start+1 取 InpCount_ 根,X 从 start+2 取 InpCount_-1 根,转置后按收盘价>开盘价标 1、否则 0。标签后移 lag_ 步,特征矩阵用每根 K 线的收盘减开盘填,最后按最后一列均值和标准差做 z-score 标准化。 外汇和贵金属波动受杠杆与消息面驱动,标准化只是数学处理,不预示方向。跑通这段代码你能在 MT5 里直接拿到 Input_X 和 Target_y,接下一步参数估计。

MQL5 / C++
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//|Get data for analysis: features and corresponding labels              |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">bool GetDataset(class="type">int InpCount_,class="type">int lag_,class="type">int start,matrix &Input_X,vector & Target_y,class="type">class="kw">string X,class="type">class="kw">string y)
  {
   matrix rates;
   matrix target;
   target.CopyRates(y, PERIOD_CURRENT, COPY_RATES_OHLC, start+class="num">1, InpCount_);
   rates.CopyRates(X, PERIOD_CURRENT, COPY_RATES_OHLC, start+class="num">2, InpCount_-class="num">1);
   rates = rates.Transpose();
   target = target.Transpose();
   class="type">int Class_ [];
   ArrayResize(Class_,InpCount_);
   for(class="type">int i=class="num">0; i<InpCount_; i++)
     {
      if(target[i,class="num">3] > target[i,class="num">0])
        Class_[i] = class="num">1;
      else
        Class_[i] = class="num">0;
     }
   vector label=vector::Zeros(InpCount_-lag_);
   for(class="type">int i=class="num">0; i<InpCount_-lag_; i++)
     {
      label[i] = Class_[i+lag_]; class=class="str">"cmt">// class label
     }
   matrix returns=matrix::Zeros(InpCount_-lag_, lag_);
   for(class="type">int j=class="num">0; j<lag_; j++)
     {
      for(class="type">int i=class="num">0; i<InpCount_-lag_; i++)
        {
         returns[i,j] =rates[i+j,class="num">3] - rates[i+j,class="num">0]  ; class=class="str">"cmt">// Input Data
        }
     }
   vector cols_mean=returns.Mean(class="num">0);
   vector cols_std=returns.Std(class="num">0);
   mean_ = cols_mean[lag_-class="num">1];
   std_ = cols_std[lag_-class="num">1];
   for(class="type">int j=class="num">0; j<lag_; j++)
     {
      for(class="type">int i=class="num">0; i<InpCount_-lag_; i++)
        {
         returns[i,j] = (returns[i,j] - cols_mean[lag_-class="num">1])/cols_std[lag_-class="num">1];
        }
     }
   Input_X = returns;
   Target_y = label;
   class="kw">return true;
  }

「在 MT5 里亲手估参数才看得见显著性」

最大似然是二元分类里最顺手的参数估计路线。logit 与 probit 都假定标签 y 服从伯努利分布,把对数似然取负就得到负对数似然(NLL),正好对接 L-BFGS 这类默认「最小化」的拟牛顿优化器,Alglib 里已直接可用。 光拿到参数还不够,标准误才是判断特征是否真有统计显著性的钥匙。scikit-learn 的 logit 接口不吐这东西,而我在 MQL 里自写模型后能顺手算出协方差矩阵、再导出标准差,哪些特征在拽预测一目了然。另一个硬需求是动态性:模型得能在每根 K 线或任意周期上重估参数,而不是靠 ONNX 把离线训练的静态包搬进来。 过拟合在这类线性分类器上常表现为参数被推得异常大。加一道 L2 正则化即可压住:损失函数后补一项 λ·‖w‖²,λ=1/C 且 C∈(0,1],C 越小惩罚越狠。FitLogitRegression 里 L2 默认关、C=1.0、probit 默认 false,另收一个卡方显著性水平 alpha,函数会自动补一列恒为 1 的哑变量来估截距 w₀。 下面这段是目标函数类,把 NLL 在 MT5 里落了地。注意 probit_ 开关切正态累积分布与 sigmoid,并对 0/1 激活值夹到 0.001/0.999 防对数算崩。外汇与贵金属波动大、样本非平稳,这类模型过拟合风险高,参数显著性得结合样本外验证再看。

MQL5 / C++
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Derived class from CNDimensional_Func                            |
class=class="str">"cmt">//+------------------------------------------------------------------+
class CNDimensional_Logit : class="kw">public CNDimensional_Func
  {
class="kw">public:
                      CNDimensional_Logit(class="type">void) {}
                     ~CNDimensional_Logit(class="type">void) {}
  class="kw">virtual class="type">void        Func(CRowDouble &w,class="type">class="kw">double &func,CObject &obj);
  };
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Objective Function: Logit Negative loglikelihood                 |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void CNDimensional_Logit::Func(CRowDouble &w,class="type">class="kw">double &func,CObject &obj)
  {
   class="type">class="kw">double LLF[],probit[],probitact[];
   vector logitact;
   ArrayResize(LLF,Rows_);
   ArrayResize(probit,Rows_);
   vector params=vector::Zeros(Cols_);
   for(class="type">int i = class="num">0; i<Cols_; i++)
     {
      params[i] =  w[i]; class=class="str">"cmt">// vector of parameters
     }
   vector logit=vector::Zeros(Rows_);
   logit = Input_X_gl.MatMul(params);
   for(class="type">int i=class="num">0; i <Rows_; i++)
     {
      probit[i] = logit[i];
     }
   if(probit_)
      MathCumulativeDistributionNormal(probit,class="num">0,class="num">1,probitact); class=class="str">"cmt">// Probit activation
   else
      logit.Activation(logitact,AF_SIGMOID); class=class="str">"cmt">// Logit activation
class=class="str">"cmt">//--------------------to avoid NAN error when calculating logarithm ------------------------------------
   if(probit_)
     {
      for(class="type">int i = class="num">0; i<Rows_; i++)
        {
         if(probitact[i]==class="num">1)
            probitact[i]= class="num">0.999;
         if(probitact[i]==class="num">0)
            probitact[i]= class="num">0.001;
        }
     }
   else
     {
      for(class="type">int i = class="num">0; i<Rows_; i++)
        {
         if(logitact[i]==class="num">1)
            logitact[i]= class="num">0.999;
         if(logitact[i]==class="num">0)

常见问题

把近期收盘价涨跌做成0/1标签,取均线差、波动率等做特征,用logit估出系数后代入算概率,高于0.5倾向看涨,但外汇高风险需结合止损。
线性概率在涨跌极端处会突破[0,1]边界,logit和probit用S形或正态累积函数兜底,输出天然落在0到1之间,适合汇率二分类。
小布盯盘已内置AIGC诊断,打开对应品种页即可看到基于模型的倾向概率,你只需专注决策而不用自己跑回归。
基础篇常用前20根bar的收益率符号作标签,特征取3/5/10期均线差与ATR,样本少于200根显著性会很差。
在交易软件里加载回归脚本,看输出中z值和p值,p小于0.05的字段才留,否则删掉降噪,贵金属杠杆高更需谨慎。