自适应指标(基础篇)
「自适应指标到底在调什么」
MT5 里的自适应指标,核心不是换指标名字,而是让参数随行情波动状态自动重算。典型做法是读取当前波动率或趋势强度,再反推周期长度、平滑系数,避免固定窗口在震荡与趋势切换时同时失效。 以一段常见的自适应均线为例,它用价格变化的标准差来缩放周期,而不是写死 14 或 20。读者可以直接在 MT5 新建脚本把下面代码贴进去,看不同品种周期被压到多少。 外汇与贵金属杠杆高、跳空频繁,自适应参数只是降低钝化概率,不保证信号方向,实盘前务必用历史数据跑一遍。
class="type">class="kw">double AdaptivePeriod(class="type">class="kw">double price[], class="type">int max_period) { class="type">class="kw">double diff_sum = class="num">0.0; for(class="type">int i=class="num">1; i<max_period; i++) diff_sum += MathAbs(price[i]-price[i-class="num">1]); class="type">class="kw">double avg_diff = diff_sum / max_period; class="type">class="kw">double vol = MathAbs(price[class="num">0]-price[max_period-class="num">1]) / avg_diff; class="kw">return MathMin(max_period, MathMax(class="num">2, (class="type">int)vol)); }
◍ 恒定比率与反馈环的差别
传统技术指标对输入信号采用恒定比率处理,比率一旦设定就不会随行情演化而调整,横盘和趋势段被一视同仁。 自适应指标在输入与输出之间引入反馈环,让比率能跟着当前市况走。本质上它仍是线性指标,只是系数随时间自适应变化,相当于指标自己调参。 外汇和贵金属波动剧烈,这类反馈机制对过滤震荡噪音可能比固定均线更有用,但高杠杆下误判风险同样被放大。 实现层最常用的适应算法大多建立在最小二乘法变体上,选哪种要看指标打算捕捉什么特征。
拿误差喂指标,喂出了个假自适应
做自适应指标最直觉的切入点,就是拿指标在近期柱线上的误差去修正下一次输出。设 Indicator[i] 是第 i 根柱线的值,误差写成 Error[i] = price[i] - Indicator[i],下一次计数时把这块误差补回去,或者取最近若干误差的平均、做指数平滑,逻辑上都顺。 实际在 MT5 里套了个带误差补偿的模板跑出来,图表上和简单移动平均线(红线)叠在一起看挺像样。但拆开算就知道,这玩意儿根本不是自适应——它只是个权重系数被隐性写死的线性指标。 举个周期 3 的例子:取最后三个误差平均去补值,展开后 Indicator[0] = (3*price[0] + 5*price[1] + 4*price[2] + 0*price[3] - 2*price[4] - 1*price[5])/9。系数全定死了,市场状态切换时它不会自己变。结论很直白:单靠处理历史误差,指标倾向还是线性的,自适应大概率没戏。 下面这段是当时跑的通达逻辑,核心在把当前误差按 NumErrors 分三种情况滚进缓冲区,最后 buffer[i]=sum+error 把误差叠回指标值。外汇和贵金属波动跳变多,这种隐性线性权重在单边行情里滞后风险高,开 MT5 把 NumErrors 从 0 调到 3 对比曲线就能验证。
class="type">class="kw">double sum=class="num">0; for(class="type">int j=class="num">0; j<size; j++) sum=sum+coeff[j]*price[i+j];class=class="str">"cmt">//Calculate the indicator value if(i>class="num">0) { class="type">class="kw">double cur_error=price[i]-sum;class=class="str">"cmt">//Current error if(NumErrors==class="num">0) cur_error=(error+cur_error)/class="num">2; if(NumErrors==class="num">1) error=cur_error/class="num">2; if(NumErrors>class="num">1) { for(class="type">int j=NumErrors-class="num">1; j>class="num">0; j--) errors[j]=errors[j-class="num">1]; errors[class="num">0]=cur_error; cur_error=class="num">0; for(class="type">int j=class="num">0; j<NumErrors; j++) cur_error=cur_error+errors[j]; error=cur_error/NumErrors; } } buffer[i]=sum+error;class=class="str">"cmt">//Indicator value considering the error
「拉普拉斯平滑在均线上的尴尬实验」
拉普拉斯曾抛出一个经典疑问:连续 1000 天看到日出,第 1001 天太阳升起的信心有多大?挪到交易里就是——9 笔交易 6 笔盈利,胜率是多少?朴素算法是 6/9,但对未来一笔做平滑时,分母加 1,分子按盈/亏两种可能取平均,得到 (6+1)/(9+1) 与 6/(9+1) 的均值,即 6.5/10=0.65,略低于原始 0.667。这种拉普拉斯平滑常用于二分类,但塞进指标却出了岔子。 我们假想价格流里存在一个「虚数价格」参与简单移动平均计算。SMA 原方程不变,加入虚数后平均值变为含 price_imag 的项;问题在于虚数价格本身并不稳定,且其表达式随序列平移会简化成 price[1] 比率为 1 的退化形式,完全没起到稳定作用。 不过这次失败反倒给出新思路:设指标周期 iPeriod,对 N=1…iPeriod 逐一算 SL 值再取平均,得到的读数可理解为「天真的预测(过去=未来)加略微弱化的线性趋势」。外汇与贵金属波动剧烈,这类基于历史均值的派生指标仅作概率参考,实盘须警惕滑点与跳空高风险。 自适应还没做出来,这趟试探算惨败。先停手缓一缓,下回换个结构重做自适应指标,不然连文章名都得改。