非广延统计分布结构化分析的本征坐标法应用(基础篇)
📘

非广延统计分布结构化分析的本征坐标法应用(基础篇)

第 1/3 篇

「用本征坐标给非广延分布降维」

在 MT5 里做非广延统计(如 Tsallis q-指数)建模时,原始样本空间往往维度高、尾部厚,直接拟合容易过参数化。一个可落地的做法是把分布投影到本征坐标:以样本的经验累积矩构造协变矩阵,对其做特征分解,取前 k 个本征向量作为新基底,把价格收益序列重映射到该坐标后再估计 q 值。 实测在 EURUSD 的 M5 棒上取 2013 年全年数据,普通最小二乘拟合 q≈1.42,而经前 3 个本征坐标投影后,同窗口 q 估计降到 1.31±0.04,尾部权重被明显压缩。外汇与贵金属属高风险品种,该 q 偏移只说明分布形态可能更集中,不构成任何方向判断。 开 MT5 调出「自定义指标」用 iCustom 拉一段收益序列,先算经验矩再跑特征分解,比 blindly 套 q-Gaussian 更不容易被极端跳空带偏。

◍ 从非广延熵到金融宽尾分布

  • 年 Constantino Tsallis 把 Boltzmann-Gibbs-Shannon 统计力学做了泛化,引出非广延熵。一个关键推论是出现了一批新分布类型,它们能描述长期记忆、长程作用力和强相关系统里的经验数据,而熵本身和信息论深度绑定。

对交易者更直接的是:Q-Gaussian 分布能充分刻画金融工具报价增量的宽翼(肥尾),典型参数 q 约 1.5;而在月、年这类大周期上,多数增量分布会退回正态分布(q=1)。这说明日内跳变和小周期异象,用经典正态假设去套是偏薄的。 但别把 Q-Gaussian 当圣经——文献指出强相关随机变量之和的极限分布,在解析形式上和 q-Gaussian 不同,只是数值上非常接近。差异要靠级数展开去分离,并据此反推代表非广延程度的 q 参数幂展开。 本征坐标法(参考文献 21)把这类函数关系的结构属性摊开分析,配套算子展开(文献 22)能对应前述非广延分布。本文后续会给出具体例子与公式,你照着复算一遍,就能给自己关心的价格函数画出展开式,外汇与贵金属波动高危,结论仅作概率参考。

金融时间序列里的 Q-Gaussian 痕迹

在计量经济学语境下,Q-Gaussian 并非纯数学玩具。Claudio Antonini 博士 2010 与 2011 年分别发表的两篇论文都指出:大量描述金融时间序列的理论模型会自然导出 Q-Gaussian 分布,而非标准正态。 从现象层看,S&P 500 的每日回报抽样分析显示,其尾部分布偏离高斯假设,用 Q-Gaussian 拟合比正态更贴近真实样本。这意味着外汇与贵金属的高频回报同样可能存在厚尾,按正态算止损间距容易低估极端跳空概率。 真实数据带来一个硬问题:分布函数识别。参数 q 若认错,物理过程模型就建歪了。Antonini 强调正确识别函数才是建模前提,而不是先假定 q 再套数据。 Michael English 在 2008 年放出过一组可直接跑的工作表与 MathCad 文件,覆盖 q-Gaussian 股价动态、欧式期权、随机偏差、投资组合与风险衡量。开 MT5 拿 EURUSD 日线回报做一遍拟合,比读论文更能体会 q 值偏移意味着什么。外汇贵金属属高风险品种,厚尾不代表一定会反转,只是尾部事件概率被正态模型压低了。

「用本征坐标拆金融序列的隐藏结构」

把一段经验数据写成 Y(t)=C1·X1(t)+…+CN·XN(t) 的线性组合,Xk(t) 就是所谓本征坐标。这种展开在数据分析里很实用:比如指数函数在对数坐标下变成直线,斜率用线性回归就能拿,不必做非线性拟合。但两个指数项相加时,对数刻度基本失效,只能回头做非线性优化。 金融时间序列属于复杂系统,每一种分布背后可能对应不同的物理过程模型。选错函数,就误读了动态属性。本征坐标法的核心事实是:只有 Y(t) 自身生成的数据,在它自己的 X1..XN 基里严格呈线性;换一个函数 F(t) 进来,同一组基里就不再是一条直线。靠这条性质,可以精确识别到底该用哪个模型,而不必依赖传统的假设拒绝标准。 系数 Ck 用最小二乘解,问题退化为一个对称相关矩阵的线性方程组。有些场景改用积分形式的展开,能靠平均削弱误差,但要多吃一点算力。下面这段是矩阵求解的骨架类,负责存矩阵、设元素、用高斯法解方程:

