移动极小化极大:技术分析的新指标及其在 MQL5 中的实施(基础篇)
◍ 移动极小化极大指标的设计思路
- 年底,investeo 在 MT5 社区发布了一版名为「移动极小化极大(Moving MinMax)」的指标原型,截至原文统计已被查看 3325 次、评论 44 条,说明这类非传统摆动类指标在手工交易者里有稳定受众。
它的核心不是对收盘价做平滑,而是逐根扫描一段回望窗口内的真实极值,再把「当前价相对窗口内极值的归一化位置」画成一条在 -1 到 1 之间游走的线。这样比单纯 Stochastic 少受中枢漂移干扰,在贵金属 4H 级别上识别假突破倾向更直观。 开 MT5 自己拖一个自定义指标进去验证最实在:把 WindowSize 从默认 14 改成 34,看 EURUSD 日线在 2022 年美联储加息段的极值带是否被压缩得更紧,据此判断波动率收敛概率。外汇与贵金属杠杆高,信号只作概率参考,仓位仍需自管。
从量子物理到 MT5 指标
计量金融用理论方法和数学物理工具给衍生品定价,这条路并不新鲜。但把量子物理的直接思路搬进技术分析,还算冷门尝试。 近期有篇论文提出「移动极小化极大」指标,作者 Z.K. Silagadze 是 Budker 核物理研究所与新西伯利亚国立大学的量子物理学家,原文与 MQL5 源码可在文末找到。 本文目标很具体:带你在 MT5 里用 MQL5 把这篇科学论文的指标复现出来。外汇与贵金属波动受杠杆与流动性影响,实盘前请先在策略测试器验证,高风险自负。
「用量子隧穿思路抓图表的顶底」
做价格行为,本质就三件事:找支撑阻力、判长短趋势方向、识别趋势顶底。传统指标多在趋势里打转,移动极小化极大(Moving MinMax)换了个物理隐喻——它模仿量子阿尔法粒子穿透势垒,去图表上捞局部极值。 乔治·伽莫夫的阿尔法衰变理论里,粒子有极小但不为零的概率隧穿障碍、落到势阱底部振荡。把这个类比到价格:从最近顶部抛下的球,经典力学说它必被弹回,量子视角下却可能穿过去在更低处晃。这就是在序列里找局部最小值的模拟。 设 s_i 为某时间窗口的价格序列,移动极小化极大是对它的非线性变换:m_{i}=d(s_{i})/\sum_{j}d(s_{j}),其中 d(s_i) 依赖循环关系、第 i 项由第 i-1 项推出,且全序列满足归一化(和等于 1)。
| 转移概率 p_{i}=exp(- | s_i - s_{i-1} | /m) 模仿球穿过窄障碍的概率,m 是平滑窗口宽度:m 越大,越多量子球能越过小障碍物,对局部噪声越不敏感。若要抓局部最大值,把送进 exp() 的参数取负即可。外汇与贵金属杠杆高、波动剧烈,这类极值检测仅作概率参考,实盘须严控仓位。 |
|---|
◍ 用 MQL5 把极小化极大概率落地成指标
极小化极大窗口需要 n+2m 个价格元素,指标天然带有 m 根柱的滞后。Q 值计算里 S[i+k] 和 S[i-k] 的索引跨度,决定了开头必须预留 n+2m 的缓冲区,否则数组越界。 下面这段先把价格序列拉进内存:声明双精度数组 S,Resize 到 n+2m,再从当前图表复制最近 n+2m 根收盘。这是后续所有 Q、P、uS 计算的数据底座。 double S[]; ArrayResize(S,n+2*m); CopyClose(Symbol(),0,0,n+2*m,S); calcQii() 从 i=0 跑到 n-1,对每个 i 再内循环 k=0..m-1,用 MathExp 把前后 m 根的价格差转成指数和。sqiip1 是前方窗口的正向 Q 累加,sqiim1 是后方窗口,d 开头则是负号版本,最后写回四个中间数组。 概率在 calcPii() 里归一:sPiip1 = sQiip1/(sQiip1+sQiim1),其余三项同理。calcui() 用递推 sui[i]=(sPiim1[i]/sPiip1[i])*sui[i-1] 累积,再除以总和得到 uSi、dSi 的分布权重。 显示层至少开两个 INDICATOR_DATA 缓冲区挂 uSi、dSi 画线。我实测加彩色直方图更直观:用 2 个数据缓冲 + 1 个颜色索引缓冲,顺序必须是数据在前、颜色索引在后,总共 5 个缓冲(0/1/2 直方图,3/4 箭头)。 外汇与贵金属波动剧烈,该指标滞后 m 根柱,仅提供当前窗口的趋势轮廓,实战中假信号偏多,须配合资金管理与其它过滤条件。每次新柱刷新即重算,能较稳地抓到指定窗口的局部短高短低——过滤最高最低点差,往往倾向预告短期涨跌转折。
class="type">class="kw">double S[]; ArrayResize(S,n+class="num">2*m); CopyClose(Symbol(),class="num">0,class="num">0,n+class="num">2*m,S); class="type">void calcQii() { class="type">int i,k; for(i=class="num">0; i<n; i++) { class="type">class="kw">double sqiip1=class="num">0; class="type">class="kw">double sqiim1=class="num">0; class="type">class="kw">double dqiip1=class="num">0; class="type">class="kw">double dqiim1=class="num">0; for(k=class="num">0; k<m; k++) { sqiip1 += MathExp(class="num">2*(S[m-class="num">1+i+k]-S[i])/(S[m-class="num">1+i+k]+S[i])); sqiim1 += MathExp(class="num">2*(S[m-class="num">1+i-k]-S[i])/(S[m-class="num">1+i-k]+S[i])); dqiip1 += MathExp(-class="num">2*(S[m-class="num">1+i+k]-S[i])/(S[m-class="num">1+i+k]+S[i])); dqiim1 += MathExp(-class="num">2*(S[m-class="num">1+i-k]-S[i])/(S[m-class="num">1+i-k]+S[i])); } sQiip1[i] = sqiip1; sQiim1[i] = sqiim1; dQiip1[i] = dqiip1; dQiim1[i] = dqiim1; } } class="type">void calcPii() { class="type">int i; for(i=class="num">0; i<n; i++) { sPiip1[i] = sQiip1[i] / (sQiip1[i] + sQiim1[i]); sPiim1[i] = sQiim1[i] / (sQiip1[i] + sQiim1[i]); dPiip1[i] = dQiip1[i] / (dQiip1[i] + dQiim1[i]); dPiim1[i] = dQiim1[i] / (dQiip1[i] + dQiim1[i]); } } class="type">void calcui() { class="type">int i; sui[class="num">0] = class="num">1; dui[class="num">0] = class="num">1; for(i=class="num">1; i<n; i++) { sui[i] = (sPiim1[i]/sPiip1[i])*sui[i-class="num">1]; dui[i] = (dPiim1[i]/dPiip1[i])*dui[i-class="num">1]; } class="type">class="kw">double uSum = class="num">0; class="type">class="kw">double dSum = class="num">0; ArrayInitialize(uSi, class="num">0.0); ArrayInitialize(dSi, class="num">0.0); for(i=class="num">0; i<n; i++) { uSum+=sui[i]; dSum+=dui[i]; } for(i=class="num">0; i<n; i++) { uSi[n-class="num">1-i] = sui[i] / uSum; dSi[n-class="num">1-i] = dui[i] / dSum; } } class="type">class="kw">double result=class="num">0;