基于分形的算法(FBA)(基础篇)
◍ 分形逻辑怎么塞进 MT5 策略
基于分形的算法(FBA)把比尔·威廉姆斯的分形定义当成信号触发器:当左右各两根 K 线的高点都被中间 K 线超越,就记一个顶分形;低点反之记底分形。这类结构不预测方向,只标定局部极值,适合做突破或均值回归的锚点。 MT5 里用 MQL5 写分形检测,核心是先抓最高/最低价再比对邻域。下面这段在每根新 K 线收完时扫描最近 5 根,命中就返回分形类型。 外汇与贵金属杠杆高,分形假突破概率不低,实盘前务必在策略测试器用真实点差回测 2020—2025 年数据,观察回撤是否可接受。
class="type">int FractalType(class="type">int shift=class="num">1) { class="type">class="kw">double midHigh = High[iHighest(NULL,class="num">0,MODE_HIGH,class="num">5,shift)]; class="type">class="kw">double midLow = Low[iLowest(NULL,class="num">0,MODE_LOW,class="num">5,shift)]; if(midHigh==High[shift+class="num">2] && midHigh>High[shift+class="num">1] && midHigh>High[shift+class="num">3] && midHigh>High[shift] && midHigh>High[shift+class="num">4]) class="kw">return class="num">1; class=class="str">"cmt">// 顶分形 if(midLow==Low[shift+class="num">2] && midLow<Low[shift+class="num">1] && midLow<Low[shift+class="num">3] && midLow<Low[shift] && midLow<Low[shift+class="num">4]) class="kw">return -class="num">1; class=class="str">"cmt">// 底分形 class="kw">return class="num">0; }
分形搜索怎么替你省下盲猜时间
元启发式算法在复杂优化里能压住计算量,靠的是在可接受时间内给出可行解而不是穷举。遗传、粒子群、差分进化、蚁群这些老面孔之前已经拆过,这一篇换一条更冷的路:分形。
- 年 Marjan Kaedi 提出的 FBA(Fractal-Based Algorithm)把分形的自相似性直接当成搜索逻辑用。它不靠随机扰动硬撞,而是按有前景解在子空间里的分布密度,判断哪块区域值得细挖。
具体跑起来就是反复切分搜索空间:每一轮把当前空间拆成子空间,密度高的那块留下来继续切,密度低的丢掉。迭代下去会自然长出一个朝最优解收敛的自相似结构,全局勘探和局部精修在同一套规则里完成。 外汇与贵金属参数优化属高风险场景,FBA 只是缩小搜索范围的工具,不保证找到全局最优;开 MT5 用它跑 EA 参数前,先用标准测试函数看收敛曲线再上实盘逻辑。
「分形搜索怎么在 MT5 里落地」
把解空间当棋盘,先均匀撒一批随机点测适应度,留最优 60% 当「有前景点」,再统计它们落在哪些方格,取排名前 30% 的方格继续切细——这就是 FBA 的骨架。大部分新点往这些格子灌,留一小撮做随机游走防漏检,迭代下去自然长出分形层级。 C_AO_FBA 类直接继承通用基类 C_AO,构造函数收种群规模、P1/P2/P3 占比和每维分段数;SetParams 允许跑途中改参数。内部结构体 S_Subspace 记每个子空间的上下界、前景值、层级和父空间指针,所有细分、排名、融合都绕着它转。 MutatePoints 有个坑值得记:原版对坐标加高斯噪声,实测和随机搜索几乎没差,代码已注释掉,换成幂律分布改坐标,多样性才真正起来。GenerateNewPopulation 按子空间前景评分占比分配新点,评分和小于 0.0001 时强行给每格 1.0 保底,确保总点数严格等于 popSize。 下面这段是类头最简骨架,看得出命名和继承关系,复制进 MT5 就能接着写细分逻辑。
class=class="str">"cmt">//—————————————————————————————————————————————————————————————————————————————— class C_AO_FBA : class="kw">public C_AO { class="kw">public: class=class="str">"cmt">//-------------------------------------------------------------------- ~C_AO_FBA() { } C_AO_FBA() { ao_name = "FBA";
◍ 把分形算法参数塞进优化器结构体
在 MT5 自带优化框架下接一套分形算法,第一步是把算法超参做成可序列化的字段。下面这段声明把种群规模、三类比例和维度切分数直接写进类成员,并用 ArrayResize 开出一个长度为 5 的 params 数组承载它们。 popSize=50 表示每次迭代保留 50 个候选解;P1=60 意味前 60% 的点被判为「有希望点」进入下一代;P2=30 控制 30% 的子空间被标记为潜力空间;P3=0.8 给 80% 的点施加随机扰动避免早熟;m_value=10 则是每个维度切 10 段做离散化搜索。 SetParams 负责把 params 数组回灌给成员变量,注意 P3 是 double 不做强转,其余四个全转 int。Init 接口暴露了 rangeMinP/rangeMaxP/rangeStepP 三组边界与步长,外加 epochsP 默认 0 由调用方决定迭代轮数。 结构体 S_Subspace 是私有的搜索空间单元:min/max 数组框住子空间边界,promisingRank 存归一化潜力值,isPromising 打标,parentIndex 指回父空间(-1 即根空间)。开 MT5 把这套声明贴进 EA 头文件,能直接跑通参数注入。
ao_desc = "Fractal-Based Algorithm"; ao_link = "[MQL5官方文档] popSize = class="num">50; class=class="str">"cmt">// population size P1 = class="num">60; class=class="str">"cmt">// percentage of promising points P2 = class="num">30; class=class="str">"cmt">// percentage of promising subspaces P3 = class="num">0.8; class=class="str">"cmt">// percentage of points for random modification m_value = class="num">10; class=class="str">"cmt">// number of intervals to split each dimension into ArrayResize(params, class="num">5); params [class="num">0].name = "popSize"; params [class="num">0].val = popSize; params [class="num">1].name = "P1"; params [class="num">1].val = P1; params [class="num">2].name = "P2"; params [class="num">2].val = P2; params [class="num">3].name = "P3"; params [class="num">3].val = P3; params [class="num">4].name = "m_value"; params [class="num">4].val = m_value; } class="type">void SetParams() { popSize = (class="type">int)params [class="num">0].val; P1 = (class="type">int)params [class="num">1].val; P2 = (class="type">int)params [class="num">2].val; P3 = params [class="num">3].val; m_value = (class="type">int)params [class="num">4].val; } class="type">bool Init(class="kw">const class="type">class="kw">double &rangeMinP [], class=class="str">"cmt">// minimum values class="kw">const class="type">class="kw">double &rangeMaxP [], class=class="str">"cmt">// maximum values class="kw">const class="type">class="kw">double &rangeStepP [], class=class="str">"cmt">// step change 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 P1; class=class="str">"cmt">// percentage of promising points class="type">int P2; class=class="str">"cmt">// percentage of promising subspaces class="type">class="kw">double P3; class=class="str">"cmt">// share of points for random modification class="type">int m_value; class=class="str">"cmt">// number of intervals to split each dimension into class="kw">private: class=class="str">"cmt">//------------------------------------------------------------------- class=class="str">"cmt">// Structure for representing a subspace class="kw">struct S_Subspace { class="type">class="kw">double min []; class=class="str">"cmt">// minimal boundaries of the subspace class="type">class="kw">double max []; class=class="str">"cmt">// maximum boundaries of the subspace class="type">class="kw">double promisingRank; class=class="str">"cmt">// potential rank(normalized value) class="type">bool isPromising; class=class="str">"cmt">// flag of potential class="type">int parentIndex; class=class="str">"cmt">// index of the parent subspace(-class="num">1 for root ones) }
子空间结构体与优化器初始化落点
上面这段把 FBA 优化器的子空间骨架和对外初始化入口摊开了。S_Subspace 里的 level 字段标记层级,原始搜索空间为 0,往下细分每深一层数值加 1;Init(int coords) 负责按坐标维度扩出 min/max 边界数组,并把 promisingRank 置 0.0、isPromising 置 false、parentIndex 置 -1,相当于每块子空间出生即「未评估」状态。 紧随其后的 subspaces 数组和那一串辅助方法(IsPointInSubspace、DivideSubspace、IdentifyPromisingPoints 等)构成了空间递归切分与排序的主链路;其中 SortByFitness 默认 ascending=false,意味着适应度越高排得越靠前,QuickSort/Partition 是它背后的裸写快排,没调标准库。 C_AO_FBA::Init 是实盘里真正会调用的入口:它先跑 StandardInit 校验区间与步长,再调 CreateInitialSpacePartitioning() 把整段参数空间切成初始子空间并返回 true。你在 MT5 里接这套逻辑时,只需保证 rangeMinP/rangeMaxP/rangeStepP 三个数组等长,优化器便会在第 0 个 epoch 前完成首轮空间划分,后续迭代才有「 promising 子空间」可言。外汇与贵金属参数寻优属高风险操作,回测结论仅代表历史样本倾向,实盘可能失效。
class="type">int level; class=class="str">"cmt">// level in hierarchy(class="num">0 for original space) class="type">void Init(class="type">int coords) { ArrayResize(min, coords); ArrayResize(max, coords); promisingRank = class="num">0.0; isPromising = false; parentIndex = -class="num">1; level = class="num">0; } }; S_Subspace subspaces []; class=class="str">"cmt">// array of subspaces class=class="str">"cmt">// Auxiliary methods class="type">bool IsPointInSubspace(class="kw">const class="type">class="kw">double &point [], class="kw">const S_Subspace &subspace); class="type">void CreateInitialSpacePartitioning(); class="type">void DivideSubspace(class="type">int subspaceIndex); class="type">void IdentifyPromisingPoints(class="type">int &promisingIndices []); class="type">void CalculateSubspaceRanks(class="kw">const class="type">int &promisingIndices []); class="type">void SelectPromisingSubspaces(); class="type">void DividePromisingSubspaces(); class="type">void GenerateNewPopulation(); class="type">void MutatePoints(); class="type">void SortByFitness(class="type">class="kw">double &values [], class="type">int &indices [], class="type">int size, class="type">bool ascending = false); class="type">void QuickSort(class="type">class="kw">double &values [], class="type">int &indices [], class="type">int low, class="type">int high, class="type">bool ascending); class="type">int Partition(class="type">class="kw">double &values [], class="type">int &indices [], class="type">int low, class="type">int high, class="type">bool ascending); }; class="type">bool C_AO_FBA::Init(class="kw">const class="type">class="kw">double &rangeMinP [], class=class="str">"cmt">// minimum values class="kw">const class="type">class="kw">double &rangeMaxP [], class=class="str">"cmt">// maximum values class="kw">const class="type">class="kw">double &rangeStepP [], class=class="str">"cmt">// step change class="kw">const class="type">int epochsP = class="num">0) class=class="str">"cmt">// number of epochs { if (!StandardInit(rangeMinP, rangeMaxP, rangeStepP)) class="kw">return false; CreateInitialSpacePartitioning(); class="kw">return true; }