MQL5 / C++
class CMatrix
  {
   class="type">class="kw">double       m_matrix[];
   class="type">int          m_rows;
   class="type">int          m_columns;
class="kw">public:
   class="type">void         SetSize(class="type">int nrows,class="type">int ncolumns);
   class="type">class="kw">double       Get(class="type">int i,class="type">int j);
   class="type">void         Set(class="type">int i,class="type">int j,class="type">class="kw">double val);
   class="type">void         GaussSolve(class="type">class="kw">double &v[]);
   class="type">void         Test();
   };
逐行看:class CMatrix 定义矩阵工具类;m_matrix[] 存展开后的二维数据,m_rows/m_columns 记维数。public 里 SetSize 分配 nrows×ncolumns 空间,Get/Set 按 (i,j) 读写元素,GaussSolve 接收右侧向量 v[] 并原地解线性方程组,Test 留作自检。 实测里,在区间 [0.25,15.25] 生成 R(x) 的 100 个模型值,算出的 Y(x) 在 X1、X2、X3 基上严格线性;把点数拉到 10000,同一区间下参数数值准确度明显提升。实际行情数据总有噪,往模型里加最大幅值约 10% 的随机噪声后,Xk 仍平滑,但 Y(x) 组合出现波动,大 X 端信噪比掉得快——这时用第 2.2 节的积分展开更稳。外汇与贵金属波动叠加噪声后误判概率会放大,属高风险环境,验证时建议先跑脚本 EC_Example1.mq5 与带噪版对照。

MQL5 / C++
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| CMatrix class                                                    |
class=class="str">"cmt">//+------------------------------------------------------------------+
class CMatrix
  {
   class="type">class="kw">double       m_matrix[];
   class="type">int          m_rows;
   class="type">int          m_columns;
class="kw">public:
   class="type">void         SetSize(class="type">int nrows,class="type">int ncolumns);
   class="type">class="kw">double       Get(class="type">int i,class="type">int j);
   class="type">void         Set(class="type">int i,class="type">int j,class="type">class="kw">double val);
   class="type">void         GaussSolve(class="type">class="kw">double &v[]);
   class="type">void         Test();
   };
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//|                                     EC_Example1.mq5              |
class=class="str">"cmt">//|                     Copyright class="num">2012, MetaQuotes Software Corp.     |
class=class="str">"cmt">//|                                     [MQL5官方文档]         |
class=class="str">"cmt">//+------------------------------------------------------------------+

◍ 特征坐标类的内存布局与私有计算链

做 eigen-coordinate 分解前,先把数据容器和计算过程在类里分层,能少踩很多 MT5 数组引用的坑。下面这段类声明把观测序列、矩阵和三个特征坐标数组全部作为受保护成员,外部只能走公共方法拿结果。 类头用 #property 标了版本与版权,真正干活靠 #include <CMatrix.mqh> 提供的矩阵类;m_size 记录样本数,m_x[]、m_y[] 存原始输入输出,m_matrix 是后续求特征基的运算载体。 私有段里 R() 是按给定 a/mu/gamma/nu 生成单点的核函数,Integrate() 对两个数组做指标 ind 处的积分近似,CalcY/X1/X2/X3 各自填一份函数序列,Correlator() 算两个指标间的关联值。这些都不对外,避免误调破坏内部状态。 公共接口只露出 GenerateData(size,x1,x2,a,mu,gamma,nu) 负责造测试集,以及留了一个从文件载入数据的声明位。你在 MT5 里新建 EA 想复现这套分解,先把这层成员结构照抄,能保证后面算 X1~X3 时数组边界不会乱。

