一维奇异谱分析(SSA)基础篇:把金融序列拆成趋势周期与噪声的线性代数骨架(基础篇)
📐

一维奇异谱分析(SSA)基础篇:把金融序列拆成趋势周期与噪声的线性代数骨架(基础篇)

(1/3)·多数交易者把 SSA 当黑箱调用,却不知轨迹矩阵与秩一分解才是识别市场结构的根

含代码示例偏理论 第 1/3 篇

金融市场的高波动让模式识别异常困难,而 SSA 不需平稳性假设就能拆出趋势、周期与噪声。可惜大量向量矩阵代数术语把新手挡在门外,只会点按钮却不懂轨迹矩阵怎么来的,等于蒙眼调参。本文是系列第一篇,先把四个步骤的数学骨架讲透,不堆公式套话。

◍ 用 SSA 把价格序列拆成可交易的成分

一维奇异谱分析(SSA)在 MT5 里常被当成去趋势和降噪的工具。它把一条价格序列投影到若干正交分量上,再按特征值大小把分量分成趋势、周期和噪声三类,交易者可以只重建前几类来过滤杂波。 在 MT5 的统计分析实践中,窗口长度 L 通常取序列长度 N 的一半左右;若 N=256,L=128 时前 3 个主分量往往已能解释 70% 以上的方差,剩下的大概率是高频噪声。 外汇与贵金属杠杆高、跳空频繁,SSA 重建信号只代表历史结构倾向,实盘仍可能失效,开 MT5 用自带时间序列跑一遍分解再决定参数更稳妥。

「为什么 SSA 值得手动拆一遍」

外汇与贵金属价格序列普遍呈现高波动、非平稳特征,传统滤波手段常因强假设而失真。奇异谱分析(SSA)基于线性代数,不要求序列平稳,能把一段报价拆成趋势、周期与噪声三层结构,对 MT5 历史数据复盘有直接可用性。 但 SSA 文献里铺满向量与矩阵代数,没受过对应训练的实盘者很容易把它当黑箱,只调库不调参。本文系列用可验证的方式把原理落地,让你能在 MT5 里自己跑分解、看成分。 SSA 不是单一算法,而是一族方法,核心都绕不开四步:把序列排成 Hankel 轨迹矩阵;对该矩阵做秩一初等矩阵分解;按结构对初等矩阵分组;重建子序列。下一节我们逐阶段拆开看。

把价格序列折成轨迹矩阵

想把一段一维报价里藏着的连续依赖挖出来,第一步是把序列折成矩阵。拿长度 N 的时间序列,用长度 L 的滑动窗口去截,能切出 K = N − L + 1 个列向量,每个向量长 L,像 {x1,x2,…,xL}、{x2,x3,…,xL+1} 这样依次排,就拼成了轨迹矩阵 X。 窗口长度 L 直接决定分析深度。经验上取 L = N/2 最常用,L 太小看不出结构,太大又会让列数 K 锐减、矩阵过瘦。 在 MT5 里用历史收盘价跑一遍就能验证:换不同 L,矩阵的奇异值分布会明显变化,这也意味着后续分解能抓到的周期成分不一样。外汇与贵金属波动高、跳空多,实盘前务必用历史数据回测确认参数敏感区间。

◍ 把轨迹矩阵拆成秩1基块的实操视角

构造好轨迹矩阵 X 之后,基础奇异谱分析(Basic-SSA)用奇异值分解把它拆开。SVD 产出特征三元组 (√λi, Ui, Vi):σi=√λi 是奇异值,等于 XX' 特征值的平方根;Ui 为左奇异向量,Vi 为右奇异向量,i 的个数就是 X 的秩。 奇异值的大小直接表示成分权重——值大对应趋势或周期这类主导模式,值小大概率是噪声。于是 X 能写成若干个秩为 1 的初等矩阵 Xi 之和,这些秩 1 矩阵就是拼出复杂结构的底料。 确定性序列(指数、正弦、多项式)满足线性递推,轨迹矩阵线性无关向量数有限:指数序列秩为 1,正弦秩为 2,k 次多项式秩为 k+1。实际金价或欧元美元报价混了噪声,是满秩序列,秩 = min(L, K);但若本质是无噪确定性信号加噪声,SSA 就能靠秩 1 基矩阵重组出信号、丢掉噪声再做预测。 下面这段 MT5 脚本直接验证了秩的结论,跑完终端会打印三种序列的秩。注意外汇贵金属报价受噪声主导,满秩是常态,高杠杆下误判信号风险极高,验证时只用历史数据别挂实盘。

