数据科学与机器学习(第 07 部分):多项式回归·综合运用
📘

数据科学与机器学习(第 07 部分):多项式回归·综合运用

第 3/3 篇

「用 BIC 挑出多项式回归的最佳阶数」

贝叶斯信息准则(BIC)的核心逻辑很直白:在候选模型里,BIC 值最低的那个残差最小,也就是拟合效率最高。对价格序列做多项式回归时,阶数不是越高越好——高阶容易过拟合,把噪声当成了结构。 下面这段 MT5 代码把 BIC 计算封装成了函数,遍历 2 到 k-1 阶,逐阶算残差平方和(RSS)再套 BIC 公式。注意它先判断 bic 数组是否含正值,再取最小值,避免负 BIC 干扰排序。 [CODE] void CPolynomialRegression::BIC(ulong k, vector &bic,int &best_degree) { vector Pred; bic.Resize(k-2); best_degree = 0; for (ulong i=2, counter = 0; i<k; i++) { PolynomialRegressionfx(i,Pred); bic[counter] = ( n * log(RSS(Pred)) ) + (i * log(n)); counter++; } //--- bool positive = false; for (ulong i=0; i<bic.Size(); i++) if (bic[i] > 0) { positive = true; break; } double low_bic = DBL_MAX; if (positive == true) for (ulong i=0; i<bic.Size(); i++) { if (bic[i] < low_bic && bic[i] > 0) low_bic = bic[i]; } else low_bic = bic.Min(); //bic[ best_degree = ArrayMinimum(bic) ]; printf("Best Polynomial Degree(s) is = %d with BIC = %.5f",best_degree = best_degree+2,low_bic); } double CPolynomialRegression::RSS(vector &Pred) { if (Pred.Size() != y.Size()) Print(__FUNCTION__," Predictions Array and Y matrix doesn't have the same size"); double sum =0; for (int i=0; i<(int)y.Size(); i++) sum += MathPow(y[i] - Pred[i],2); return(sum); } vector bic_; //A vector to store the model BIC values for visualization purposes only int best_order; //A variable to store the best model order pol_reg.BIC(polynomia_degrees,bic_,best_order);

  • 09.22 20:58:21.540 polynomialReg test (#NQ100,D1) Best Polynomial Degree(s) is = 2 with BIC = 0.93358

[/CODE] 代码逐行拆解:BIC 函数先给 bic 数组预留 k-2 个位置(从 2 阶起算);循环里 PolynomialRegressionfx(i,Pred) 生成 i 阶预测值,bic[counter] 按 n·ln(RSS)+i·ln(n) 存好;后面那段 positive 判断是为防负 BIC 导致 Min() 误选,最后 printf 把最佳阶数加 2 还原并输出。RSS 函数就是经典残差平方和:遍历 y 与 Pred 差值平方累加。 实跑日志里,NQ100 日线数据在 10 阶以内扫描,最佳阶数落在 2、BIC=0.93358。对外汇或贵金属做同类回归时,换品种换周期结果可能倾向不同阶数,且杠杆品种波动剧烈、模型外推风险高,动手前先在策略测试器跑一遍再上实盘。

MQL5 / C++
class="type">void  CPolynomialRegression::BIC(class="type">class="kw">ulong k, vector &bic,class="type">int &best_degree)
 {
   vector Pred;
   
   bic.Resize(k-class="num">2); 
   best_degree = class="num">0;
   
    for (class="type">class="kw">ulong i=class="num">2, counter = class="num">0; i<k; i++)
     {        
        PolynomialRegressionfx(i,Pred);        
        bic[counter] = ( n * log(RSS(Pred)) ) + (i * log(n)); 
        
        counter++;
     }
     
class=class="str">"cmt">//--- 
   class="type">bool positive = class="kw">false;
   for (class="type">class="kw">ulong i=class="num">0; i<bic.Size(); i++)
    if (bic[i] > class="num">0) { positive = true; class="kw">break; }
   

   class="type">class="kw">double low_bic = DBL_MAX;
   
   if (positive == true) 
    for (class="type">class="kw">ulong i=class="num">0; i<bic.Size(); i++) 
    {
      if (bic[i] < low_bic && bic[i] > class="num">0) low_bic = bic[i];
    }
   else  low_bic = bic.Min(); class=class="str">"cmt">//bic[ best_degree = ArrayMinimum(bic) ];
      
   printf("Best Polynomial Degree(s) is = %d with BIC = %.5f",best_degree = best_degree+class="num">2,low_bic);
 }
class="type">class="kw">double CPolynomialRegression::RSS(vector &Pred)
 {
  if (Pred.Size() != y.Size()) Print(__FUNCTION__," Predictions Array and Y matrix doesn&class="macro">#x27;t have the same size");
  class="type">class="kw">double sum =class="num">0;
   for (class="type">int i=class="num">0; i<(class="type">int)y.Size(); i++)
     sum += MathPow(y[i] - Pred[i],class="num">2);
     
    class="kw">return(sum);
 }
   vector bic_; class=class="str">"cmt">//A vector to store the model BIC values for visualization purposes only
   
   class="type">int best_order; class=class="str">"cmt">//A variable to store the best model order 
   
   pol_reg.BIC(polynomia_degrees,bic_,best_order);
class="num">2022.09.class="num">22 class="num">20:class="num">58:class="num">21.540 polynomialReg test(class="macro">#NQ100,D1) Best Polynomial Degree(s) is = class="num">2 with BIC = class="num">0.93358

特征缩放不做,高阶多项式直接失控

单变量多项式回归里,自变量可以任意升幂,但缩放必须先于一切处理。若原始特征落在 100–1000,二次幂就到 1万–100万,三次幂直接 10^6–10^9,量纲差几个数量级,拟合矩阵会严重病态。 Min-max 是最省事的处理方式:把向量压到 [0,1] 区间,且必须在提取价格、算 BIC、建模型之前完成。下方函数即 MT5 向量归一化的可直接拷用版本。 [CODE] void MinMaxScaler(vector &v) { //Normalizing vector using Min-max scaler double min, max, mean; min = v.Min(); max = v.Max(); mean = v.Mean(); for (int i=0; i<(int)v.Size(); i++) v[i] = (v[i] - min) / (max - min); } [/CODE] 逐行看:先取向量最小、最大值;遍历每个元素,用 (原值-最小)/(最大-最小) 重写。mean 虽取了但未参与计算,可删。 实操中,先 SymbolSelect 把两个品种加进市场报价,再用 CopyRates 取 H1 收盘价分别灌入 x_v、y_v,随后对两者各调一次 MinMaxScaler。接着用 BIC 扫不同阶数找最优(示例里 best_order 出来是 2),建模型预测并画图。 别把正态当圣经:多项式回归底子仍是线性模型,要求两者有关联但未必线性。纳斯达克 vs 苹果那组相关系数不到 1%,跑出来 R² 仅 2.36%(SP500,D1 上同脚本也只 2.36%),属于最差档。外汇、贵金属杠杆高、跳空频繁,这类低相关对直接套多项式回归大概率无效,先测相关系数再决定要不要跑模型。

MQL5 / C++
class="type">void MinMaxScaler(vector &v)
{
  class=class="str">"cmt">//Normalizing vector class="kw">using Min-max scaler
  class="type">class="kw">double min, max, mean;
  min = v.Min();
  max = v.Max();
  mean = v.Mean();
  for (class="type">int i=class="num">0; i<(class="type">int)v.Size(); i++)
    v[i] = (v[i] - min) / (max - min);
}

◍ 用 Print 把相关系数打出来

在 MT5 的 EA 或脚本里,想快速确认两组序列的相关性,最直接的就是调用 CorrCoef 后用 Print 输出。 把 x_v 和 y_v 两个已构造好的序列对象传入 x_v.CorrCoef(y_v),函数返回皮尔逊相关系数,范围在 -1 到 1 之间。 打开 MT5 终端的「专家」标签页,就能看到实时打印的「correlation coefficient」及数值,无需额外绘图即可做初步验证。外汇与贵金属杠杆高、波动剧烈,相关系数仅反映历史线性关联,样本外可能快速失效。

MQL5 / C++
  Print("correlation coefficient ",x_v.CorrCoef(y_v));

「多项式回归能做什么、怕什么」

多项式回归最大的价值,是能把变量间的非线性关系用一条曲线兜住。MT5 里你随便换 2 次、3 次甚至更高阶项,就能看出哪条拟合线更贴你那段行情数据,这对探索型复盘很实用。 它编码成本极低,但解释力不弱:系数符号和显著性直接告诉你价格对因子的弹性方向。缺点是异常值会狠狠拽偏整条回归线,一根错价 tick 可能让低阶模型变形。 更麻烦的是过拟合倾向。阶数堆太高,样本内 R² 冲到 0.98 也别高兴太早,模型在外围行情大概率失效。外汇与贵金属杠杆高、跳空频繁,拿过拟合多项式去推演拐点风险极大。

别急着下结论

多项式回归在价格行为建模里最实用的地方,是当自变量和因变量的关系明显偏离线性时,它能补上线性模型顾不到的弯曲段,给 MT5 上的自定义指标留更多自由度。 但参数模型越灵活越容易过拟合:一个在训练集上 R² 冲到 0.98 的 5 阶多项式,放到未参与的行情样本上可能直接跌到 0.3 以下。外汇与贵金属杠杆高、滑点无常,这种回撤不是纸面风险。 稳妥做法是阶数能低就低,给残差留出错空间,先用 Polynomial_Regression.zip(4.8 KB)里的脚本在 EURUSD 的 H1 上跑一遍不同阶数对比再谈策略。

常见问题

把不同阶数模型分别拟合,算各自 BIC 值,选 BIC 最小的那个阶数;BIC 会惩罚参数过多,避免你硬上高阶过拟合。
高阶项数值跨度极大,不缩放会让求解矩阵病态、系数爆炸;先对自变量做标准化再拟合,曲线才稳。
可以,小布能按你的品种数据跑不同阶数并列出 BIC 与相关系数,直接标出最可能合适的阶数和风险点。
在回测或计算脚本里用 Print 把 R²、相关系数、各阶系数输出到日志,肉眼核对哪阶更贴合样本。
只能拟合已有样本的形态倾向,外推高风险;别拿高阶曲线当未来路径,价差和滑点会让实盘偏离。外汇贵金属属高风险,结论仅作概率参考。