种群优化算法:改变概率分布的形状和位移,并基于智能头足类生物(SC)进行测试(基础篇)
用头足类智能重写分布形态
种群优化思路在 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 跑一遍,画布上红团居中就说明采样没偏。
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 观察画布形态变化。外汇与贵金属价格分布受事件驱动,这类可视化仅辅助判断概率结构,实盘仍属高风险。
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);