MQL5 中的统计分布 - 充分利用 R 并使其更快·进阶篇
📊

MQL5 中的统计分布 - 充分利用 R 并使其更快·进阶篇

(2/3)· 从均值方差到正态对数正态β分布,MQL5 标准库已内置 R 函数且修正了原版错误

案例拆解新手友好 第 2/3 篇

接上篇对统计基础的铺垫,这一篇直接扎进 MQL5 标准库里的分布函数实装。很多人还在自己手搓正态分布累积概率,其实 MathCumulativeDistributionNormal 早就补进了库里,而且比 R 原版快了数倍。

MT5数学库里的厚尾与对称分布族

在 MT5 的标准数学库里,学生 t、非中心 t、逻辑斯谛、柯西、均匀、威布尔这几类分布各自配齐了密度、累积、分位、随机与矩计算五组函数。单值版本出错返 NaN,数组版本出错返 false,命名规则直接对齐 R 语言的 d / p / q / r 前缀,方便从量化脚本迁移。 非中心 t 分布比普通 t 多一个偏移参数 delta,分位函数 MathQuantileNoncentralT 在数组版本里原文标注用 sigma 而非 delta,这属于文档笔误,实际调用仍应以 delta 为非中心参数。外汇与贵金属波动建模中,非中心 t 可能对跳空后的收益率尾部有更贴合的刻画,但杠杆品种高风险,参数错配会直接让函数返 false。 柯西分布没有有限方差,MathMomentsCauchy 虽返回前 4 矩理论值,但二阶以上实际无意义,回测时别拿它的标准差当止损依据。均匀分布 MathRandomUniform 的伪随机常用于蒙特卡洛重采样,a、b 区间若设成 [0,1] 就等价于基础噪声源。 打开 MT5 的 MQL5/Include/Math/Stat 目录,搜 MathProbabilityDensityWeibull 就能看到双参数 a、b 的默认实现,把 b 从 1 改成 1.5 跑一遍随机序列,能直观看到分布峰度的收紧倾向。

◍ 离散分布函数族在 MT5 里的直接映射

MT5 标准库把一批离散概率分布封装成了 Math* 系列函数,覆盖二项、负二项、几何、超几何与泊松五类。每一类都按密度、累积、分位、随机、矩五个维度拆出独立接口,数组版本与单值版本的出错返回不同:单值算错返 NaN,数组版算错返 false。 以二项分布为例,MathProbabilityDensityBinomial 对应 R 的 dbinom(),MathCumulativeDistributionBinomial 对应 pbinom(),分位和随机则分别映射 qbinom() 与 rbinom()。负二项、几何、超几何、泊松的同构关系完全一致,只是参数从 (n,p) 换成 (r,p)、(m,k,n) 或 lambda。 做价格行为统计时,这类函数能直接算「N 根 K 线里出现 M 次突破」的概率规模。比如用 MathProbabilityDensityBinomial 代入 n=20、p=0.3,可得到某 20 根窗口内恰有若干根收在布林带外的密度值,用来评估样本是否偏离随机。 泊松族在刻画「单位时间跳空次数」时更顺手:lambda=1.5 下 MathCumulativeDistributionPoisson 能给出单根 H1 内跳空数 ≤3 的累积概率约 0.934。外汇与贵金属波动聚集明显,这类理论值仅作分布参照,实盘仍属高风险环境,勿当胜率保证。

「正态密度与累积分布的函数重载」

MT5 内置了两族正态分布相关函数,分别处理概率密度(PDF)和累积分布(CDF),且都做了单值与数组两种入参的重载。做价格分布建模时,先分清你要算的是某点的密度还是某区间的累计概率,再选对应签名,能省掉自己写循环的开销。 MathProbabilityDensityNormal 有四种形态:单值返回 double、单值带 log_mode 与 error_code、数组入参返回 bool 并填充 result[]、数组入参带 log_mode。log_mode 置 true 时返回的是自然对数,适合后续做对数似然相加,避免小概率连乘下溢。 MathCumulativeDistributionNormal 的 tail 参数决定方向——true 时算的是不超过 x 的概率(左尾累计),配合 log_mode 可拿对数累计值。外汇与贵金属波动聚类明显,正态假设在极端行情会偏薄尾,用这些函数做止损区间概率估算时须意识到高风险,结果仅作参考而非确定边界。 直接把下面签名贴进 MT5 的 MQ5 文件就能看到编译器识别情况,改 mu、sigma 跑几个 x 值对照手册表验证:

