大气云模型优化(ACMO):理论·进阶篇
「云滴优化器的参数骨架」
用雨滴云模型做 EA 参数寻优时,先得把种群与云结构的基础常量钉死。下面这组初值来自一套实盘前回测用的默认配置:种群规模 50、云数量 5、每维区域数 10,初始熵 1.0、超熵 0.5,阈值因子 λ=0.7、衰减率 γ=0.2。 这些量不是拍脑袋,dMin=0.2 表示最稀疏云内雨滴数不低于平均值的 20%,λ 控制“暴雨区”入选门槛,γ 决定每次迭代后云势的削弱速度。外汇与贵金属波动高、滑点随机,直接套用可能偏离你的品种特性,建议先在 MT5 策略测试器里跑一轮 EURUSD M15 观察收敛曲线。 代码里用 ArrayResize(params,8) 开出 8 个槽位,把上面 8 个变量名和值成对塞进 params 数组,SetParams() 再反向读回——这样外部面板改一个数,优化器内部常量就跟着变,不用动核心逻辑。
popSize = class="num">50; class=class="str">"cmt">//population size cloudsNumber = class="num">5; class=class="str">"cmt">// Number of clouds regionsNumber = class="num">10; class=class="str">"cmt">// Number of regions per dimension(M) dMin = class="num">0.2; class=class="str">"cmt">// Minimum number of drops relative to the average number of drops in the clouds(dN) EnM0 = class="num">1.0; class=class="str">"cmt">// Initial value of entropy HeM0 = class="num">0.5; class=class="str">"cmt">// Initial value of hyperentropy λ = class="num">0.7; class=class="str">"cmt">// Threshold factor(threshold of the rainiest regions) γ = class="num">0.2; class=class="str">"cmt">// Weaken rate ArrayResize(params, class="num">8); params [class="num">0].name = "popSize"; params [class="num">0].val = popSize; params [class="num">1].name = "cloudsNumber"; params [class="num">1].val = cloudsNumber; params [class="num">2].name = "regionsNumber"; params [class="num">2].val = regionsNumber; params [class="num">3].name = "dMin"; params [class="num">3].val = dMin; params [class="num">4].name = "EnM0"; params [class="num">4].val = EnM0; params [class="num">5].name = "HeM0"; params [class="num">5].val = HeM0; params [class="num">6].name = "λ"; params [class="num">6].val = λ; params [class="num">7].name = "γ"; params [class="num">7].val = γ; } class="type">void SetParams() { popSize = (class="type">int)params [class="num">0].val; cloudsNumber = (class="type">int)params [class="num">1].val; regionsNumber = (class="type">int)params [class="num">2].val; dMin = params [class="num">3].val; EnM0 = params [class="num">4].val; HeM0 = params [class="num">5].val; λ = params [class="num">6].val; γ = params [class="num">7].val; } class="type">bool Init(class="kw">const class="type">class="kw">double &rangeMinP [], class=class="str">"cmt">//minimum search range class="kw">const class="type">class="kw">double &rangeMaxP [], class=class="str">"cmt">//maximum search range class="kw">const class="type">class="kw">double &rangeStepP [], class=class="str">"cmt">//step search
◍ ACMO 云滴结构体的字段与初始化落点
这段 C_AO_ACMO 类的成员变量定义了云优化(ACMO)的核心参数:cloudsNumber 控制云的数量,regionsNumber 即每个维度的区域数 M,dMin 是相对平均云滴数的最小雨滴比例,λ 与 γ 分别充当阈值因子和衰减率。私有段里的 dTotal 对应最大总雨滴数 N,entropy[] 与 minGp 用于跟踪演化过程中的熵和压力。 Init 函数接收区间上下限与步长数组,并带一个默认 0 的 epochsP 参数。进去先跑 StandardInit 做基础校验,失败直接返 false;随后把 epochs 设为传入值、epochNow 归零,dTotal 绑定 popSize,并把 dMin 按云数比例缩放:dMin = dMin * (popSize / (double)cloudsNumber)。 最后两行 ArrayResize 把 entropy 和 areas 都拉到 coords 长度,意味着维度坐标数直接决定熵数组与区域数组的规模。在 MT5 里改 coords 或 popSize 后,这两处 resize 会直接影响内存占用和后续降雨分布的分辨率,外汇与贵金属行情下此类算法对参数敏感,实盘验证前务必用历史数据回测。
class="kw">const class="type">int epochsP = class="num">0); class=class="str">"cmt">//number of epochs class="type">void Moving(); class="type">void Revision(); class=class="str">"cmt">//---------------------------------------------------------------------------- class="type">int cloudsNumber; class=class="str">"cmt">// Number of clouds class="type">int regionsNumber; class=class="str">"cmt">// Number of regions per dimension(M) class="type">class="kw">double dMin; class=class="str">"cmt">// Minimum number of drops relative to the average number of drops in the clouds(dN) class="type">class="kw">double EnM0; class=class="str">"cmt">// Initial value of entropy class="type">class="kw">double HeM0; class=class="str">"cmt">// Initial value of hyperentropy class="type">class="kw">double λ; class=class="str">"cmt">// Threshold factor class="type">class="kw">double γ; class=class="str">"cmt">// Weaken rate S_ACMO_Area areas []; S_ACMO_Cloud clouds []; class="kw">private: class=class="str">"cmt">//------------------------------------------------------------------- class="type">int epochs; class="type">int epochNow; class="type">int dTotal; class=class="str">"cmt">// Maximum total number of droplets(N) class="type">class="kw">double entropy []; class=class="str">"cmt">// Entropy class="type">class="kw">double minGp; class=class="str">"cmt">// Minimum global pressure class="type">void MoveClouds(class="type">bool &rev); class="type">int GetRegionIndex(class="type">class="kw">double point, class="type">int ind); class="type">void RainProcess(class="type">bool &rev); class="type">void DropletsDistribution(class="type">class="kw">double &clouds [], class="type">int &droplets []); class="type">void UpdateRegionProperties(); class="type">void GenerateClouds(); class="type">class="kw">double CalculateHumidityThreshold(); class="type">void CalculateNewEntropy(S_ACMO_Cloud &cl, class="type">int t); }; class=class="str">"cmt">//—————————————————————————————————————————————————————————————————————————————— class=class="str">"cmt">//—————————————————————————————————————————————————————————————————————————————— class="type">bool C_AO_ACMO::Init(class="kw">const class="type">class="kw">double &rangeMinP [], class="kw">const class="type">class="kw">double &rangeMaxP [], class="kw">const class="type">class="kw">double &rangeStepP [], class="kw">const class="type">int epochsP = class="num">0) { if (!StandardInit(rangeMinP, rangeMaxP, rangeStepP)) class="kw">return class="kw">false; class=class="str">"cmt">//---------------------------------------------------------------------------- epochs = epochsP; epochNow = class="num">0; class=class="str">"cmt">//---------------------------------------------------------------------------- dTotal = popSize; dMin = dMin * (popSize / (class="type">class="kw">double)cloudsNumber); ArrayResize(entropy, coords); ArrayResize(areas, coords);
网格区域的熵宽与云点初始化
这段逻辑干的事,是把每个坐标维度的取值范围切成等宽区间,并为后续聚类准备空云。熵宽 entropy[c] 直接由 (rangeMax[c] - rangeMin[c]) / regionsNumber 算出,区间数量 regionsNumber 决定粒度,设太大在 MT5 里会拖慢实时计算。 内层循环给每个 region 算中心价:先取区间中值,再用 u.SeInDiSp 按最小/最大/步长吸附到合法报价网格上,最后把 x 也指向该中心。注意 centre 被函数二次处理,意味着你给的 rangeStep 会真实影响聚类重心位置。 clouds 数组按 cloudsNumber 扩容,每个云调用 Init(coords) 清成空壳;minGp 置为 DBL_MAX 是为了后面找最小组间距离时有干净初值。外汇与贵金属波动大,这种网格法对参数敏感,回测时建议先固定 regionsNumber 做敏感性排查。
for (class="type">int c = class="num">0; c < coords; c++) { entropy [c] = (rangeMax [c] - rangeMin [c]) / regionsNumber; ArrayResize(areas [c].regions, regionsNumber); for (class="type">int r = class="num">0; r < regionsNumber; r++) { areas [c].regions [r].Init(); areas [c].regions [r].centre = rangeMin [c] + entropy [c] * (r + class="num">0.5); areas [c].regions [r].centre = u.SeInDiSp(areas [c].regions [r].centre, rangeMin [c], rangeMax [c], rangeStep [c]); areas [c].regions [r].x = areas [c].regions [r].centre; } } ArrayResize(clouds, cloudsNumber); for (class="type">int i = class="num">0; i < cloudsNumber; i++) clouds [i].Init(coords); minGp = DBL_MAX; class="kw">return true; }
「画得少,看得清」
ACMO 把大气气象映射成三组实体:云层管解的空间多样性,区域框定搜索边界,水滴负责在解之间迁移。三者各自独立运行,耦合后形成一套不依赖多群体框架的连续优化机制,实数编码下既能跑离散决策也能跑浮点调参。 第二部分的落点很直接——把这套模型丢进标准测试函数,看收敛曲线和稳定性,再判断能不能挪到实盘参数寻优里。俄文原帖附的 ACMO.zip 只有 37.22 KB,本地解压后用 MT5 的 MetaEditor 直接编译,先跑几个低维函数验证水滴迁移逻辑有没有按文档走。 外汇和贵金属策略寻优天然高波动、高杠杆,任何算法给出的参数组合都只是概率倾向更优,不是免死金牌。跑通代码后,建议拿 EUR/USD 的 H1 历史数据做一轮样本外回测,再决定要不要进实盘。