MQL5 / C++
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//|                                                                Rank.mq5 |
class=class="str">"cmt">//|                                                                Eugene |
class=class="str">"cmt">//|                                                    [MQL5官方文档] |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="macro">#class="kw">property copyright "Eugene"
class="macro">#class="kw">property link      "[MQL5官方文档]
class="macro">#class="kw">property version   "class="num">1.00"
class="macro">#class="kw">property script_show_inputs
input class="type">int      N  = class="num">100;            class=class="str">"cmt">// N - length of generated time series
input class="type">int      L  = class="num">30;            class=class="str">"cmt">// L - window length
input class="type">int      T  = class="num">22;            class=class="str">"cmt">// T - period length of sine function
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Script program start function                                    |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void OnStart()
  {
   matrix X=matrix::Zeros(L,N-L+class="num">1);
   vector x_exp= vector::Zeros(N);
   vector x_sinus= vector::Zeros(N);
   vector x_polynom= vector::Zeros(N);
   for(class="type">int t=class="num">0; t <N; t++)
     {
      x_exp[t] = MathPow(class="num">1.01,t);          class=class="str">"cmt">// class="num">1. Exponential sequence: x_t = class="num">1.01^t
      x_sinus[t] = MathSin(class="num">2*M_PI*t/T);    class=class="str">"cmt">// class="num">2. Sine wave: x_t = sin(class="num">2 * pi * t / T)
      x_polynom[t] =  class="num">1 + t+ MathPow(t,class="num">2); class=class="str">"cmt">// class="num">3. Polynomial of degree class="num">2: x_t = class="num">1 + t + t^class="num">2
     }
   trajectory_matrix(x_exp,L,X);
   Print("Rank Exponential sequence = ",Rank_SVD(X));
   trajectory_matrix(x_sinus,L,X);
   Print("Rank Sinus sequence = ",Rank_SVD(X));
   trajectory_matrix(x_polynom,L,X);
   Print("Rank Polynom sequence = ",Rank_SVD(X));
  }
class=class="str">"cmt">//+------------------------------------------------------------------+

「用轨迹矩阵和SVD给序列定秩」

做奇异谱分析(SSA)的第一步,是把一维价格序列铺成轨迹矩阵。下面这段把长度为 N 的 series 按窗口 L 切成 L 行、K=N-L+1 列的矩阵 X,每个元素 X[i,j] 直接取 series[i+j],相当于把原序列的所有长度为 L 的片段竖着排开。

MQL5 / C++
class=class="str">"cmt">//| Trajectory matrix X                                                                              |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void trajectory_matrix(vector & series,class="type">int window_length, matrix & X)
  {
   class="type">int N_ = (class="type">int)series.Size();
   class="type">int L_ = window_length;
   class="type">int K = N_ - L_ + class="num">1;
   X=matrix::Zeros(L_,K);
   for(class="type">int i=class="num">0; i <L_;  i++)
     {
      for(class="type">int j=class="num">0; j <K;  j++)
        {
         X[i,j] = series[i+j];
        }
     }
  }
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//|Finds the rank of a matrix class="kw">using SVD                                                              |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">int Rank_SVD(matrix & X)
  {
   vector sv;
   matrix U,V;
   class="type">class="kw">double tol = class="num">1e-8;   class=class="str">"cmt">// Threshold for non-zero values
   X.SingularValueDecompositionDC(SVDZ_N,sv,U,V);
   class="type">class="kw">double threshold = tol * sv.Max();
   class="type">int rank=class="num">0;
   for(class="type">int i=class="num">0; i<(class="type">int)sv.Size(); i++)
     {
      if(sv[i] > threshold)
        rank++;
     }
   class="kw">return rank;
  }
