针对交易的组合数学和概率论(第二部分):通用分形·进阶篇
(2/3)·对称、非对称与单边边界分形如何被一个通用函数收编,并落地到代码与性能评估
◍ 通用分形启动函数的落地写法
要让分形在 MT5 里正确跑起来,先得有一个准备函数:它负责在分形真正启动前算好所有前置变量,再按既定规则把分形交出去。下面这套 MQL5 实现把输入参数压得很短,m、n 对称相等,足够覆盖交易适用的目标,没必要堆砌高级扩展。 核心是一个 Container 结构体,装了上下边界各自的「概率×步数」累加值和总概率,并重载了 += 运算符,方便在主函数里合并同类结构。日志里能看到:首次即时报价时算完整个分形后不再重算,前六个数是容器原生字段,其余都是从它们派生的——比如「完整组」里两个非重叠假设概率之和恒为 1.0,代码可直接验证。 别把参数对称当摆设:设置函数里 m 和 n 相等且对称,Middle 的符号随大小关系翻转,Half 始终是 (m+n)/2.0。外汇与贵金属波动随机性强、杠杆风险高,这套逻辑只提供概率倾向,不预示必然方向。
Container StartFractal(class="type">int m, class="type">int n, class="type">int s,class="type">class="kw">double p)class=class="str">"cmt">//preparing all variables and starting the fractal { class="type">int Minimum; if ( m <= n ) Minimum=m; else Minimum=n; class="type">class="kw">double Middle; if ( n >= m ) Middle = (m+n)/class="num">2.0 - Minimum; else Middle = -((m+n)/class="num">2.0 - Minimum); class="type">class="kw">double Half = (m+n)/class="num">2.0; class="kw">return Fractal(Half,Middle,m,n,s,p,class="num">0,class="num">0,class="num">0,class="num">1.0); } class="kw">struct Containerclass=class="str">"cmt">//a container for collecting all the necessary data about the fractal { class=class="str">"cmt">//values to be summed, for the upper bound class="type">class="kw">double UpperMidSUp;class=class="str">"cmt">//the sum of probabilities multiplied by the number of steps up of a specific chain(to cross the upper bound) class="type">class="kw">double UpperMidSDown;class=class="str">"cmt">//the sum of probabilities multiplied by the number of steps down of a specific chain(to cross the upper bound class="type">class="kw">double UpperSummProbability;class=class="str">"cmt">//the sum of the probabilities(to cross the upper border) class=class="str">"cmt">//values to be summed, for the lower border class="type">class="kw">double LowerMidSUp;class=class="str">"cmt">//the sum of probabilities multiplied by the number of steps up of a specific chain(to cross the lower border) class="type">class="kw">double LowerMidSDown;class=class="str">"cmt">//the sum of probabilities multiplied by the number of steps down of a specific chain(to cross the lower border) class="type">class="kw">double LowerSummProbability;class=class="str">"cmt">//the sum of the probabilities(to cross the lower border) Container()class=class="str">"cmt">//class="kw">default constructor { UpperMidSUp=class="num">0.0; UpperMidSDown=class="num">0.0; UpperSummProbability=class="num">0.0; LowerMidSUp=class="num">0.0; LowerMidSDown=class="num">0.0; LowerSummProbability=class="num">0.0; } class=class="str">"cmt">// class="type">void Summ(Container &c0,class="kw">const Container &c1) class="kw">constclass=class="str">"cmt">//full sum for class="kw">operator overloading { c0.UpperMidSUp=c0.UpperMidSUp+c1.UpperMidSUp; c0.UpperMidSDown=c0.UpperMidSDown+c1.UpperMidSDown; c0.UpperSummProbability=c0.UpperSummProbability+c1.UpperSummProbability; c0.LowerMidSUp=c0.LowerMidSUp+c1.LowerMidSUp; c0.LowerMidSDown=c0.LowerMidSDown+c1.LowerMidSDown; c0.LowerSummProbability=c0.LowerSummProbability+c1.LowerSummProbability; } class="type">void class="kw">operator+=(Container &c) { Summ(this,c); }class=class="str">"cmt">//class="kw">operator += overload }; Container Fractal(class="type">class="kw">double Half, class="type">class="kw">double Middle, class="type">int m, class="type">int n, class="type">int s,class="type">class="kw">double p,class="type">int SU,class="type">int SD, class="type">int U, class="type">class="kw">double P)class=class="str">"cmt">//Fractal { Container C; class=class="str">"cmt">///to pass to the next fractal level
向上突破中轴的递归分形构造
当已出现上升笔数 U 大于中轴 Middle,且总步数 SU+SD 仍小于目标 s 时,进入 case 1 的分形展开。此时剩余可走步数为 (n-1)-U,若大于 0 就按二项式系数把后续每一步的上升/下降组合全部枚举进容器 C。 核心递推在 for 循环里:NewU 由 -(n-1)+2*u+2*U 给出,NewP 用 Factorial 算组合数再乘 pow(p,u)*pow(1-p,剩余) 得到该分支概率。NewSU、NewSD 同步累加,随后调用 Fractal 做下一层递归。 若剩余步数恰为 0,则不再循环,直接构造一个 Container ct:其 UpperMidSDown = P*p*SD,UpperMidSUp = P*p*(SU+1),UpperSummProbability = P*p,并将 ct 与递归结果一并加入 C。这段逻辑说明,在 U>Middle 的边界情形下,价格向上越过中轴后的概率质量会按 p 的次幂衰减分配。 外汇与贵金属市场杠杆高、波动剧烈,此类分形概率仅反映数学模型下的路径可能,实盘须以 MT5 回测验证,切勿直接用作仓位依据。
class="type">int NewU; class="type">int NewSU; class="type">int NewSD; class="type">class="kw">double NewP; class=class="str">"cmt">/// if ( U > Middle && SU + SD < s )class=class="str">"cmt">//case class="num">1 { if ( (n-class="num">1) - U > class="num">0 ) { for ( class="type">int u=class="num">0 ; u <= (n-class="num">1) - U; u++ ) { NewU = -(n-class="num">1) + class="num">2*u + class="num">2*U; NewP = P * (Factorial((n-class="num">1) - U)/(Factorial(u)*Factorial((n-class="num">1) - U - u))) * pow(p,u)*pow(class="num">1.0-p,(n-class="num">1) - U - u); NewSU = SU + u; NewSD = SD + ((n-class="num">1) - U - u); C+=Fractal(Half,Middle,m,n,s,p,NewSU,NewSD,NewU,NewP); } } if ( (n-class="num">1) - U == class="num">0 ) { NewU = U - class="num">1; NewP = P * (class="num">1.0 - p); NewSU = SU; NewSD = SD + class="num">1; Container ct; ct.UpperMidSDown=P*p*SD; ct.UpperMidSUp=P*p*(SU+class="num">1); ct.UpperSummProbability=P*p; C+=ct; C+=Fractal(Half,Middle,m,n,s,p,NewSU,NewSD,NewU,NewP); } } if ( U < Middle && SU + SD < s )class=class="str">"cmt">//case class="num">2 { if ( (m-class="num">1) + U > class="num">0 ) { for ( class="type">int u=class="num">0 ; u <= (m-class="num">1) + U; u++ ) { NewU = -(m-class="num">1) + class="num">2*u; NewP = P * (Factorial((m-class="num">1) + U)/(Factorial(u)*Factorial((m-class="num">1) + U - u))) * pow(p,u)*pow(class="num">1.0-p,(m-class="num">1) + U - u); NewSU = SU + u; NewSD = SD + ((m-class="num">1) + U - u); C+=Fractal(Half,Middle,m,n,s,p,NewSU,NewSD,NewU,NewP); } } if ( (m-class="num">1) + U == class="num">0 ) {
「递归分形里的向下分支与中间态展开」
这段逻辑处理的是价格路径在向下偏离后、以及恰好落在中间位置的两种递归情形。外汇与贵金属杠杆高、跳空频繁,这类分形概率计算仅作路径推演,实盘信号仍需结合结构确认。 先看 case 2 的向下分支:NewU 在原有 U 上加 1,代表向上步数增一;NewP 用 P 乘衰减系数 p,概率随层级递减。NewSU 加 1 而 NewSD 不变,说明累计向上成功次数增加但向下次数未动。 随后构造 Container 实例 ct,LowerMidSDown 用 P*(1.0-p)*(SD+1) 表达「本层向下、下层再向下」的联合概率质量;LowerMidSUp 与 LowerSummProbability 同理分别刻画另一种分支与边际概率。ct 被压入集合 C,再递归调用 Fractal 把新参数传下去,层数越深分支越多。 case 3 触发条件是 U==Middle 且 SU+SD<s,即走到中点但总步数未达标。循环上界取 MathFloor(Half)-1,若大于 0 才展开;NewU 用 -(Half-1)+2*u+U 对称映射左右偏移,NewP 套用组合数乘 p^u*(1-p)^(剩余) 的二项分布权重。每一轮把更新后的 SU、SD 传入 Fractal 继续向下拆,最后 return C 把整棵概率树交回上层。 在 MT5 里把 Factorial 和 pow 换成自写整型阶乘可避免浮点误差;调小 s 会让递归深度陡增,i7 上 s=20 时叶节点可能破万,先打印 C.Size() 看规模再决定要不要剪枝。
NewU = U + class="num">1; NewP = P * p; NewSU = SU + class="num">1; NewSD = SD; Container ct; ct.LowerMidSDown=P*(class="num">1.0 - p)*(SD+class="num">1); ct.LowerMidSUp=P*(class="num">1.0 - p)*SU; ct.LowerSummProbability=P*(class="num">1.0 - p); C+=ct; C+=Fractal(Half,Middle,m,n,s,p,NewSU,NewSD,NewU,NewP); } } if ( U == Middle && SU + SD < s )class=class="str">"cmt">//case class="num">3 { if ( class="type">int(MathFloor(Half))-class="num">1 > class="num">0 ) { for ( class="type">int u=class="num">0 ; u <= class="type">int(MathFloor(Half))-class="num">1; u++ ) { NewU = -(class="type">int(MathFloor(Half))-class="num">1) + class="num">2*u + U; NewP = P * (Factorial(class="type">int(MathFloor(Half))-class="num">1)/(Factorial(u)*Factorial(class="type">int(MathFloor(Half))-class="num">1 - u))) * pow(p,u)*pow(class="num">1.0-p,class="type">int(MathFloor(Half))-class="num">1 - u); NewSU = SU + u; NewSD = SD + (class="type">int(MathFloor(Half))-class="num">1 - u); C+=Fractal(Half,Middle,m,n,s,p,NewSU,NewSD,NewU,NewP); } } } class="kw">return C; }
◍ 用对称分形反推走廊步阶公式
日志跑出来的平均步阶数会收敛到一个整数:当走廊按单位步阶翻倍、n 和 m 都取 1 时,链经过的平均步阶数趋于 4。 这说明较小对称走廊拼成较大对称走廊时,宽度和步阶数各自有一条递推链。 宽度递推是 P[n] = P[n-1] * 2,步阶递推是 S[n] = S[n-1] * 4。 若令 P[0]=1、S[0]=1 并从 0 开始编号,就得到 P[n]=2^n 与 S[n]=4^n,而 4^n 可写成 (2^n)^2,也就是 S = P^2。 换一组参数验证:n=3、m=3 时平均步阶数趋于 9,对应 P[n]=3^n、S[n]=9^n,关系仍是 S=P^2。 外汇与贵金属价格走这种对称分形时波动剧烈、风险极高,但该关系不依赖具体 n 和 m,只要求走廊对称且宽度成整数倍放大。 由此可外推任意放大倍数 K 下的指标:新走廊平均步阶 S = S0 * K^2,平均生存期 T = T0 * K^2(设旧走廊 S0=1),其中 K = P/P0。 在 MT5 里把 n、m 和走廊倍数改掉跑一遍日志,就能确认这条二次依赖是否在你关心的品种上成立。
用整数走廊逼近浮点因子的生存期
前面推导的生存期公式对整数 P 成立,但真实行情里加宽系数 K 往往是浮点。要让公式覆盖实数 K,得借一条已知平均生存期的价格走廊当基准。 假设手里有平均生存期 T 的走廊,它容纳了某个更小走廊的 N 倍宽度,但小走廊生存期未知。套原关系 T = T0 * N^2,反推 T0 = T / N^2,就拿到最小走廊的生存期。 小走廊以点数为单位的宽度 d = P / N。要塞进加宽到 K 倍的走廊,能容下的段数取下整:Smin = MathFloor(K * N)。极限 Lim(N→+∞)[K*N / MathFloor(K*N)] = 1,说明 N 越大,取整丢掉的小数越无关紧要。 若担心截断误差,再算 Smax = MathFloor(K*N)+1 = Smin+1,真实 K*N 必落在二者之间。N 趋于无穷时,这两套只差一段的走廊平均生存期几乎相等,于是用算术平均兜底:T1 = T0 * (Smin^2 + Smax^2) / 2。 拿 N=1000 做第一次验证,替代表达式算出的 T1 与整数公式 T*K^2 结果数字相同;逻辑上 N 更大二者更重合。极限 Lim(N→+∞)[T0*(Smin^2+Smax^2)/2 / (T*K^2)] = 1 从数学上坐实了这一点。 我写了个简单函数,把 N 从 1 扫到整千量级做全区间比对,输出证实:为整数 K 找到的生存期函数,对 0 到 +∞ 内任意正浮点 K 同样适用。这给后续把分形结构铺到实数系数上留了底。