确定性振荡搜索(DOS)·进阶篇
📘

确定性振荡搜索(DOS)·进阶篇

第 2/2 篇

粒子位移与适应度反馈的核心循环

在基于粒子群思路的优化器里,每一次迭代都先让所有粒子按当前速度平移,再做边界与步长对齐。Moving() 遍历 popSize 个粒子,对每个坐标维度把速度累加进位置,随后用 u.SeInDiSp() 把连续值吸附到 [rangeMin, rangeMax] 内允许的离散步长上,避免越界或无效参数。 Revision() 在位置更新后重算适应度,并维护全局最优 fB 与坐标数组 cB。若某个粒子适应度 a[i].f 高于已知最优,就通过 ArrayCopy 把它的坐标整组拷进 cB,这一步决定了后续搜索是否会向该区域聚集。 ProcessParticleMovement() 用前后两次适应度差 fitnessDiff 来判断斜率状态。当原斜率为正却出现适应度回落,速度向量各分量直接乘 -0.5 反向并减半,把 slope 置为 -1;这种「撞墙减速折返」机制让参数搜索在外汇或贵金属这类高噪声品种上,可能减少在局部劣化区的无效游走。 开 MT5 把这段接进自己的 EA 框架时,重点看 velocities[i].v[d] *= -0.5 这一行——若你的坐标维度超过 10,折返步长衰减可能偏快,可先改成 -0.7 观察收敛轨迹是否更稳。

MQL5 / C++
class="type">void C_AO_DOS::Moving()
{
  class=class="str">"cmt">// Handle all particles
  for (class="type">int i = class="num">0; i < popSize; i++)
  {
    class=class="str">"cmt">// Save the fitness value
    a [i].fP = a [i].f;
    class=class="str">"cmt">// Calculate new coordinates based on velocity
    for (class="type">int d = class="num">0; d < coords; d++)
    {
      class=class="str">"cmt">// Update position
      a [i].c [d] += velocities [i].v [d];
      class=class="str">"cmt">// Round to the nearest acceptable step
      a [i].c [d] = u.SeInDiSp(a [i].c [d], rangeMin [d], rangeMax [d], rangeStep [d]);
    }
  }
}

class="type">void C_AO_DOS::Revision()
{
  class=class="str">"cmt">// Handle each particle
  for (class="type">int i = class="num">0; i < popSize; i++)
  {
    class=class="str">"cmt">// Update the best solution if the current solution is better
    if (a [i].f > fB)
    {
      fB = a [i].f;
      ArrayCopy(cB, a [i].c, class="num">0, class="num">0, WHOLE_ARRAY);
    }
    class=class="str">"cmt">// Handle particle motion based on fitness change
    ProcessParticleMovement(i);
  }
}