MQL5 / C++
class="type">class="kw">double MathProbabilityDensityNormal(
  const class="type">class="kw">double   x,
  const class="type">class="kw">double   mu,
  const class="type">class="kw">double   sigma,
  const class="type">bool     log_mode,
  class="type">int&           error_code
);
class="type">class="kw">double MathProbabilityDensityNormal(
  const class="type">class="kw">double   x,
  const class="type">class="kw">double   mu,
  const class="type">class="kw">double   sigma,
  class="type">int&           error_code
);
class="type">bool MathProbabilityDensityNormal(
  const class="type">class="kw">double   &x[],
  const class="type">class="kw">double   mu,
  const class="type">class="kw">double   sigma,
  const class="type">bool     log_mode,
  class="type">class="kw">double         &result[]
);
class="type">bool MathProbabilityDensityNormal(
  const class="type">class="kw">double   &x[],
  const class="type">class="kw">double   mu,
  const class="type">class="kw">double   sigma,
  class="type">class="kw">double         &result[]
);
class="type">class="kw">double MathCumulativeDistributionNormal(
  const class="type">class="kw">double   x,
  const class="type">class="kw">double   mu,
  const class="type">class="kw">double   sigma,
  const class="type">bool     tail,
  const class="type">bool     log_mode,
  class="type">int&           error_code
);
class="type">class="kw">double MathCumulativeDistributionNormal(
  const class="type">class="kw">double   x,
  const class="type">class="kw">double   mu,
  const class="type">class="kw">double   sigma
);

正态分布的累积与分位函数怎么调

在 MT5 里做价格分布假设检验,绕不开正态分布的累积分布(CDF)和分位数(quantile)两组函数。它们能直接把一段收益率序列映射成概率,或者反过来按置信度取出临界值。 MathCumulativeDistributionNormal 有三种重载:数组版带 tail 和 log_mode 开关,tail=true 时算的是「不超过 x 的概率」,log_mode=true 则返回自然对数,方便做极大似然类的连乘避免溢出;不带 log_mode 的简化版默认走线性概率。 分位数侧用 MathQuantileNormal,单值版接受 probability、mu、sigma,tail=false 会先算 1.0-概率再取分位,log_mode=true 时输入先过 Exp()。数组版则批量吐出分位点,适合一次性标出 5%、50%、95% 三档波动边界。外汇与贵金属杠杆高,分布尾部往往厚于正态,用这套算出的边界仅作参考,实盘破界概率可能偏高。 下面拆一下带完整参数的两个声明,看清每个入参的坑:

MQL5 / C++
class="type">bool MathCumulativeDistributionNormal(
  const class="type">class="kw">double &x[],      class=class="str">"cmt">// [输入] 随机变量值的数组
  const class="type">class="kw">double  mu,       class=class="str">"cmt">// [输入] 期望值
  const class="type">class="kw">double  sigma,    class=class="str">"cmt">// [输入] 均方根偏离
  const class="type">bool   tail,      class=class="str">"cmt">// [输入] 计算标志, 如果 true, 则计算不超过随机变量 x 的概率
  const class="type">bool   log_mode,  class=class="str">"cmt">// [输入] 计算数值对数的标志, 如果 log_mode=true, 则计算概率的自然对数
  class="type">class="kw">double       &result[]  class=class="str">"cmt">// [输出] 概率函数密度值的数组
);
class="type">class="kw">double MathQuantileNormal(
  const class="type">class="kw">double  probability, class=class="str">"cmt">// [输入] 随机变量概率值
  const class="type">class="kw">double  mu,          class=class="str">"cmt">// [输入] 期望值
  const class="type">class="kw">double  sigma,       class=class="str">"cmt">// [输入] 均方根偏离
  const class="type">bool   tail,         class=class="str">"cmt">// [输入] 计算标志, 如果 false, 则执行 class="num">1.0-概率的计算
  const class="type">bool   log_mode,     class=class="str">"cmt">// [输入] 计算标志, 如果 log_mode=true, 执行 Exp(probability) 计算
  class="type">int          &error_code   class=class="str">"cmt">// [输出] 错误代码变量
);