class=class="str">"cmt">//+------------------------------------------------------------------+
trajectory_matrix 逐行看:先拿序列总长 N_ 和窗口 L_,算出片段数 K;用 matrix::Zeros 建好空矩阵,双层循环里 i 管行(窗口内偏移)、j 管列(片段起点),X[i,j]=series[i+j] 就是把第 j 个片段的第 i 个值填进去。 Rank_SVD 靠奇异值分解判秩。容差 tol 设 1e-8,阈值取 tol 乘奇异值最大值,大于它的才算有效维度。外汇和贵金属波动里噪声多,有效秩往往远小于 L,调小 tol 可能多捡回几个弱分量,但也可能把噪声当信号——MT5 里跑一遍看 sv 数组分布最直观。

MQL5 / C++
class=class="str">"cmt">//| Trajectory matrix X                                                                              |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void trajectory_matrix(vector & series,class="type">int window_length, matrix & X)
  {
   class="type">int N_ = (class="type">int)series.Size();
   class="type">int L_ = window_length;
   class="type">int K = N_ - L_ + class="num">1;
   X=matrix::Zeros(L_,K);
   for(class="type">int i=class="num">0; i <L_;  i++)
     {
      for(class="type">int j=class="num">0; j <K;  j++)
        {
         X[i,j] = series[i+j];
        }
     }
  }
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//|Finds the rank of a matrix class="kw">using SVD                                                              |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">int Rank_SVD(matrix & X)
  {
   vector sv;
   matrix U,V;
   class="type">class="kw">double tol = class="num">1e-8;   class=class="str">"cmt">// Threshold for non-zero values
   X.SingularValueDecompositionDC(SVDZ_N,sv,U,V);
   class="type">class="kw">double threshold = tol * sv.Max();
   class="type">int rank=class="num">0;
   for(class="type">int i=class="num">0; i<(class="type">int)sv.Size(); i++)
     {
      if(sv[i] > threshold)
        rank++;
     }
   class="kw">return rank;
  }
class=class="str">"cmt">//+------------------------------------------------------------------+

用奇异向量形态切分时序成分

分组阶段要把秩为1的基矩阵归到互不相交的集合里,每个集合对应一类时序成分:趋势、季节或噪声。最实用的判据是看轨迹矩阵 X 的奇异值是否接近——相近的归一组,因为同源成分在能量谱上会聚堆。 具体拆分时常见做法是:I_trend 单独吃掉最大那根奇异值;I_seasonal 取 {2,3} 这种成对索引(周期信号秩恒为2);I_noise 收编从4到 i 的剩余项,i 等于总奇异值数。这样 X 就被显式拆成趋势+季节+噪声的并。 肉眼看左奇异向量比数特征根更快。趋势项画出来是平滑单调轨迹;周期项必出成对正弦状向量;和理想高斯白噪声长得很像、且挂在很小奇异值上的,就是噪声。MT5 里把 SSA 的 U_i 向量导出来画线,基本一眼能定分组,不用死磕阈值。 这种视觉分组对外汇小时线尤其敏感:贵金属夜盘常冒出伪周期,单看数值易误归趋势,描一遍向量形态就能避开。

把矩阵分解交给小布盯盘
这些诊断小布盯盘的 AIGC 已内置,打开对应品种页即可看到轨迹矩阵重构的趋势与噪声分量,你只需判断哪段权重值得信。

常见问题

它基于轨迹矩阵和奇异值分解,直接在多维空间反映连续值依赖,不依赖均值方差恒定的前提,对非平稳金融序列更通用。
L 决定分析深度与可提取成分的分辨率,取 N/2 是经验折中,兼顾矩阵秩上限与样本信息保留,过短会丢结构过长易过拟合。
说明它由两个线性无关向量张成,满足二阶线性递推,对应 SVD 里两个显著奇异值,可归为同一周期组重建。
可以,品种页内置 AIGC 诊断,自动出轨迹矩阵重构分量和权重,省去自己写 MQL5 矩阵代码,但解读仍由你做。
它们是轨迹矩阵经 SVD 拆出的基础模块,每个对应一个特征三元组,按奇异值大小排,大权重的是信号小的是噪声。