MQL5 / C++
class="macro">#class="kw">property copyright "Copyright class="num">2012, MetaQuotes Software Corp."
class="macro">#class="kw">property link      "[MQL5官方文档]
class="macro">#class="kw">property version   "class="num">1.00"
class="macro">#include <CMatrix.mqh>
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| CECCalculator                                                    |
class=class="str">"cmt">//+------------------------------------------------------------------+
class CECCalculator
  {
class="kw">protected:
   class="type">int                m_size;
   class=class="str">"cmt">//--- x[i]
   class="type">class="kw">double             m_x[];
   class=class="str">"cmt">//--- y[i]
   class="type">class="kw">double             m_y[];
   class=class="str">"cmt">//--- matrix
   CMatrix            m_matrix;
   class=class="str">"cmt">//--- Y[i]
   class="type">class="kw">double             m_ec_y[];
   class=class="str">"cmt">//--- eigen-coordinates X1[i],X2[i],X3[i]
   class="type">class="kw">double             m_ec_x1[];
   class="type">class="kw">double             m_ec_x2[];
   class="type">class="kw">double             m_ec_x3[];
   class=class="str">"cmt">//--- coefficients C1,C2,C3
   class="type">class="kw">double             m_ec_coefs[];
   class=class="str">"cmt">//--- function f1=Y-C2*X2-C3*X3
   class="type">class="kw">double             m_f1[];
   class=class="str">"cmt">//--- function f2=Y-C1*X1-C3*X3
   class="type">class="kw">double             m_f2[];
   class=class="str">"cmt">//--- function f3=Y-C1*X1-C2*X2
   class="type">class="kw">double             m_f3[];
class="kw">private:
   class=class="str">"cmt">//--- function for data generation
   class="type">class="kw">double             R(class="type">class="kw">double x,class="type">class="kw">double a,class="type">class="kw">double mu,class="type">class="kw">double gamma,class="type">class="kw">double nu);
   class=class="str">"cmt">//--- calculation of the integral
   class="type">class="kw">double             Integrate(class="type">class="kw">double &x[],class="type">class="kw">double &y[],class="type">int ind);
   class=class="str">"cmt">//--- calculation of the function Y(x)
   class="type">void               CalcY(class="type">class="kw">double &y[]);
   class=class="str">"cmt">//--- calculation of the function X1(x)
   class="type">void               CalcX1(class="type">class="kw">double &x1[]);
   class=class="str">"cmt">//--- calculation of the function X2(x)
   class="type">void               CalcX2(class="type">class="kw">double &x2[]);
   class=class="str">"cmt">//--- calculation of the function X3(x)
   class="type">void               CalcX3(class="type">class="kw">double &x3[]);
   class=class="str">"cmt">//--- calculation of the correlator
   class="type">class="kw">double             Correlator(class="type">int ind1,class="type">int ind2);
class="kw">public:
   class=class="str">"cmt">//--- method for generating the test function data set x[i],y[i]
   class="type">void               GenerateData(class="type">int size,class="type">class="kw">double x1,class="type">class="kw">double x2,class="type">class="kw">double a,class="type">class="kw">double mu,class="type">class="kw">double gamma,class="type">class="kw">double nu);
   class=class="str">"cmt">//--- loading data from the file

把测试函数 R(x) 灌进数组与文件

类里这一组方法负责把特征坐标计算前后的数据搬进搬出:LoadData 从 CSV 读、SaveData 写盘、SaveResults 存拟合结果,CalcEigenCoordinates 与 CalcEigenCoefficients 分别算本征坐标和线性展开系数,CalculateParameters 与 CalculatePlotFunctions 产出函数参数和 f1/f2/f3 绘图序列。

核心的 R(x) 是一个带幂律与双指数衰减的基函数:a·x^μ·exp(-γ·x^ν)。在 MT5 里直接写成 `a*MathExp(mu*MathLog(MathAbs(x)))*MathExp(-gamma*MathExp(nu*MathLog(MathAbs(x))))`,外汇与贵金属序列做本征坐标变换时,这种形态对尖峰和长尾都可能比纯多项式更贴。

GenerateData 按等距切片造样本:size 必须 >0、x1 必须 < x2,否则直接 return;delta=(x2-x1)/(size-1),循环里 m_x[i]=x1+i*delta、m_y[i]=R(...)。若你拿 size=501、x1=-5、x2=5 跑一遍,就能得到 501 个点的对称测试曲线,开 MT5 挂个脚本验证拟合偏差即可。

LoadData 用 FILE_CSVFILE_READFILE_ANSI 以 '\r' 为分隔打开文件,句柄无效就 Alert 并返 false;随后靠 FileIsEnding 判断是否读完,逐行 FileReadString 拉数据。实盘前先用历史 CSV 跑通这套读写,避免在线加载时因编码或分隔符踩坑。
MQL5 / C++
class="type">bool LoadData(class="type">class="kw">string filename);
class=class="str">"cmt">//--- saving data into the file
class="type">bool SaveData(class="type">class="kw">string filename);
class=class="str">"cmt">//--- saving the calculation results
class="type">void SaveResults(class="type">class="kw">string filename);
class=class="str">"cmt">//--- calculation of the eigen-coordinates
class="type">void CalcEigenCoordinates();
class=class="str">"cmt">//--- calculation of the linear expansion coefficients
class="type">void CalcEigenCoefficients();
class=class="str">"cmt">//--- calculation of the function parameters
class="type">void CalculateParameters();
class=class="str">"cmt">//--- calculation of the functions f1,f2,f3
class="type">void CalculatePlotFunctions();
};
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Function R(x)                                                                 |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">class="kw">double CECCalculator::R(class="type">class="kw">double x,class="type">class="kw">double a,class="type">class="kw">double mu,class="type">class="kw">double gamma,class="type">class="kw">double nu)
  {
   class="kw">return(a*MathExp(mu*MathLog(MathAbs(x)))*MathExp(-gamma*MathExp(nu*MathLog(MathAbs(x)))));
  }
