MQL5 中的矩阵和向量·综合运用
(3/3)· 前两层铺垫完类型与基础接口,这篇把乘积累加、维度陷阱和复数矩阵一次打通
「MT5 矩阵运算能直接搬哪些 NumPy 套路」
MQL5 的 matrix 类把一堆线性代数原语塞进了原生环境,做多资产协方差、因子加权或回归滤噪时不用自己写循环。换位、逐元素加减乘除、标量与矩阵混合运算、MatMul 积,以及 Inner / Outer / Kron 这些都在列,基本对应 NumPy 的同名语义。 解线性方程组有 Solve(),非方阵或退化矩阵走 LstSq() 拿最小二乘解,PInv() 给伪逆。Inv() 求逆但要先确认条件数别炸,外汇分钟级回归矩阵常接近奇异,直接逆容易数值溢出。 分解方法对照 NumPy 很直白:Cholesky 对应 cholesky,QR 对应 qr,SVD 对应 svd,Eig / EigVals 对应 eig / eigvals。LU 和带行置换的 LUP(PA=LU)也都内置,回测里做状态空间递推时能省不少事。 贵金属跨期价差建模若用 Cholesky 分解降维,注意样本外窗口要滚动重算,历史相关在高波动期会快速失效,杠杆品种回撤风险被放大。
◍ MatMul 里向量和矩阵的排列陷阱
MT5 的 matrix/vector 体系里,MatMul() 做矩阵积时有两套方向规则:左水平向量乘右矩阵,要求向量长度等于矩阵列数;左矩阵乘右垂直向量,要求矩阵列数等于向量长度。若向量长度与矩阵列数对不上,运行时直接抛严重错误,不是返回空值那么简单。 两个矩阵相乘的维度约束是 A[M,N]*B[N,K]=C[M,K],左矩阵列数必须等右矩阵行数,否则得到空矩阵。示例里用 m35(3x5) 乘 m52(5x2) 得到 3x2,维度链断一处就全废。 向量在底层就是特殊矩阵:水平向量是 1xN,垂直向量是 Nx1。代码里 v3.MatMul(m35) 得到长度 5 的水平向量,等价于 m13(1x3).MatMul(m35);m35.MatMul(v5) 得到长度 3 的垂直向量,等价于 m35.MatMul(m51(5x1))。开 MT5 把下面代码跑一遍,对照 Print 输出就能确认向量方向。 别把 Outer 当 MatMul 用。v5.Outer(v3) 得到 5x3 矩阵,和 m15(1x5).Outer(m31(3x1)) 结果一致,但它是外积不是矩阵积,维度逻辑完全不同。外汇/贵金属策略里拿矩阵做多资产权重计算时,乘错方向可能让信号整体反转,属高风险操作。
class="type">void OnStart() { class=class="str">"cmt">//--- initialize matrices matrix m35, m52; m35.Init(class="num">3,class="num">5,Arange); m52.Init(class="num">5,class="num">2,Arange); class=class="str">"cmt">//--- Print("class="num">1. Product of horizontal vector v[class="num">3] and matrix m[class="num">3,class="num">5]"); vector v3 = {class="num">1,class="num">2,class="num">3}; Print("On the left v3 = ",v3); Print("On the right m35 = \n",m35); Print("v3.MatMul(m35) = horizontal vector v[class="num">5] \n",v3.MatMul(m35)); class=class="str">"cmt">//--- show that this is really a horizontal vector Print("\n2. Product of matrix m[class="num">1,class="num">3] and matrix m[class="num">3,class="num">5]"); matrix m13; m13.Init(class="num">1,class="num">3,Arange,class="num">1); Print("On the left m13 = \n",m13); Print("On the right m35 = \n",m35); Print("m13.MatMul(m35) = matrix m[class="num">1,class="num">5] \n",m13.MatMul(m35)); Print("\n3. Product of matrix m[class="num">3,class="num">5] and vertical vector v[class="num">5]"); vector v5 = {class="num">1,class="num">2,class="num">3,class="num">4,class="num">5}; Print("On the left m35 = \n",m35); Print("On the right v5 = ",v5); Print("m35.MatMul(v5) = vertical vector v[class="num">3] \n",m35.MatMul(v5)); class=class="str">"cmt">//--- show that this is really a vertical vector Print("\n4. Product of matrix m[class="num">3,class="num">5] and matrix m[class="num">5,class="num">1]"); matrix m51; m51.Init(class="num">5,class="num">1,Arange,class="num">1); Print("On the left m35 = \n",m35); Print("On the right m51 = \n",m51); Print("m35.MatMul(m51) = matrix v[class="num">3] \n",m35.MatMul(m51)); Print("\n5. Product of matrix m[class="num">3,class="num">5] and matrix m[class="num">5,class="num">2]"); Print("On the left m35 = \n",m35); Print("On the right m52 = \n",m52); Print("m35.MatMul(m52) = matrix m[class="num">3,class="num">2] \n",m35.MatMul(m52)); Print("\n6. Product of horizontal vector v[class="num">5] and matrix m[class="num">5,class="num">2]"); Print("On the left v5 = \n",v5); Print("On the right m52 = \n",m52); Print("v5.MatMul(m52) = horizontal vector v[class="num">2] \n",v5.MatMul(m52)); Print("\n7. Outer() product of horizontal vector v[class="num">5] and vertical vector v[class="num">3]"); Print("On the left v5 = \n",v5); Print("On the right v3 = \n",v3); Print("v5.Outer(v3) = matrix m[class="num">5,class="num">3] \n",v5.Outer(v3)); class=class="str">"cmt">//--- show that the product of matrices generates the same result Print("\n8. Outer() product of the matrix m[class="num">1,class="num">5] and matrix m[class="num">3,class="num">1]"); matrix m15,m31; m15.Init(class="num">1,class="num">5,Arange,class="num">1); m31.Init(class="num">3,class="num">1,Arange,class="num">1); Print("On the left m[class="num">1,class="num">5] = \n",m15); Print("On the right m31 = \n",m31); Print("m15.Outer(m31) = matrix m[class="num">5,class="num">3] \n",m15.Outer(m31)); }
用 Arange 填矩阵看 MatMul 外积怎么算
下面这段函数给任意 matrix 按行优先、从 start 起以 step 递增填值,是验证矩阵乘法结果的手工构造器。把它丢进 MT5 脚本,先造出规则矩阵,再对照 MatMul / Outer 的输出,能直接看清维度对齐规则。 void Arange(matrix &m, double start=0, double step=1) 接收矩阵引用与起止步长;内部取 m.Cols()、m.Rows() 拿到列数与行数,用双层 for 把 value 依次写入 m[r][c] 并累加 step。跑完一个 3×5 矩阵会从 0 填到 14。 实测几组乘积:横向向量 v3=[1,2,3] 乘 m35(3×5)得 [40,46,52,58,64];m35 乘纵向向量 v5=[1,2,3,4,5] 得 [40,115,190]。Outer 外积更直白,v5(1×5)与 v3(3×1)外积出 5×3 矩阵,首行就是 [1,2,3] 的倍数排开。 外汇与贵金属市场杠杆高、跳空频繁,这类线性代数工具只帮你算信号矩阵,不预示行情方向,结论都只是概率层面的参考。
class="type">void Arange(matrix &m, class="type">class="kw">double start = class="num">0, class="type">class="kw">double step = class="num">1) class=class="str">"cmt">// the function has three parameters { class=class="str">"cmt">//--- class="type">class="kw">ulong cols = m.Cols(); class="type">class="kw">ulong rows = m.Rows(); class="type">class="kw">double value = start; for(class="type">class="kw">ulong r = class="num">0; r < rows; r++) { for(class="type">class="kw">ulong c = class="num">0; c < cols; c++) { m[r][c] = value; value += step; } } class=class="str">"cmt">//--- } class=class="str">"cmt">/* Execution result class="num">1. Product of horizontal vector v[class="num">3] and matrix m[class="num">3,class="num">5] On the left v3 = [class="num">1,class="num">2,class="num">3] On the right m35 = [[class="num">0,class="num">1,class="num">2,class="num">3,class="num">4] [class="num">5,class="num">6,class="num">7,class="num">8,class="num">9] [class="num">10,class="num">11,class="num">12,class="num">13,class="num">14]] v3.MatMul(m35) = horizontal vector v[class="num">5] [class="num">40,class="num">46,class="num">52,class="num">58,class="num">64] class="num">2. Product of matrix m[class="num">1,class="num">3] and matrix m[class="num">3,class="num">5] On the left m13 = [[class="num">1,class="num">2,class="num">3]] On the right m35 = [[class="num">0,class="num">1,class="num">2,class="num">3,class="num">4] [class="num">5,class="num">6,class="num">7,class="num">8,class="num">9] [class="num">10,class="num">11,class="num">12,class="num">13,class="num">14]] m13.MatMul(m35) = matrix m[class="num">1,class="num">5] [[class="num">40,class="num">46,class="num">52,class="num">58,class="num">64]] class="num">3. Product of matrix m[class="num">3,class="num">5] and vertical vector v[class="num">5] On the left m35 = [[class="num">0,class="num">1,class="num">2,class="num">3,class="num">4] [class="num">5,class="num">6,class="num">7,class="num">8,class="num">9] [class="num">10,class="num">11,class="num">12,class="num">13,class="num">14]] On the right v5 = [class="num">1,class="num">2,class="num">3,class="num">4,class="num">5] m35.MatMul(v5) = vertical vector v[class="num">3] [class="num">40,class="num">115,class="num">190] class="num">4. Product of matrix m[class="num">3,class="num">5] and matrix m[class="num">5,class="num">1] On the left m35 = [[class="num">0,class="num">1,class="num">2,class="num">3,class="num">4] [class="num">5,class="num">6,class="num">7,class="num">8,class="num">9] [class="num">10,class="num">11,class="num">12,class="num">13,class="num">14]] On the right m51 = [[class="num">1] [class="num">2] [class="num">3] [class="num">4] [class="num">5]] m35.MatMul(m51) = matrix v[class="num">3] [[class="num">40] [class="num">115] [class="num">190]] class="num">5. Product of matrix m[class="num">3,class="num">5] and matrix m[class="num">5,class="num">2] On the left m35 = [[class="num">0,class="num">1,class="num">2,class="num">3,class="num">4] [class="num">5,class="num">6,class="num">7,class="num">8,class="num">9] [class="num">10,class="num">11,class="num">12,class="num">13,class="num">14]] On the right m52 = [[class="num">0,class="num">1] [class="num">2,class="num">3] [class="num">4,class="num">5] [class="num">6,class="num">7] [class="num">8,class="num">9]] m35.MatMul(m52) = matrix m[class="num">3,class="num">2] [[class="num">60,class="num">70] [class="num">160,class="num">195] [class="num">260,class="num">320]] class="num">6. The product of horizontal vector v[class="num">5] and matrix m[class="num">5,class="num">2] On the left v5 = [class="num">1,class="num">2,class="num">3,class="num">4,class="num">5] On the right m52 = [[class="num">0,class="num">1] [class="num">2,class="num">3] [class="num">4,class="num">5] [class="num">6,class="num">7] [class="num">8,class="num">9]] v5.MatMul(m52) = horizontal vector v[class="num">2] [class="num">80,class="num">95] class="num">7. Outer() product of horizontal vector v[class="num">5] and vertical vector v[class="num">3] On the left v5 = [class="num">1,class="num">2,class="num">3,class="num">4,class="num">5] On the right v3 = [class="num">1,class="num">2,class="num">3] v5.Outer(v3) = matrix m[class="num">5,class="num">3] [[class="num">1,class="num">2,class="num">3] [class="num">2,class="num">4,class="num">6] [class="num">3,class="num">6,class="num">9] [class="num">4,class="num">8,class="num">12] [class="num">5,class="num">10,class="num">15]] class="num">8. Outer() product of the matrix m[class="num">1,class="num">5] and matrix m[class="num">3,class="num">1] On the left m[class="num">1,class="num">5] = [[class="num">1,class="num">2,class="num">3,class="num">4,class="num">5]] On the right m31 = [[class="num">1] [class="num">2] [class="num">3]] m15.Outer(m31) = matrix m[class="num">5,class="num">3] [[class="num">1,class="num">2,class="num">3] [class="num">2,class="num">4,class="num">6] [class="num">3,class="num">6,class="num">9] [class="num">4,class="num">8,class="num">12] [class="num">5,class="num">10,class="num">15]] */
「画得少,看得清」
MQL5 里的 complex 类型本质是个含 real 与 imag 双精度字段的结构,但它跳出了普通结构的限制:能作为函数参数按值传递,只有从 DLL 导入时才强制走引用。写常数时后缀 i 直接标虚部,比如 1+2i 就是实 1 虚 2。 目前复数只开放了 =、+、-、*、/ 及对应复合赋值和相等判断这几组基础运算,官方提到后续会补绝对值、正弦、余弦等数学函数,但当下若要做频域滤波还得自己扩。 把上面那段代码丢进 MT5 脚本跑,OnStart 里 Print(square(1+2i)) 会输出 "(-3,4)"——实算 (1+2i)²=1+4i²+4i=-3+4i,验证按值传递和运算符重载都没坑。外汇与贵金属杠杆高、波动剧烈,用复数做信号变换前先在小周期回测,别直接挂实盘。
class="kw">struct complex { class="type">class="kw">double real; class=class="str">"cmt">// real part class="type">class="kw">double imag; class=class="str">"cmt">// imaginary part }; complex square(complex c) { class="kw">return(c*c); } class="type">void OnStart() { Print(square(class="num">1+2i)); class=class="str">"cmt">// a constant is passed as a parameter } class=class="str">"cmt">// will print "(-class="num">3,class="num">4)" - a class="type">class="kw">string representation of a complex number