class="type">void C_AO_DOS::ProcessParticleMovement(class="type">int particleIndex)
{
  class=class="str">"cmt">// Local variables for access optimization
  class="type">class="kw">double currentFitness  = a [particleIndex].f;
  class="type">class="kw">double previousFitness = a [particleIndex].fP;
  class="type">int    currentSlope    = velocities [particleIndex].slope;
  class=class="str">"cmt">// Comparison of fitnesses to determine the movement direction
  class="type">class="kw">double fitnessDiff = currentFitness - previousFitness;
  class=class="str">"cmt">// Handle a slope according to the current state
  if (currentSlope == class="num">0) class=class="str">"cmt">// Unknown slope
  {
    class=class="str">"cmt">// Determine the slope based on the change in fitness
    velocities [particleIndex].slope = (fitnessDiff > class="num">0) ? class="num">1 : (fitnessDiff < class="num">0) ? -class="num">1 : class="num">0;
  }
  else
    if (currentSlope == class="num">1 && fitnessDiff < class="num">0) class=class="str">"cmt">// Positive slope and deterioration of fitness
    {
      class=class="str">"cmt">// Change direction and decrease velocity
      for (class="type">int d = class="num">0; d < coords; d++) velocities [particleIndex].v [d] *= -class="num">0.5; class=class="str">"cmt">// Optimized form of division by class="num">2
      velocities [particleIndex].slope  = -class="num">1; class=class="str">"cmt">// Change the slope to negative
    }
    else

◍ 负斜率下的粒子群漂移逻辑

在粒子群寻优里,当某个粒子的 currentSlope 被判定为 -1(即负斜率)且 fitnessDiff 小于 0(适应度退化)时,算法不再让其自由探索,而是强制向全局最优 cB 靠拢。 具体做法是对每个维度 d 累加速度项:(cB[d] - a[particleIndex].c[d]) * movementFactor,相当于用移动因子把粒子拉向当前已知最优坐标;随后把 slope 重置为 0,表示斜率状态未知,等待下一轮评估。 若用结构方法检测到该粒子速度整体为零(IsZero 为真),同样要初始化速度朝 cB 移动,并清零 slope。这套机制避免了粒子在退化或停滞时原地空转,对外汇与贵金属参数优化这类高噪声场景,可能提升收敛稳定性,但实盘前务必在 MT5 策略测试器用历史数据验证,此类品种杠杆高、跳空频繁,存在重大资金风险。

MQL5 / C++
if (currentSlope == -class="num">1 && fitnessDiff < class="num">0) class=class="str">"cmt">// Negative slope and fitness degradation
{
  class=class="str">"cmt">// Apply the swarming mechanism - movement towards the global optimum
  for (class="type">int d = class="num">0; d < coords; d++) velocities [particleIndex].v [d] += (cB [d] - a [particleIndex].c [d]) * movementFactor;
  velocities [particleIndex].slope = class="num">0; class=class="str">"cmt">// Reset the slope as unknown
}
class=class="str">"cmt">// Check for zero velocity class="kw">using the structure method
if (velocities [particleIndex].IsZero())
{
  class=class="str">"cmt">// Initialize the velocity by moving towards the global optimum
  for (class="type">int d = class="num">0; d < coords; d++) velocities [particleIndex].v [d] = (cB [d] - a [particleIndex].c [d]) * movementFactor;
  class=class="str">"cmt">// Reset the slope
  velocities [particleIndex].slope  = class="num">0;
}

「低维测试里的算法排位与离散现象」

把内置群体效应的梯度型算法(DOS)丢进三组标准测试函数跑一遍,每组函数各取 5、25、500 个峰值形态,迭代次数固定 10000。Hilly 函数三项结果落在 0.3422 附近,Forest 函数从 0.5709 降到 0.3288,Megacity 函数则从 0.2000 爬到 0.2308,总分 2.91248,约占满分的 32.36%。 横向拉一张 39 个种群优化算法的评级表,DOS 只作参考示例,没进正式排名。榜首 ANS 跨邻域搜索三项 Hilly 值 0.94948 / 0.84776 / 0.43857,最终 6.134 分(68.15%);末位 ABHA 人工蜂巢算法仅 4.127 分(45.85%)。中间如 DE 差分进化在 500 峰 Megacity 上掉到 0.02953,离散程度比低维时更夸张。 低维函数上 DOS 的结果本身就有明显抖动——5 峰 Forest 给出 0.5709,但 500 峰反而压到 0.3288。这说明群体效应梯度法在维度切换时稳定性并不线性,MT5 里复现这套基准时,建议先锁死 Func runs=10000 再横向比对数个峰值档位。 外汇与贵金属市场属高风险领域,任何优化器回测优势都只是概率倾向,实盘须以风控为先。

优化器横向跑分里的冷门黑马

上面这组对照表把 8 个优化器的三项误差分量、综合误差、收敛代数与耗时摊开了看。ACMO 大气云模型综合误差 1.69270、耗时 44.90 秒,ADAMm 紧随其后 1.60014 / 44.85 秒,都属于第一梯队,但代价是迭代到 4.037 代上下才稳住。 真正值得盯的是垫底的 RW 神经 Boid 优化:综合误差仅 1.06694,收敛代 2.348,耗时压到 26.09 秒,三项分量里最低的一组到了 0.52734。它用更少的代数和一半出头的时间,把误差控在比 CFO(1.43750 / 40.76 秒)更低的区间。 做 MT5 参数寻优时,别只认 ADAM 系。把 RW 或 DOS(综合 1.02654、32.36 秒)塞进你的 EA 优化脚本里跑一遍同品种回测,可能比默认优化器更快出可交易解。外汇与贵金属杠杆高,优化结果仅代表历史样本拟合,实盘仍属高风险。

◍ 一点提醒

这套 DOS 算法只吃两个参数——种群大小和移动系数,实测配置负担比多数随机群智能轻,参数设歪的风险也低。三态斜率(正向、负向、未知)让粒子按当前搜索方向质量自调行为,是它区别于标准描述的核心改动,且全程无复杂数学,MT5 里跑起来很快。 从附带的 Test_AO_DOS.mq5 回测看,评分区间 0–100、100 为理论顶分,低维函数结果偏分散是明确短板;作者归档里放了 DOS.zip(215.67 KB)含基类与测试台,想验证直接下脚本跑统一平台即可。 外汇与贵金属市场高波动、高杠杆,这类确定性群算法仅解决特定优化问题,别当信号源裸用;文内结论基于实验、作者不对准确性担责,自己跑一遍再决定是否接进 EA。

常见问题

每轮先按当前位置算适应度,再用振荡项扰动位移,反馈决定下一轮偏移方向,核心就是位移—评估—再位移的闭环。
负斜率让低值区适应度更优,振荡项叠加后粒子倾向朝该侧累积,形成单向漂移,需在边界加反弹或重采样抑制。
小布可接入你的品种页,把 DOS 输出参数做离散度与排位诊断,标出低维测试里异常跃迁的冷门解,减少人工肉眼筛查。
是,低维空间适应度地形破碎,排位跳动属正常离散;建议多 seed 复跑取中位排位,别信单次第一。
大概率不值得直接跟,黑马多依赖特定维度与噪声,先验证其斜率逻辑与边界处理,再考虑小样本实盘。