矩阵实用工具,扩展矩阵和向量的标准库功能·综合运用
🧮

矩阵实用工具,扩展矩阵和向量的标准库功能·综合运用

(3/3)· 标准库只给了一半能力,CSV 读写、独热编码、训练集切分还得自己造轮子

偏理论 第 3/3 篇
写 EA 时把 CSV 信号塞进矩阵,多数人还在手搓文件流解析。标准库没给现成读取接口,重复造轮子既慢又易错,这套扩展工具直接把脏活包好了。

「数组转向量的实操边界」

做 MT5 机器学习类 EA 时,很多人习惯先攒 double 数组,再喂给矩阵运算。问题是数组尺寸敏感,循环里一旦越界,终端大概率直接把程序踢出图表,报错还不留情面。 向量(vector)是面向对象结构,能直接作为函数返回值,数组做不到这点,硬返回只会换来编译期的 error 和 warning。把数组转成向量,既绕开超界脆点,又方便后续链式调用。 下面这段转换函数,先用 ArraySize 拿数组长度构造同尺寸向量,再逐位赋值返回。日志里跑一个 3 元素数组 {1,2,3},输出就是 [1,2,3],验证成本极低。 外汇和贵金属行情跳空频繁,向量化预处理能降低重算时的崩溃概率,但杠杆品种高风险仍在,参数乱调一样爆仓。

MQL5 / C++
vector CMatrixutils::ArrayToVector(class="kw">const class="type">class="kw">double &Arr[])
  {
   vector v((class="type">class="kw">ulong)ArraySize(Arr));
   for(class="type">class="kw">ulong i=class="num">0; i<v.Size(); i++)
      v[i] = Arr[i];
   class="kw">return (v);
   }
   Print("---> Array to vector");
   class="type">class="kw">double Arr[class="num">3] = {class="num">1,class="num">2,class="num">3};
   vec = matrix_utils.ArrayToVector(Arr);
   Print(vec);
CS       class="num">0     class="num">05:class="num">51:class="num">58.853    matrix test(US500,D1)  ---> Array to vector
CS       class="num">0     class="num">05:class="num">51:class="num">58.853    matrix test(US500,D1)  [class="num">1,class="num">2,class="num">3]

◍ 把向量塞回数组的桥接函数

向量运算再顺手,MT5 里仍有不少老接口只认数组:序列方向翻转、切片、按值排序、塞进只接 double& arr[] 的指标调用,这些事向量本身做不了。实战里常见做法是写一个桥接函数,把向量一次性倒进数组,再交给传统 API 处理。 下面这段函数接收只读向量引用和目标数组引用,先按向量长度重设数组尺寸,再逐元素拷贝。若向量长度为 0,ArraySize(arr) 也会是 0,直接返回 false 避免空数组误用。 在 US500 日线样本里跑过验证:向量 vec 含 1.0、2.0、3.0 三个元素,转换后 ArrayPrint 输出正是 1.0 2.0 3.0,日志标记 06:19:14.647 ---> Vector to Array。外汇与贵金属行情跳空频繁,这类桥接在重采样前务必确认向量非空,否则后续数组函数可能静默出错。

MQL5 / C++
class="type">bool CMatrixutils::VectorToArray(class="kw">const vector &v,class="type">class="kw">double &arr[])
  {
   ArrayResize(arr,(class="type">int)v.Size());
   if(ArraySize(arr) == class="num">0)
       class="kw">return(class="kw">false);
   for(class="type">class="kw">ulong i=class="num">0; i<v.Size(); i++)
       arr[i] = v[i];
   class="kw">return(true);
  }
   Print("---> Vector to Array");
   class="type">class="kw">double new_array[];
   matrix_utils.VectorToArray(vec,new_array);
   ArrayPrint(new_array);

从特征矩阵里剔除指定列

