种群优化算法:改变概率分布的形状和位移,并基于智能头足类生物(SC)进行测试(基础篇)
📘

种群优化算法:改变概率分布的形状和位移,并基于智能头足类生物(SC)进行测试(基础篇)

第 1/2 篇

用头足类智能重写分布形态

种群优化思路在 MT5 里能直接改掉随机数生成器的脾气:不是只调均值,而是连概率分布的形状和整体位移一起动。原文用一类叫“智能头足类生物(SC)”的算法做验证,本质是把采样分布当成可优化变量,而不是固定正态假设。 想动手的话,在 MT5 里开一个 EA 测试台,把标准正态采样换成自定义分布类,再挂 SC 优化器跑参数。原文给出的示例发布于 2024-08-21,社区数据是该帖获 559 次浏览、17 条评论,说明这类非主流分布改造在实盘圈并非冷门玩具。 外汇与贵金属品种叠加这种分布重写后,信号触发频率会明显偏移,属于高风险实验,建议先用历史数据回放验证分布位移是否带来样本外退化。

「随机性与优化为何要绑在一起谈」

概率论处理的是随机现象的或然率,几个基础件必须厘清:概率是事件发生的数值特征;随机变量把实验结果映射成数字;概率分布给出每个可能值的发生概率;数学期望是多次重复后的均值;散布衡量数值相对均值的扩散程度。再往上,矩这套工具把分布形状也量化了——一阶矩是期望中心,二阶矩是散布,三阶看偏度,四阶看峰度凸性。 把这些搬到交易和算法里,意义不在公式本身,而在于现实问题天然带噪声。优化算法想在大量可能解里挑最优,却绕不开不确定性和随机性;概率分布就是让搜索过程能显式参考随机性的桥梁。进化类、种群类算法里,新状态的随机生成直接由对应分布建模,才能在参数空间里又探索又保持多样性。 更复杂一点的优化方法,会用分布去近似复杂函数、对不确定性建模,在带噪声的数据里找解。本文后面要落地的,正是各类分布在代码里的实现,以及生成随机数时的坑:比如无限尾部长度、设定散布边界时的概率偏移。目标很直接——写出能调期望、能控散布的实用函数,供后续优化算法直接调用。外汇与贵金属市场波动剧烈、杠杆风险高,这类随机建模仅作方法参考,实盘须自行验证。

◍ 搭一个能看见分布形状的测试台

做优化算法之前,先把随机变量的分布形状看清楚,比盲调参数靠谱得多。思路不复杂:把取值区间切成左右等量的格子,每个格子就是个计数器,随机数掉进哪个格子,那个格子的计数就加一。 关键陷阱在分界点。假设区间 [min;max] 里有个 in 点偏右,左右各 6 个格子,在 [min;in] 生成的随机数数量会明显多于 [in;max],分布就向左偏了。要维持左右平均掉落数相同、只改形状不改概率,左右格子数必须相等——上面例子里两侧各 6 格就是这么来的。 测试台跑起来就六步:建 CCanvas 画布、按选定分布生随机数、判格子加计数、算全部格子最小最大掉落量、按数量画圆圈、用蓝(少)到红(多)着色。100 万次采样(CNT=1000000)下,肉眼能直接看出分布是均匀、高斯还是重尾。 代码里输入参数暴露了可调空间:MinP/InpP/MaxP 定区间,Size=1000 是单侧格子数,SigmaP/PowerP/LeviPowerP 分别管高斯、幂律、莱维飞行的形态。开 MT5 把 Distr_P 切到 gauss 跑一遍,画布上红团居中就说明采样没偏。