◍ 正态与对数正态的统计函数接口

在 MT5 的 Math/Stat 模块里,正态分布相关函数分成两类:一类做分位、密度与矩的解析计算,另一类负责按指定 mu、sigma 生成伪随机序列。下面这组声明直接对应标准库头文件,复制进 MQ5 即可调用。 MathQuantileNormal 接收 probability[] 数组与 mu、sigma,把分位数写回 result[];若省略 tail 与 log_mode 的重载版本,默认按左尾计算,不取对数。 MathRandomNormal 有两个重载:单值版本返回 double 并通过 error_code 报状态;数组版本靠 data_count 一次性塞满 result[],适合做蒙特卡洛式的价差分布模拟。 MathMomentsNormal 一口气输出均值、方差、偏度、峰度四个矩,外汇小时线收益率在 mu=0、sigma=0.0008 附近时,样本偏度常落在 -0.3~0.5,峰度可能高于 3,提示厚尾,别把正态当圣经。 MathProbabilityDensityLognormal 的 x 必须为正数,mu 与 sigma 是 ln(x) 的均值与标准差;log_mode=true 时直接回自然对数,省去后续 Exp 步骤,做似然计算更稳。

MQL5 / C++
const class="type">bool    tail,        class=class="str">"cmt">// [输入] 计算标志, 如果 false, 则执行 class="num">1.0-概率的计算
const class="type">bool    log_mode,    class=class="str">"cmt">// [输入] 计算标志, 如果 log_mode=true, 执行 Exp(probability) 计算
class="type">class="kw">double        &result[]    class=class="str">"cmt">// [输出] 具有分位数值的数组
);
class="type">bool MathQuantileNormal(
  const class="type">class="kw">double &probability[], class=class="str">"cmt">// [输入] 随机变量概率值数组
  const class="type">class="kw">double mu,             class=class="str">"cmt">// [输入] 期望值
  const class="type">class="kw">double sigma,          class=class="str">"cmt">// [输入] 均方根偏离
  class="type">class="kw">double       &result[]       class=class="str">"cmt">// [输出] 具有分位数值的数组
);
class="type">class="kw">double MathRandomNormal(
  const class="type">class="kw">double mu,             class=class="str">"cmt">// [输入] 期望值
  const class="type">class="kw">double sigma,          class=class="str">"cmt">// [输入] 均方根偏离
  class="type">int          &error_code     class=class="str">"cmt">// [输出] 错误代码变量
);
class="type">bool MathRandomNormal(
  const class="type">class="kw">double mu,             class=class="str">"cmt">// [输入] 期望值
  const class="type">class="kw">double sigma,          class=class="str">"cmt">// [输入] 均方根偏离
  const class="type">int    data_count,     class=class="str">"cmt">// [输入] 所需数据数量
  class="type">class="kw">double       &result[]       class=class="str">"cmt">// [输出] 伪随机变量值数组
);
class="type">bool MathMomentsNormal(
  const class="type">class="kw">double mu,             class=class="str">"cmt">// [输入] 期望值
  const class="type">class="kw">double sigma,          class=class="str">"cmt">// [输入] 均方根偏离
  class="type">class="kw">double       &mean,          class=class="str">"cmt">// [输出] 均值变量 (第一力矩)
  class="type">class="kw">double       &variance,      class=class="str">"cmt">// [输出] 方差变量 (第二力矩)
  class="type">class="kw">double       &skewness,      class=class="str">"cmt">// [输出] 偏度变量 (第三力矩)
  class="type">class="kw">double       &kurtosis,      class=class="str">"cmt">// [输出] 峰度变量 (第四力矩)
  class="type">int          &error_code     class=class="str">"cmt">// [输出] 错误代码变量
);
class="type">class="kw">double MathProbabilityDensityLognormal(
  const class="type">class="kw">double x,              class=class="str">"cmt">// [输入] 随机变量值
  const class="type">class="kw">double mu,             class=class="str">"cmt">// [输入] 期望值的对数 (对数均值)
  const class="type">class="kw">double sigma,          class=class="str">"cmt">// [输入] 均方根偏离的对数 (对数标准偏离)
  const class="type">bool   log_mode       class=class="str">"cmt">// [输入] 计算对数值的标志, 如果 log_mode = true, 则返回概率密度的自然对数
);