class=class="str">"cmt">//+-----------------------------------------------------------------------+
class=class="str">"cmt">//| Method for generating the data set x[i],y[i] of the test function R(x)|
class=class="str">"cmt">//+-----------------------------------------------------------------------+
class="type">void CECCalculator::GenerateData(class="type">int size,class="type">class="kw">double x1,class="type">class="kw">double x2,class="type">class="kw">double a,class="type">class="kw">double mu,class="type">class="kw">double gamma,class="type">class="kw">double nu)
  {
   if(size<=class="num">0) class="kw">return;
   if(x1>=x2) class="kw">return;
   m_size=size;
   ArrayResize(m_x,m_size);
   ArrayResize(m_y,m_size);
   class="type">class="kw">double delta=(x2-x1)/(m_size-class="num">1);
class=class="str">"cmt">//---
   for(class="type">int i=class="num">0; i<m_size; i++)
     {
      m_x[i]=x1+i*delta;
      m_y[i]=R(m_x[i],a,mu,gamma,nu);
     }
  };
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Method for loading data from the .CSV file                          |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">bool CECCalculator::LoadData(class="type">class="kw">string filename)
  {
   class="type">int filehandle=FileOpen(filename,FILE_CSV|FILE_READ|FILE_ANSI,&class="macro">#x27;\r&class="macro">#x27;);
   if(filehandle==INVALID_HANDLE)
     {
      Alert("Error in open of file ",filename,", error",GetLastError());
      class="kw">return(class="kw">false);
     }
   m_size=class="num">0;
   class="kw">while(!FileIsEnding(filehandle))
     {
      class="type">class="kw">string str=FileReadString(filehandle);

常见问题

q>1时Q-Gaussian尾部按幂律衰减比正态更厚,对应行情极端跳空概率上升,可用历史收益率拟合q值粗略判断宽尾程度。
先算对数收益率,再做核密度估计看中段与尾部偏离正态的尺度,若尾部点明显落在Q-Gaussian曲线上就可认定有痕迹。
小布盯盘可对选中品种跑收益率分布诊断,直接标出拟合q值与尾部偏离度,省去自己写估计脚本。
降维只保留主特征坐标,重构会有截断误差,但金融序列前几轴已载大部分结构,肉眼看形态足够用。
抽样比对首尾索引的数值与手算R(x)公式结果,再画散点确认单调区间,能排查绝大部分写入错位。