MQL5 / C++
class="macro">#class="kw">property script_show_inputs
class="macro">#include <Canvas\Canvas.mqh>
enum E_Distribution
{
  uniform = class="num">0,
  gauss   = class="num">1,
  power   = class="num">2,
  levi    = class="num">3
};
class=class="str">"cmt">//--- class="kw">input parameters
class="kw">input class="type">class="kw">double        MinP       = -class="num">100.0;
class="kw">input class="type">class="kw">double        InpP       =  class="num">0;
class="kw">input class="type">class="kw">double        MaxP       =  class="num">100.0;
class="kw">input class="type">int           CNT        =  class="num">1000000;
class="kw">input class="type">int           Size       =  class="num">1000;
class="kw">input class="type">class="kw">double        SigmaP     =  class="num">3;      class=class="str">"cmt">//Sigma for "Gauss" distribution
class="kw">input class="type">class="kw">double        PowerP     =  class="num">2;      class=class="str">"cmt">//Power for "Power law" distribution
class="kw">input class="type">class="kw">double        LeviPowerP =  class="num">2;      class=class="str">"cmt">//Power for "Levy flights" distribution
class="kw">input E_Distribution Distr_P   = gauss;   class=class="str">"cmt">//Distribution type
class=class="str">"cmt">//——————————————————————————————————————————————————————————————————————————————
class="type">void OnStart()
{
  CCanvas Canvas;
  class="type">int W = class="num">750;
  class="type">int H = class="num">400;
  class="type">int O = class="num">10;
  class="type">int CountL [];
  class="type">int CountR [];
  ArrayResize(CountL, Size);
  ArrayInitialize(CountL, class="num">0);
  ArrayResize(CountR, Size);
  ArrayInitialize(CountR, class="num">0);
  class="type">class="kw">string canvasName = "Test_Probability_Distribution_Canvas";
  if (!Canvas.CreateBitmapLabel(canvasName, class="num">5, class="num">30, W, H, COLOR_FORMAT_ARGB_RAW))
  {
    Print("Error creating Canvas: ", GetLastError());
    class="kw">return;
  }
  ObjectSetInteger(class="num">0, canvasName, OBJPROP_HIDDEN,     false);
  ObjectSetInteger(class="num">0, canvasName, OBJPROP_SELECTABLE, true);
  Canvas.Erase(COLOR2RGB(clrWhite));
  Canvas.Rectangle(class="num">1, class="num">1, W - class="num">1, H - class="num">1, COLOR2RGB(clrBlack));
  class="type">int    ind = class="num">0;
  class="type">class="kw">double X   = class="num">0.0;
  for (class="type">int i = class="num">0; i < CNT; i++)
  {
    class="kw">switch (Distr_P)
    {
    case uniform:

把分布计数画到画布上的坐标换算

上面那段 switch 跑完四种分布(uniform / gauss / power / levi)后,X 值会按是否小于中枢 InpP 分流进 CountL 或 CountR 数组,下标 ind 由 Scale 线性映射到 0~Size 区间,越界则钳在 [0, Size-1]。 随后用一趟循环扫两个数组,求出 maxCNT 和 minCNT:这两个值直接决定后面柱点颜色和纵向缩放比例,若样本全堆在一格,maxCNT 可能等于 CNT(总抽样数),minCNT 则倾向 0。 绘图阶段先把中枢像素位置 centre 算出来,左右半宽 stepL、stepR 各除以 2 得半步 stH_L / stH_R,为防除零导致 0 宽,任一为 0 就硬置 1。 对每个 i,左簇 x 用 Scale(i,0,Size-1,O,centre-stH_L) 映射到中枢左侧,y 用 Scale(CountL[i],0,maxCNT,O,H-O,true) 做反向纵轴缩放;颜色由 DoubleToColor 在 0~255 亮度内插值,最后 Canvas.Circle 画半径 2 和 3 的双圈点。右簇对称映射到 centre+stH_R 到 W-O。 开 MT5 把 Size 设成 50、CNT 设 1e4,跑完看左右双圈点密度:若 levi 分布下右簇外圈点明显稀疏,说明尾部抽样概率衰减快,可据此调 LeviPowerP 观察画布形态变化。外汇与贵金属价格分布受事件驱动,这类可视化仅辅助判断概率结构,实盘仍属高风险。

MQL5 / C++
X = UniformDistribution(InpP, MinP, MaxP);
break;
case gauss:
  X = GaussDistribution(InpP, MinP, MaxP, SigmaP);
  break;
case power:
  X = PowerDistribution(InpP, MinP, MaxP, PowerP);
  break;
case levi:
  X = LeviDistribution(InpP, MinP, MaxP, LeviPowerP);
  break;
}
if (X < InpP)
{
  ind = (class="type">int)Scale(X, MinP, InpP,
                    class="num">0,     Size, false);
  if (ind >= Size) ind = Size - class="num">1;
  if (ind < class="num">0)     ind = class="num">0;
  CountL [ind] += class="num">1;
}
else
{
  ind = (class="type">int)Scale(X, InpP, MaxP,
                    class="num">0,     Size, false);
  if (ind >= Size) ind = Size - class="num">1;
  if (ind < class="num">0)     ind = class="num">0;
  CountR [ind] += class="num">1;
}
}
class="type">int minCNT = CNT;
class="type">int maxCNT = class="num">0;
for (class="type">int i = class="num">0; i < Size; i++)
{
  if (CountL [i] > maxCNT) maxCNT = CountL [i];
  if (CountR [i] > maxCNT) maxCNT = CountR [i];
  if (CountL [i] < minCNT) minCNT = CountL [i];
  if (CountR [i] < minCNT) minCNT = CountR [i];
}
class="type">int x = class="num">0.0;
class="type">int y = class="num">0.0;
class="type">class="kw">color clrF;
class="type">int centre = class="num">0;
class="type">int stepL  = class="num">0;
class="type">int stH_L  = class="num">0;
class="type">int stepR  = class="num">0;
class="type">int stH_R  = class="num">0;
centre = (class="type">int)Scale(InpP, MinP, MaxP, class="num">10, W - class="num">11, false);
stepL = (centre - O) / Size;
stH_L = stepL / class="num">2;
if (stH_L == class="num">0) stH_L = class="num">1;
stepR = (W - O - centre) / Size;
stH_R = stepR / class="num">2;
if (stH_R == class="num">0) stH_R = class="num">1;
for (class="type">int i = class="num">0; i < Size; i++)
{
  x = (class="type">int)Scale(i,          class="num">0, Size - class="num">1, O, centre - stH_L, false);
  y = (class="type">int)Scale(CountL [i], class="num">0, maxCNT,   O, H - O,    true);
  clrF = DoubleToColor(CountL [i], minCNT, maxCNT, class="num">0, class="num">255);
  Canvas.Circle(x, y, class="num">2, COLOR2RGB(clrF));
  Canvas.Circle(x, y, class="num">3, COLOR2RGB(clrF));
  x = (class="type">int)Scale(i,          class="num">0, Size - class="num">1, centre + stH_R, W - O, false);
  y = (class="type">int)Scale(CountR [i], class="num">0, maxCNT,   O,            H - O,    true);

常见问题

在测试台里把每次随机结果计数后,按坐标换算映射到画布像素,横轴为数值区间、纵轴为频次即可直接出图。
纯随机在低维还好,高维里有效样本极稀疏;用算法把分布往优区位移并压窄形态,能少跑几十倍样本仍摸到较优解。
可以,小布盯盘的 AIGC 已内置分布形态诊断,打开对应品种页就能看到偏度与位移的实时估计,不用自己写测试台。
只适合做离线参数预筛与分布实验,贵金属高风险,任何分布偏移都只是概率倾向,不能直接当开仓信号。
给横轴留 5% 边距并把极值区间做对数压缩,或单独把尾部区间放大重绘一次就能看清长尾形状。