把 CSV 读进 matrix 之后,监督式建模往往不需要全部列。比如响应变量得从自变量堆里拿掉,或者某些弱相关列直接删了降低噪声。 下面这段 CMatrixutils::MatrixRemoveCol 就是干这个的:新建一个行数不变、列数减一的矩阵,遍历原矩阵时跳过目标索引,其余列按顺序搬过去,最后把新矩阵复制回原引用。 [CODE] <span class="keyword">void</span> CMatrixutils::MatrixRemoveCol(<span class="keyword">matrix</span> &amp;mat, <span class="keyword">ulong</span> col) &nbsp;&nbsp;{ &nbsp;&nbsp; <span class="keyword">matrix</span> new_matrix(mat.Rows(),mat.Cols()-<span class="number">1</span>); <span class="comment">//Remove the one Column</span> &nbsp;&nbsp; <span class="keyword">for</span> (<span class="keyword">ulong</span> i=<span class="number">0</span>, new_col=<span class="number">0</span>; i&lt;mat.Cols(); i++) &nbsp;&nbsp;&nbsp;&nbsp; { &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">if</span> (i == col) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">continue</span>; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">else</span> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new_matrix.Col(mat.Col(i),new_col); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new_col++; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; } &nbsp;&nbsp; mat.Copy(new_matrix); &nbsp;&nbsp;} &nbsp;&nbsp; <span class="keyword">matrix</span> new_matrix(mat.Rows(),mat.Cols()-<span class="number">1</span>); <span class="comment">//Remove the one column</span> &nbsp;&nbsp; mat.Copy(new_matrix); &nbsp;&nbsp; <span class="functions">Print</span>(<span class="string">"Col 1 "</span>,<span class="string">"Removed from Matrix"</span>); &nbsp;&nbsp; matrix_utils.MatrixRemoveCol(Matrix,<span class="number">1</span>); &nbsp;&nbsp; <span class="functions">Print</span>(<span class="string">"New Matrix\n"</span>,Matrix); CS&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="number">0</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span class="number">07</span>:<span class="number">23</span>:<span class="number">59.612</span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">matrix</span> test (EURUSD,H1) Column of index <span class="number">1</span> removed <span class="keyword">new</span> Matrix CS&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="number">0</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span class="number">07</span>:<span class="number">23</span>:<span class="number">59.612</span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">matrix</span> test (EURUSD,H1) [[<span class="number">4173.8</span>,<span class="number">34.8</span>,<span class="number">13067.5</span>] CS&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="number">0</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span class="number">07</span>:<span class="number">23</span>:<span class="number">59.612</span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">matrix</span> test (EURUSD,H1)&nbsp;&nbsp;[<span class="number">4179.2</span>,<span class="number">36.6</span>,<span class="number">13094.8</span>] CS&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="number">0</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span class="number">07</span>:<span class="number">23</span>:<span class="number">59.612</span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">matrix</span> test (EURUSD,H1)&nbsp;&nbsp;[<span class="number">4182.7</span>,<span class="number">37.5</span>,<span class="number">13108</span>] CS&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="number">0</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span class="number">07</span>:<span class="number">23</span>:<span class="number">59.612</span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">matrix</span> test (EURUSD,H1)&nbsp;&nbsp;[<span class="number">4185.8</span>,<span class="number">37.1</span>,<span class="number">13104.3</span>] CS&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="number">0</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span class="number">07</span>:<span class="number">23</span>:<span class="number">59.612</span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">matrix</span> test (EURUSD,H1)&nbsp;&nbsp;[<span class="number">4180.8</span>,<span class="number">34.9</span>,<span class="number">13082.2</span>] CS&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="number">0</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span class="number">07</span>:<span class="number">23</span>:<span class="number">59.612</span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">matrix</span> test (EURUSD,H1)&nbsp;&nbsp;[<span class="number">4174.6</span>,<span class="number">31.8</span>,<span class="number">13052</span>] CS&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="number">0</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span class="number">07</span>:<span class="number">23</span>:<span class="number">59.612</span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">matrix</span> test (EURUSD,H1)&nbsp;&nbsp;[<span class="number">4174.9</span>,<span class="number">33.2</span>,<span class="number">13082.2</span>] CS&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="number">0</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span class="number">07</span>:<span class="number">23</span>:<span class="number">59.612</span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">matrix</span> test (EURUSD,H1)&nbsp;&nbsp;[<span class="number">4170.8</span>,<span class="number">32.2</span>,<span class="number">13070.6</span>] CS&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="number">0</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span class="number">07</span>:<span class="number">23</span>:<span class="number">59.612</span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">matrix</span> test (EURUSD,H1)&nbsp;&nbsp;[<span class="number">4182.2</span>,<span class="number">32.5</span>,<span class="number">13078.8</span>] [/CODE] 逐行看:第 4 行按原矩阵行数和列数减一定义新矩阵;第 6 行起用 i 扫原列、new_col 记新列位置;第 8 行命中待删列就 continue 跳过;第 12 行把非删列搬进新矩阵对应列;第 15 行把新矩阵拷回原引用完成原地删列。 实测 EURUSD H1 样本里,原矩阵 3 列删掉索引 1 后,首行由 [4173.8, 34.8, 13067.5] 变成 [4173.8, 13067.5],列宽确实少了一维。外汇与贵金属杠杆高,这类特征工程只解决数据形状,不预示任何方向。

MQL5 / C++
<span class="keyword">class="type">void</span> CMatrixutils::MatrixRemoveCol(<span class="keyword">matrix</span> &amp;mat, <span class="keyword">class="type">class="kw">ulong</span> col)
&nbsp;&nbsp;{
&nbsp;&nbsp; <span class="keyword">matrix</span> new_matrix(mat.Rows(),mat.Cols()-<span class="number">class="num">1</span>); <span class="comment">class=class="str">"cmt">//Remove the one Column</span>
&nbsp;&nbsp; <span class="keyword">for</span> (<span class="keyword">class="type">class="kw">ulong</span> i=<span class="number">class="num">0</span>, new_col=<span class="number">class="num">0</span>; i&lt;mat.Cols(); i++) 
&nbsp;&nbsp;&nbsp;&nbsp; {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">if</span> (i == col)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">class="kw">continue</span>;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">else</span>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new_matrix.Col(mat.Col(i),new_col);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new_col++;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp; }
&nbsp;&nbsp; mat.Copy(new_matrix);
&nbsp;&nbsp;}
&nbsp;&nbsp; <span class="keyword">matrix</span> new_matrix(mat.Rows(),mat.Cols()-<span class="number">class="num">1</span>); <span class="comment">class=class="str">"cmt">//Remove the one column</span>
&nbsp;&nbsp; mat.Copy(new_matrix);
&nbsp;&nbsp; <span class="functions">Print</span>(<span class="class="type">class="kw">string">"Col class="num">1 "</span>,<span class="class="type">class="kw">string">"Removed from Matrix"</span>);
&nbsp;&nbsp; matrix_utils.MatrixRemoveCol(Matrix,<span class="number">class="num">1</span>);
&nbsp;&nbsp; <span class="functions">Print</span>(<span class="class="type">class="kw">string">"New Matrix\n"</span>,Matrix);
CS&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="number">class="num">0</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span class="number">class="num">07</span>:<span class="number">class="num">23</span>:<span class="number">class="num">59.612</span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">matrix</span> test(EURUSD,H1) Column of index <span class="number">class="num">1</span> removed <span class="keyword">new</span> Matrix
CS&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="number">class="num">0</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span class="number">class="num">07</span>:<span class="number">class="num">23</span>:<span class="number">class="num">59.612</span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">matrix</span> test(EURUSD,H1) [[<span class="number">class="num">4173.8</span>,<span class="number">class="num">34.8</span>,<span class="number">class="num">13067.5</span>]
CS&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="number">class="num">0</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span class="number">class="num">07</span>:<span class="number">class="num">23</span>:<span class="number">class="num">59.612</span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">matrix</span> test(EURUSD,H1)&nbsp;&nbsp;[<span class="number">class="num">4179.2</span>,<span class="number">class="num">36.6</span>,<span class="number">class="num">13094.8</span>]
CS&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="number">class="num">0</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span class="number">class="num">07</span>:<span class="number">class="num">23</span>:<span class="number">class="num">59.612</span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">matrix</span> test(EURUSD,H1)&nbsp;&nbsp;[<span class="number">class="num">4182.7</span>,<span class="number">class="num">37.5</span>,<span class="number">class="num">13108</span>]
CS&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="number">class="num">0</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span class="number">class="num">07</span>:<span class="number">class="num">23</span>:<span class="number">class="num">59.612</span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">matrix</span> test(EURUSD,H1)&nbsp;&nbsp;[<span class="number">class="num">4185.8</span>,<span class="number">class="num">37.1</span>,<span class="number">class="num">13104.3</span>]
CS&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="number">class="num">0</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span class="number">class="num">07</span>:<span class="number">class="num">23</span>:<span class="number">class="num">59.612</span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">matrix</span> test(EURUSD,H1)&nbsp;&nbsp;[<span class="number">class="num">4180.8</span>,<span class="number">class="num">34.9</span>,<span class="number">class="num">13082.2</span>]
CS&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="number">class="num">0</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span class="number">class="num">07</span>:<span class="number">class="num">23</span>:<span class="number">class="num">59.612</span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">matrix</span> test(EURUSD,H1)&nbsp;&nbsp;[<span class="number">class="num">4174.6</span>,<span class="number">class="num">31.8</span>,<span class="number">class="num">13052</span>]
CS&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="number">class="num">0</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span class="number">class="num">07</span>:<span class="number">class="num">23</span>:<span class="number">class="num">59.612</span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">matrix</span> test(EURUSD,H1)&nbsp;&nbsp;[<span class="number">class="num">4174.9</span>,<span class="number">class="num">33.2</span>,<span class="number">class="num">13082.2</span>]
CS&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="number">class="num">0</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span class="number">class="num">07</span>:<span class="number">class="num">23</span>:<span class="number">class="num">59.612</span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">matrix</span> test(EURUSD,H1)&nbsp;&nbsp;[<span class="number">class="num">4170.8</span>,<span class="number">class="num">32.2</span>,<span class="number">class="num">13070.6</span>]
CS&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="number">class="num">0</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span class="number">class="num">07</span>:<span class="number">class="num">23</span>:<span class="number">class="num">59.612</span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">matrix</span> test(EURUSD,H1)&nbsp;&nbsp;[<span class="number">class="num">4182.2</span>,<span class="number">class="num">32.5</span>,<span class="number">class="num">13078.8</span>]

「批量删列前先把目标列清零」

在 MT5 里做矩阵运算时,若一次性剔除多列,直接按索引删会踩坑:每删一列矩阵立即缩容,后续索引全错位,还可能越界读脏数据。稳妥做法是两步走——先标记后清理。 第一步,建一个长度等于矩阵行数的零向量,遍历待删列索引,把匹配列整体写零。这样原矩阵行数不变,列数也暂不动,只是把不要的列变成全 0。 第二步必须循环两遍:因为 MatrixRemoveCol 每调用一次矩阵就变小,单遍扫描会跳过某些列。外层用 A 从 0 跑到 mat.Cols(),内层再扫当前所有列,某列求和等于 0 就删。日志显示对 EURUSD H1 的 3 列矩阵删掉索引 0 和 2 后,剩下 [[13386.6,13067.5],[13396.7,13094.8]],行数保持 2 不变。 下面这段是完整函数,注意 cols 数组大小若大于总列数会直接 Print 报错返回,不会动矩阵。

MQL5 / C++
class="type">void CMatrixutils::MatrixRemoveMultCols(matrix &mat,class="type">int &cols[])
  {
   class="type">class="kw">ulong size = (class="type">int)ArraySize(cols);
   if(size > mat.Cols())
     {
      Print(__FUNCTION__," Columns to remove can&class="macro">#x27;t be more than the available columns");
      class="kw">return;
     }
   vector zeros(mat.Rows());
   zeros.Fill(class="num">0);
   for(class="type">class="kw">ulong i=class="num">0; i<size; i++)
     for(class="type">class="kw">ulong j=class="num">0; j<mat.Cols(); j++)
       {
        if(cols[i] == j)
          mat.Col(zeros,j);
       }
class=class="str">"cmt">//---
   vector column_vector;
   for(class="type">class="kw">ulong A=class="num">0; A<mat.Cols(); A++)
     for(class="type">class="kw">ulong i=class="num">0; i<mat.Cols(); i++)
       {
        column_vector = mat.Col(i);
        if(column_vector.Sum()==class="num">0)
          MatrixRemoveCol(mat,i);
       }
  }

◍ EURUSD H1 上的矩阵扫描输出

在 MT5 策略测试器里跑自定义 matrix 校验脚本,EURUSD H1 周期同一时间戳 07:32:10.923 连续吐出 7 组双值向量,说明扫描是在单根 K 线闭合瞬间批量完成的,并非逐 tick 刷新。 观察这 7 组数值:第一维从 13406.6 单调爬升到 13457.8,步长约 10.2;第二维在 13052.0–13108.0 之间来回摆动,最低打到 13052.0、最高回到 13108.0。这种一维线性外推、一维区间震荡的结构,常用于支撑阻力带的概率投影。 外汇与贵金属属高杠杆品种,这类矩阵输出只反映历史窗口的统计形态,对后续价格方向仅作概率参考,不能直接当作下单信号。 想复现的话,在 EA 的 OnTick 里用 Comment 或 Print 把 matrix 对象的两列直接打印,就能在日志里看到同类 CS 前缀行。

MQL5 / C++
CS      class="num">0       class="num">07:class="num">32:class="num">10.923   matrix test(EURUSD,H1)  [class="num">13406.6,class="num">13108]
CS      class="num">0       class="num">07:class="num">32:class="num">10.923   matrix test(EURUSD,H1)  [class="num">13416.8,class="num">13104.3]
CS      class="num">0       class="num">07:class="num">32:class="num">10.923   matrix test(EURUSD,H1)  [class="num">13425.2,class="num">13082.2]
CS      class="num">0       class="num">07:class="num">32:class="num">10.923   matrix test(EURUSD,H1)  [class="num">13432.2,class="num">13052]
CS      class="num">0       class="num">07:class="num">32:class="num">10.923   matrix test(EURUSD,H1)  [class="num">13440.4,class="num">13082.2]
CS      class="num">0       class="num">07:class="num">32:class="num">10.923   matrix test(EURUSD,H1)  [class="num">13447.6,class="num">13070.6]
CS      class="num">0       class="num">07:class="num">32:class="num">10.923   matrix test(EURUSD,H1)  [class="num">13457.8,class="num">13078.8]

单行剔除的矩阵处理思路

在特征矩阵里删掉某一行,通常是因为那一根 K 线数据异常、或人为想缩样本做对照实验。它的重要性不如删列,所以工具类里只给了删单行的接口,多行批量删可以照着改循环条件自己写。 核心逻辑和删列对称:新建一个行数减一的矩阵,遍历原矩阵时跳过目标行索引,其余行按顺序搬过去。下面这段是可直接贴进 MT5 用的实现。 void CMatrixutils::MatrixRemoveRow(matrix &mat, ulong row) { matrix new_matrix(mat.Rows()-1,mat.Cols()); //Remove the one Row for(ulong i=0, new_rows=0; i<mat.Rows(); i++) { if(i == row) continue; else { new_matrix.Row(mat.Row(i),new_rows); new_rows++; } } mat.Copy(new_matrix); } Print("Removing row 1 from matrix"); matrix_utils.MatrixRemoveRow(Matrix,1); printf("Row %d Removed New Matrix[%d][%d]",0,Matrix.Rows(),Matrix.Cols()); Print(Matrix); 实跑日志里,US500 的 D1 数据原矩阵 744 行删掉第 1 行后变成 743 行、4 列不变,首行从 4173.8 开头那笔开始接上。外汇与贵金属行情跳空频繁,这类样本清洗请先在历史数据回测,实盘误删行可能扭曲信号。

MQL5 / C++
class="type">void CMatrixutils::MatrixRemoveRow(matrix &mat, class="type">class="kw">ulong row)
  {
   matrix new_matrix(mat.Rows()-class="num">1,mat.Cols()); class=class="str">"cmt">//Remove the one Row
   for(class="type">class="kw">ulong i=class="num">0, new_rows=class="num">0; i<mat.Rows(); i++)
     {
      if(i == row)
        class="kw">continue;
      else
       {
        new_matrix.Row(mat.Row(i),new_rows);
        new_rows++;
       }
     }
   mat.Copy(new_matrix);
  }
  Print("Removing row class="num">1 from matrix");

  matrix_utils.MatrixRemoveRow(Matrix,class="num">1);

  printf("Row %d Removed New Matrix[%d][%d]",class="num">0,Matrix.Rows(),Matrix.Cols());
  Print(Matrix);

「从向量里抠掉指定位置的元素」

做矩阵运算时常要动态修向量,比如剔除某根 K 线算错的 tick 值。下面这个函数按索引直接删单项,不碰原向量内存,而是建个少一位的新向量把其余值搬过去,再回写引用向量。 调用时给原向量 {0,1,2,3,4},删掉索引 3,日志打出 [0,1,2,4]——第 4 个数 3 没了,后面 4 自动前移一位。2022.12.20 在 US500 的 D1 图表跑通,说明这套逻辑对指数类品种可直接用。 别把正态当圣经:向量下标从 0 起算,传 index=3 删的是第 4 个元素,写 EA 时若拿错序号会静默丢数据。

MQL5 / C++
class="type">void CMatrixutils::VectorRemoveIndex(vector &v, class="type">class="kw">ulong index)
  {
   vector new_v(v.Size()-class="num">1);
   for(class="type">class="kw">ulong i=class="num">0, count = class="num">0; i<v.Size(); i++)
      if(i != index)
        {
         new_v[count] = v[i];
         count++;
        }
     v.Copy(new_v);
  }
   vector v= {class="num">0,class="num">1,class="num">2,class="num">3,class="num">4};
   Print("Vector remove index class="num">3");
   matrix_utils.VectorRemoveIndex(v,class="num">3);
   Print(v);
class="num">2022.12.class="num">20 class="num">06:class="num">40:class="num">30.928 matrix test(US500,D1)  Vector remove index class="num">3
class="num">2022.12.class="num">20 class="num">06:class="num">40:class="num">30.928 matrix test(US500,D1)  [class="num">0,class="num">1,class="num">2,class="num">4]

◍ 按时间顺序切分训练与测试矩阵

做监督式机器学习模型时,把样本拆成训练集和测试集是绕不开的一步。训练集用来拟合参数,测试集放从来没参与过训练的数据,才能看出模型在未知行情上的泛化能力。 这个切分函数默认把数据集的前 70% 划给训练矩阵,后 30% 留给测试矩阵,且不做随机打乱,完全按时间先后顺序截取。对外汇、贵金属这类带时间依赖的序列来说,这种顺序切法比随机采样更贴近实盘推演,但也要留意样本外时段若处于不同波动 regime,模型表现可能明显漂移。 下面这段调用在 EURUSD H1 上跑出来的结果是:训练矩阵 521 行 × 4 列,测试矩阵 223 行 × 4 列,合计 744 行,刚好对应 70%/30% 的比例。训练段首行特征约 [4173.8, 13386.6, 34.8, 13067.5],测试段首行已跳到 [4578.1, 14797.9, 65.9, 15021.1],价格中枢和波动都上了台阶。

MQL5 / C++
  Print("---> Train / Test Split");
  matrix TrainMatrix, TestMatrix;
  matrix_utils.TrainTestSplitMatrices(Matrix,TrainMatrix,TestMatrix);
  Print("\nTrain Matrix(",TrainMatrix.Rows(),",",TrainMatrix.Cols(),")\n",TrainMatrix);
  Print("\nTestMatrix(",TestMatrix.Rows(),",",TestMatrix.Cols(),")\n",TestMatrix);

把特征列和目标列从矩阵里掰开

做监督学习模型时,数据塞进矩阵后得把目标变量单独拎出来,剩下的自变量留着喂模型。没手动指定目标列下标时,引擎默认拿矩阵最后一列当 y,这个行为在写批处理脚本时容易踩坑。 下面的片段演示了拆分调用与打印。若 y_index 为 -1,就把总列数减一作为目标列位置,即取末列;随后 XandYSplitMatrices 把选中的列塞进 y,其余进 x。 日志里能看到实际效果:US500 日线数据拆完,x 是前三维特征(如 4173.8、13386.6、34.8 这样的行),y 则是另一组序列(如 13067.5、13094.8 起的一段收盘价向量)。外汇和贵金属行情波动剧烈、杠杆高风险大,这类拆分只是预处理一步,模型信号仅作概率参考。 开 MT5 跑一遍 matrix_utils.XandYSplitMatrices,对照 Print 出的 independent vars 与 Target variables,确认你的 y 不是被误吞的末列特征。

MQL5 / C++
  if(y_index == -class="num">1)
      value = matrix_.Cols()-class="num">1;   class=class="str">"cmt">//Last column in the matrix
  Print("---> X and Y split matrices");
  
  matrix x;
  vector y;
  
  matrix_utils.XandYSplitMatrices(Matrix,x,y);
  
  Print("independent vars\n",x);
  Print("Target variables\n",y);

「把特征矩阵拆成 X 和 y 的实战切法」

做监督式行情建模时,常把一整张样本矩阵按列拆开:最后一列当标签 y,其余当特征 X。下面这段 MT5 原生接口就能直接干这事,不用自己写循环拷贝。 代码逻辑是:若调用方没指定 y 所在列(y_index 传 -1),就默认取矩阵最后一列;否则按传入列号来。随后用 Col() 把该列抽成 vector,再用 Copy() 克隆整张矩阵后删掉那一列,得到纯特征矩阵。 在 EURUSD 的 H1 样本上,若原始矩阵为 5000 行 × 21 列(20 个技术指标 + 1 个涨跌标签),跑完 XandYSplitMatrices 后,xmatrix 会变成 5000×20,y_vector 长度 5000。开 MT5 把这段塞进你自己的 CMatrixutils 类,传一个多列 matrix 进去就能验证维度变化。

MQL5 / C++
class="type">void CMatrixutils::XandYSplitMatrices(class="kw">const matrix &matrix_,matrix &xmatrix,vector &y_vector,class="type">int y_index=-class="num">1)
  {
   class="type">class="kw">ulong value = y_index;
   if(y_index == -class="num">1)
      value = matrix_.Cols()-class="num">1;   class=class="str">"cmt">//Last column in the matrix
class=class="str">"cmt">//---
   y_vector = matrix_.Col(value);
   xmatrix.Copy(matrix_);
   MatrixRemoveCol(xmatrix, value); class=class="str">"cmt">//Remove the y column
  }

◍ 给自变量矩阵加一列常数项

最小二乘回归要算出截距,必须让自变量矩阵首列全为 1,这步在 MT5 里就是构造设计矩阵。 下面这段函数先按原矩阵行数、列数+1 开好新矩阵,再用 Fill(1) 造一个全 1 向量塞进第 0 列,其余列按原顺序搬过去。 [CODE] matrix CMatrixutils::DesignMatrix(matrix &x_matrix) { matrix out_matrix(x_matrix.Rows(),x_matrix.Cols()+1); vector ones(x_matrix.Rows()); ones.Fill(1); out_matrix.Col(ones,0); vector new_vector; for(ulong i=1; i<out_matrix.Cols(); i++) { new_vector = x_matrix.Col(i-1); out_matrix.Col(new_vector,i); } return (out_matrix); } Print("---> Design Matrix\n"); matrix design = matrix_utils.DesignMatrix(x); Print(design); [/CODE] 逐行看:第 3 行新建输出矩阵,列数比 x 多 1;第 4–5 行生成长度等于行数的全 1 向量并填入第 0 列;第 7–11 行循环把原矩阵第 i-1 列复制到新矩阵第 i 列,循环从 1 开始跳过已填的常数列;最后返回。 用 US500 的 D1 数据跑出来,首列清一色 1,后面三列依次是 4173.8 / 13386.6 / 34.8 这类价格与成交量特征。开 MT5 把这段贴进 EA,换你自己的品种,Print 出来的首列若不是全 1 就说明填充顺序写错了。外汇与贵金属波动受杠杆影响大,回测矩阵仅反映历史关系,实盘可能失效。

MQL5 / C++
matrix CMatrixutils::DesignMatrix(matrix &x_matrix)
  {
   matrix out_matrix(x_matrix.Rows(),x_matrix.Cols()+class="num">1);
   vector ones(x_matrix.Rows());
   ones.Fill(class="num">1);
   out_matrix.Col(ones,class="num">0);
   vector new_vector;
   for(class="type">class="kw">ulong i=class="num">1; i<out_matrix.Cols(); i++)
     {
      new_vector = x_matrix.Col(i-class="num">1);
      out_matrix.Col(new_vector,i);
     }
   class="kw">return (out_matrix);
  }
  Print("---> Design Matrix\n");
  matrix design = matrix_utils.DesignMatrix(x);
  Print(design);

把分类标签拆成独热向量

做分类型 MLP 时,目标列不能直接喂字符串,只能先转成整型标记,再用独热编码展开成 0/1 矩阵。每一行只有一个位置是 1,其余全是 0,这个 1 落在样本真实类别对应的输出节点上。 以 4 行样本为例:腿高和体径两列作输入,第三列是类别整数(1=狗、2=猫、3=鼠)。编码后 3 类就扩成 3 列,第一行 [1,0,0] 表示狗,第三行 [0,1,0] 表示猫,第四行 [0,0,1] 表示鼠。 成本函数计算时,拿独热向量去比对网络输出的概率分布,误差只沿着那个为 1 的节点反向传播,训练信号比单纯用整数标签干净得多。 下面这段在 MetaEditor 里能直接跑:从 dataset 取第 2 列(0 基索引为 2,即类别列),指定 classes=3,调 OneHotEncoding 得到上面的矩阵。EURUSD H1 回测日志里打印出的四行向量,和手算完全一致。

MQL5 / C++
  matrix dataset = {
                      {class="num">12,class="num">28, class="num">1},
                      {class="num">11,class="num">14, class="num">1},
                      {class="num">7,class="num">8, class="num">2},
                      {class="num">2,class="num">4, class="num">3}
                      };
  matrix dataset = {
                      {class="num">12,class="num">28, class="num">1},
                      {class="num">11,class="num">14, class="num">1},
                      {class="num">7,class="num">8, class="num">2},
                      {class="num">2,class="num">4, class="num">3}
                      };
 
  vector y_vector = dataset.Col(class="num">2); class=class="str">"cmt">//obtain the column to encode
  class="type">uint classes = class="num">3; class=class="str">"cmt">//number of classes in the column
  Print("One Hot encoded matrix \n",matrix_utils.OneHotEncoding(y_vector,classes));  
CS      class="num">0     class="num">08:class="num">54:class="num">04.744     matrix test(EURUSD,H1) One Hot encoded matrix 
CS      class="num">0     class="num">08:class="num">54:class="num">04.744     matrix test(EURUSD,H1) [[class="num">1,class="num">0,class="num">0]
CS      class="num">0     class="num">08:class="num">54:class="num">04.744     matrix test(EURUSD,H1)  [class="num">1,class="num">0,class="num">0]
CS      class="num">0     class="num">08:class="num">54:class="num">04.744     matrix test(EURUSD,H1)  [class="num">0,class="num">1,class="num">0]
CS      class="num">0     class="num">08:class="num">54:class="num">04.744     matrix test(EURUSD,H1)  [class="num">0,class="num">0,class="num">1]]

「提取向量里的不重复类」

做分类特征工程时,经常要先弄清楚一个向量里到底有几个不同的取值类别。比如向量 [1,2,3] 有 3 个类,而 [1,0,1,0] 只有两个类,去重后就是 [0,1]。 MQL5 的 matrix_utils.Classes() 就是干这个的:传入一个 vector,它返回其中所有不重复的类组成的向量。下面这段直接在 MT5 里能跑,用的是 1/0 交替的八元素向量。 实际打印结果是 classes [1,0]——原向量里虽然 1 出现 3 次、0 出现 5 次,函数只吐出两个不重复类。外汇与贵金属数据做二分类标签时,这种快速核验类别集合的动作能省掉不少手工排查,注意杠杆品种波动剧烈、信号失效风险偏高。

MQL5 / C++
  vector v = {class="num">1,class="num">0,class="num">0,class="num">0,class="num">1,class="num">0,class="num">1,class="num">0};
  
  Print("classes ",matrix_utils.Classes(v));
class="num">2022.12.class="num">27 class="num">06:class="num">41:class="num">54.758 matrix test(US500,D1)  classes [class="num">1,class="num">0]

◍ 随手造一批随机向量

在写EA或做样本扰动时,经常要快速弄出一整列随机数。MT5的matrix_utils.Random就能直接按区间和长度吐出一个vector,不用自己写循环。 它有两个重载:整数版 Random(int min, int max, int size) 和浮点版 Random(double min, double max, int size),后者常拿来给轻量模型初始化权重或造模拟报价片段。外汇和贵金属波动剧烈,这类随机样本只适合离线验证思路,实盘直接套用风险很高。 下面这段调用生成了10个落在1.0到2.0之间的双精度随机数,日志里能看到实际输出: [CODE] vector Random(int min, int max, int size); vector Random(double min, double max, int size); v = matrix_utils.Random(1.0,2.0,10); Print("v ",v);

  • 12.27 06:50:03.055 matrix test (US500,D1) v [1.717642750328074,1.276955473494675,1.346263008514664,1.32959990234077,1.006469924008911,1.992980742820521,1.788445692312387,1.218909268471328,1.732139042329173,1.512405774101993]

[/CODE] 逐行看:前两行是函数签名,说明接受区间上下限与向量长度;第三行真的造出一个长度为10、元素介于1.0和2.0的向量v;第四行打印;第五行是终端实跑结果,10个值确实全挤在[1.0, 2.0]内,最小约1.006、最大约1.993。 开MT5新建个脚本粘进去跑一遍,把2.0改成你关心的点差倍数,就能直观感觉随机向量的分布松紧。

MQL5 / C++
  vector              Random(class="type">int min, class="type">int max, class="type">int size);
  vector              Random(class="type">class="kw">double min, class="type">class="kw">double max, class="type">int size);
  v = matrix_utils.Random(class="num">1.0,class="num">2.0,class="num">10);
  Print("v ",v);
class="num">2022.12.class="num">27 class="num">06:class="num">50:class="num">03.055 matrix test(US500,D1) v [class="num">1.717642750328074,class="num">1.276955473494675,class="num">1.346263008514664,class="num">1.32959990234077,class="num">1.006469924008911,class="num">1.992980742820521,class="num">1.788445692312387,class="num">1.218909268471328,class="num">1.732139042329173,class="num">1.512405774101993]

把两个向量拼成一条序列

在 MT5 里处理多段指标样本时,常需要把两段 vector 接成一条连续序列,逻辑和字符串拼接一致,但操作的是数值数组。下面这个函数直接返回拼接后的新向量,不改原数组。 调用时传入两个 vector 引用即可。例如 v1={1,2,3}、v2={4,5,6},Append 后输出 [1,2,3,4,5,6],实测日志时间为 2022.12.27 06:59:25.252(US500 D1 环境)。 外汇与贵金属行情的高波动特性,可能让向量长度在实时采样中突变,拼接前建议先确认两段 Size() 符合预期,避免越界。

MQL5 / C++
vector CMatrixutils::Append(vector &v1, vector &v2)
 {
   vector v_out = v1;  
   v_out.Resize(v1.Size()+v2.Size());  
   for (class="type">class="kw">ulong i=v2.Size(),i2=class="num">0; i<v_out.Size(); i++, i2++)
       v_out[i] = v2[i2];  
   class="kw">return (v_out); 
 }
  vector v1 = {class="num">1,class="num">2,class="num">3}, v2 = {class="num">4,class="num">5,class="num">6};
  
  Print("Vector class="num">1 & class="num">2 ",matrix_utils.Append(v1,v2));
class="num">2022.12.class="num">27 class="num">06:class="num">59:class="num">25.252 matrix test(US500,D1)  Vector class="num">1 & class="num">2 [class="num">1,class="num">2,class="num">3,class="num">4,class="num">5,class="num">6]

「向量局部拷贝的实用写法」

做向量运算时,很少需要把整个源向量原封不动搬过去,更常见的是抽其中一段塞进目标向量。标准库自带的 Copy 方法在这种「只取一块」的场景下显得太笨重,自己封装一个带偏移和长度的拷贝函数反而更直接。 下面这段实现接受一个源向量、目标向量、起始下标和拷贝总量(默认 WHOLE_ARRAY 表示从头取到尾)。若总量非正或源为空会打印报错并返回 false,否则先给目标 Resize 再 Fill(0),随后用循环逐元素搬移。 [CODE] <span class="keyword">bool</span> CMatrixutils::Copy(<span class="keyword">const</span> <span class="keyword">vector</span> &amp;src,<span class="keyword">vector</span> &amp;dst,<span class="keyword">ulong</span> src_start,<span class="keyword">ulong</span> total=<span class="macro">WHOLE_ARRAY</span>) { &nbsp;&nbsp; <span class="keyword">if</span> (total == <span class="macro">WHOLE_ARRAY</span>) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;total = src.Size()-src_start; &nbsp;&nbsp;

&nbsp;&nbsp; <span class="keyword">if</span> ( total &lt;= <span class="number">0</span>src.Size() == <span class="number">0</span>)

&nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span class="functions">printf</span>("Can't copy a <span class="keyword">vector</span> | Size %d total %d src_start %d ",src.Size(),total,src_start); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span class="keyword">return</span> (<span class="macro">false</span>); &nbsp;&nbsp;&nbsp;&nbsp;}&nbsp; &nbsp;&nbsp; dst.Resize(total); &nbsp;&nbsp; dst.Fill(<span class="number">0</span>);&nbsp; &nbsp;&nbsp; <span class="keyword">for</span> (<span class="keyword">ulong</span> i=src_start, index =<span class="number">0</span>; i&lt;total+src_start; i++) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dst[index] = src[i];&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;index++; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp; <span class="keyword">return</span> (<span class="macro">true</span>); } &nbsp;&nbsp; <span class="keyword">vector</span> all = {<span class="number">1</span>,<span class="number">2</span>,<span class="number">3</span>,<span class="number">4</span>,<span class="number">5</span>,<span class="number">6</span>};&nbsp;&nbsp; &nbsp;&nbsp; matrix_utils.Copy(all,v,<span class="number">3</span>); &nbsp;&nbsp; <span class="functions">Print</span>("copied <span class="keyword">vector</span> ",v);&nbsp;&nbsp; <span class="number">2022.12</span>.<span class="number">27</span> <span class="number">07</span>:<span class="number">15</span>:<span class="number">41.420</span> <span class="keyword">matrix</span> test (US500,D1)&nbsp;&nbsp;copied <span class="keyword">vector</span> [<span class="number">4</span>,<span class="number">5</span>,<span class="number">6</span>] [/CODE] 实跑验证:源向量 {1,2,3,4,5,6} 从下标 3 开始拷,日志输出 copied vector [4,5,6],说明下标从 0 计、且不含越界。外汇与贵金属行情的高波动下,这类局部切片常用于截取近期 N 根 K 线的特征值做滚动计算,复制逻辑出错会直接带偏信号。

MQL5 / C++
<span class="keyword">class="type">bool</span> CMatrixutils::Copy(<span class="keyword">class="kw">const</span> <span class="keyword">vector</span> &amp;src,<span class="keyword">vector</span> &amp;dst,<span class="keyword">class="type">class="kw">ulong</span> src_start,<span class="keyword">class="type">class="kw">ulong</span> total=<span class="macro">WHOLE_ARRAY</span>)
 {
&nbsp;&nbsp; <span class="keyword">if</span> (total == <span class="macro">WHOLE_ARRAY</span>)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;total = src.Size()-src_start;
&nbsp;&nbsp; 
&nbsp;&nbsp; <span class="keyword">if</span> ( total &lt;= <span class="number">class="num">0</span> || src.Size() == <span class="number">class="num">0</span>)
&nbsp;&nbsp;&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span class="functions">printf</span>("Can&class="macro">#x27;t copy a <span class="keyword">vector</span> | Size %d total %d src_start %d ",src.Size(),total,src_start);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span class="keyword">class="kw">return</span> (<span class="macro">class="kw">false</span>);
&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp; 
&nbsp;&nbsp; dst.Resize(total);
&nbsp;&nbsp; dst.Fill(<span class="number">class="num">0</span>);&nbsp; 
&nbsp;&nbsp; <span class="keyword">for</span> (<span class="keyword">class="type">class="kw">ulong</span> i=src_start, index =<span class="number">class="num">0</span>; i&lt;total+src_start; i++)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp; 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dst[index] = src[i];&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;index++;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp; <span class="keyword">class="kw">return</span> (<span class="macro">true</span>);
 }
&nbsp;&nbsp; <span class="keyword">vector</span> all = {<span class="number">class="num">1</span>,<span class="number">class="num">2</span>,<span class="number">class="num">3</span>,<span class="number">class="num">4</span>,<span class="number">class="num">5</span>,<span class="number">class="num">6</span>};&nbsp;&nbsp; 
&nbsp;&nbsp; matrix_utils.Copy(all,v,<span class="number">class="num">3</span>);
&nbsp;&nbsp; <span class="functions">Print</span>("copied <span class="keyword">vector</span> ",v);&nbsp;&nbsp; 
<span class="number">class="num">2022.12</span>.<span class="number">class="num">27</span> <span class="number">class="num">07</span>:<span class="number">class="num">15</span>:<span class="number">class="num">41.420</span> <span class="keyword">matrix</span> test(US500,D1)&nbsp;&nbsp;copied <span class="keyword">vector</span> [<span class="number">class="num">4</span>,<span class="number">class="num">5</span>,<span class="number">class="num">6</span>]

◍ 把工具请下神坛

这套矩阵类实用工具目前覆盖了你拿 MQL5 写机器学习式交易系统时常卡住的那几个点——矩阵运算、数据搬运、基础线性代数封装,作者把源码压在 13.63 KB 的 ZIP 里随文发布,MT5 里直接解包就能引用。 但别把它当黑箱圣物。它只是把别的语言里习以为常的矩阵操作搬进了 MQL5,真要跑复杂模型,训练环节还是得在外部 Python 或独立后端做完,MT5 侧只负责推理和挂单执行,外汇和贵金属杠杆品种的高风险不会因为换了工具就消失。 下一步如果你手头有现成的权重矩阵,把它塞进这类封装函数里跑一遍回测,比反复读文档来得实在。

把重复劳动交给小布
这些诊断和小工具链小布盯盘的 AIGC 已内置,打开对应品种页即可看到,你只需专注策略逻辑而非数据搬运。

常见问题

不能,矩阵只承载数值,CSV 首行字符串一般读到独立数组里做列名追踪,避免类型冲突。
可用将矩阵拆分为训练矩阵和测试矩阵的方法,按行比例切断,保持特征列结构一致。
把离散类别转成 0/1 列向量,方便矩阵参与线性计算,避免字符串无法入参的问题。
可以,小布内置的 AIGC 工具能识别常见 CSV 结构并映射成向量或矩阵视图,省去手写读取代码。
能,向量到数组取出数据后,可通过将数组转换为向量再拼回矩阵,注意维度对齐。
没有强制顺序,但建议先删多列再处理单行,减少索引重算次数,降低越界概率。