「对数正态函数的四种重载怎么调」

MT5 里对数正态相关的数学接口给了四组重载,分别覆盖单值密度、数组密度、累计分布单值三种需求。做品种波动建模时,若直接用单值版本逐根 K 线算,CPU 占用会明显高于数组版本。 double MathProbabilityDensityLognormal(const double x, const double mu, const double sigma, int& error_code) 返回某一点 x 的概率密度;mu 是对数均值,sigma 是对数标准差,error_code 向外传递执行状态。 数组版本多了 log_mode 与 result[] 两个参数:log_mode=true 时直接吐出概率密度的自然对数,适合后续做似然累加;result[] 长度需与 x[] 一致,否则函数返回 false。 累计分布 MathCumulativeDistributionLognormal 带 tail 与 log_mode:tail=true 算不超过 x 的概率,log_mode=true 返回对数。外汇与贵金属杠杆高,用这些分布估尾部风险时仅作概率参考,实盘仍可能突破历史分位。 开 MT5 把下面代码贴进脚本,改 mu=0、sigma=0.5 跑一遍,看 x=1.0 时密度与累计值是否分别为约 0.627 和 0.758,能立刻验证接口行为。

MQL5 / C++
class="type">class="kw">double MathProbabilityDensityLognormal(
  const class="type">class="kw">double x,
  const class="type">class="kw">double mu,
  const class="type">class="kw">double sigma,
  class="type">int& error_code
);
class="type">class="kw">double MathProbabilityDensityLognormal(
  const class="type">class="kw">double x,
  const class="type">class="kw">double mu,
  const class="type">class="kw">double sigma,
  class="type">int& error_code
);
class="type">bool MathProbabilityDensityLognormal(
  const class="type">class="kw">double &x[],
  const class="type">class="kw">double mu,
  const class="type">class="kw">double sigma,
  const class="type">bool log_mode,
  class="type">class="kw">double &result[]
);
class="type">bool MathProbabilityDensityLognormal(
  const class="type">class="kw">double &x[],
  const class="type">class="kw">double mu,
  const class="type">class="kw">double sigma,
  class="type">class="kw">double &result[]
);
class="type">class="kw">double MathCumulativeDistributionLognormal(
  const class="type">class="kw">double x,
  const class="type">class="kw">double mu,
  const class="type">class="kw">double sigma,
  const class="type">bool tail,
  const class="type">bool log_mode,
  class="type">int& error_code
);
class="type">class="kw">double MathCumulativeDistributionLognormal(
  const class="type">class="kw">double x,
  const class="type">class="kw">double mu,
  const class="type">class="kw">double sigma,
  const class="type">bool tail,
  const class="type">bool log_mode,
  class="type">int& error_code
);
把分布诊断交给小布
这些分布函数的调用与品种收益拟合,小布盯盘的 AIGC 已内置常用诊断模板,打开对应品种页就能直接看偏度峰度是否异于正态假设,你只管判断行情结构。

常见问题

前者返回方差即标准差的平方,后者直接返回标准差;两者都基于样本矩计算,调用前需确保数组已去空值。
可以,小布盯盘内置了基于 MQL5 统计库的品种诊断,能自动输出正态性偏离与矩估计,省去手写 EA 的重复劳动。
标准库针对 MetaTrader 5 的数组结构与编译做了重写,并修正了 R 某些函数的边界实现错误,所以同逻辑下吞吐更高。
价格类数据因非负且右偏,用对数正态拟合比正态更合理,常用于止损间距与波动幅度的概率估计,结果仅作概率参考。
多了一个非中心参数,能表达更偏的Shape,适合做非对称胜率区间建模,但参数估计更容易过拟合,实盘需谨慎。