您能用移动平均线做什么呢·进阶篇
(2/3)· 当默认10周期SMA不够用时,如何用双线坡度与ATR通道重构价格边界
「把均线当动态支撑阻力用」
把移动平均线当成会移动的支撑/阻力线,是曲线最直白的用法之一。价格碰到均线但没有越过、在同一侧收盘,就算出一个信号;比如 2 月 17 日那段行情里,向下刺探均线的点出现 3 次,若不过滤就对应一次反向向上信号。 周期越长,均线角度越平、离价越远,被突破和回滚的频率越低,但支撑阻力位的可信度倾向更高。拿 20 周期均线比 3 周期看,回滚次数明显减少,止损可以相应缩窄,代价是信号来得晚、可能漏掉一段潜在利润。 实盘里经常遇到多周期打架:2 月 17 日凌晨 4 点,短周期红线给买、长周期橙线给卖,这时候硬上就容易亏损;但红线若在上午 8 点、10 点、下午 3 点连续给同向信号,就可以在原有仓位上顺势加。外汇和贵金属波动大,这种加仓节奏必须配合仓位上限,否则一次反向逆转就能吞掉前面所有浮盈。 下面这段是 MA-Support 里的主循环,逻辑就是「上一根 K 线实体穿破均线但收回来」才挂箭头。high[i-1]>=均线 且 close/open 都低于均线,判为下穿回滚,箭头挂在 high+ATR/5;反过来 low<=均线 且 close/open 都高于均线,判为上穿回滚,箭头挂在 low-ATR/5。
class=class="str">"cmt">//--- main cycle for(i=start+class="num">3; i<rates_total && !IsStopped(); i++) { ArrowDownBuffer[i]=class="num">0; ArrowUpBuffer[i]=class="num">0; class=class="str">"cmt">//--- if( (high[i-class="num">1]>=extMAData[i-class="num">1] && close[i-class="num">1]<extMAData[i-class="num">1] && open[i-class="num">1]<extMAData[i-class="num">1] ) ) { ArrowDownBuffer[i]=high[i]+extATRData[i]/class="num">5; } else if( (low[i-class="num">1]<=extMAData[i-class="num">1] && close[i-class="num">1]>extMAData[i-class="num">1] && open[i-class="num">1]>extMAData[i-class="num">1] ) ) { ArrowUpBuffer[i]=low[i]-extATRData[i]/class="num">5; } } class=class="str">"cmt">// Main cycle end
◍ 均线坡度的三种量化视角
直线坡度越陡,价格波动往往越快,下一根烛条延续该方向的概率也越高。最朴素的度量就是用均线当前值与若干柱线前的值做差:差为正即上行,差为负即下行。 主回路里 SlopeShift 控制回溯距离,默认取 1;把它加到 2 或 3,能看到完全不同的坡度结构。下面这段是 MA-Slope 指标的核心循环: //--- main cycle for(i=start+SlopeShift*2; i<rates_total && !IsStopped(); i++) { SlopeDownBuffer[i]=0; SlopeUpBuffer[i]=0; slopeIndex=(extMAData[i-1]-extMAData[i-1-SlopeShift]); //--- if( slopeIndex<0 ) { SlopeDownBuffer[i]=slopeIndex; } else if( slopeIndex>0 ) { SlopeUpBuffer[i]=slopeIndex; } } // main cycle 逐行看:循环从 start+SlopeShift*2 起步避免越界;上下行缓冲先清零;slopeIndex 就是均线隔 SlopeShift 根柱的差值;负值写进 SlopeDownBuffer,正值写进 SlopeUpBuffer,零不记录。 把坡度画成直方图后,有三点立刻显出来:一两根柱就反向的波动多半只是噪音,谈趋势反转太早;直方图柱高低于某阈值时,后续大概率是横盘,沿均线方向但坡度小于 2-3 根柱时不值得开仓;趋势段里曲线看着单边,但真实变化率逐根差异很大。 为了避开除零,往分子分母各加 Point()/100 几乎不改变形态,但能保程序不崩。相对指数版本代码如下: //--- main cycle for(i=start+SlopeShift*3; i<rates_total && !IsStopped(); i++) { SlopeDownBuffer[i]=0; SlopeUpBuffer[i]=0; slopeIndex=(extMAData[i-1]-extMAData[i-1-SlopeShift]+Point()/100) /(extMAData[i-2]-extMAData[i-2-SlopeShift]+Point()/100); //--- if( slopeIndex<0 ) { SlopeDownBuffer[i]=slopeIndex; } else if( slopeIndex>0 ) { SlopeUpBuffer[i]=slopeIndex; } } // main cycle 这里 slopeIndex 变成「当期差 / 前期差」的比值,峰值往往卡在走势边界上。把图表左移几根柱,峰值更醒目。 相对指数的峰和其他值悬殊太大,做直方图意义不大,不如二元化。设定 SlopeThreshold,超过就标 1 或 -1,否则不标。SlopeThreshold=5 与 =15 的条纹明显不同,标记点倾向出现在方向变化当根或其后 2-3 根。外汇与贵金属波动剧烈,这类信号仅作概率参考,实盘前请用 MT5 自测统计。 //--- main cycle for(i=start+SlopeShift*3; i<rates_total && !IsStopped(); i++) { SlopeDownBuffer[i]=0; SlopeUpBuffer[i]=0; slopeIndex=(extMAData[i-1]-extMAData[i-1-SlopeShift]+Point()/100) /(extMAData[i-2]-extMAData[i-2-SlopeShift]+Point()/100); //--- if( slopeIndex<=-SlopeThreshold ) { SlopeDownBuffer[i]=-1; } else if( slopeIndex>=SlopeThreshold ) { SlopeUpBuffer[i]=1; } } // Main cycle 阈值比较换成带负号的绝对值判定,命中即写死 ±1,渲染层可轻易换成箭头。
class=class="str">"cmt">//--- main cycle for(i=start+SlopeShift*class="num">2; i<rates_total && !IsStopped(); i++) { SlopeDownBuffer[i]=class="num">0; SlopeUpBuffer[i]=class="num">0; slopeIndex=(extMAData[i-class="num">1]-extMAData[i-class="num">1-SlopeShift]); class=class="str">"cmt">//--- if( slopeIndex<class="num">0 ) { SlopeDownBuffer[i]=slopeIndex; } else if( slopeIndex>class="num">0 ) { SlopeUpBuffer[i]=slopeIndex; } } class=class="str">"cmt">// main cycle class=class="str">"cmt">//--- main cycle for(i=start+SlopeShift*class="num">3; i<rates_total && !IsStopped(); i++) { SlopeDownBuffer[i]=class="num">0; SlopeUpBuffer[i]=class="num">0; slopeIndex=(extMAData[i-class="num">1]-extMAData[i-class="num">1-SlopeShift]+Point()/class="num">100) /(extMAData[i-class="num">2]-extMAData[i-class="num">2-SlopeShift]+Point()/class="num">100); class=class="str">"cmt">//--- if( slopeIndex<class="num">0 ) { SlopeDownBuffer[i]=slopeIndex; } else if( slopeIndex>class="num">0 ) { SlopeUpBuffer[i]=slopeIndex; } } class=class="str">"cmt">// main cycle class=class="str">"cmt">//--- main cycle for(i=start+SlopeShift*class="num">3; i<rates_total && !IsStopped(); i++) { SlopeDownBuffer[i]=class="num">0; SlopeUpBuffer[i]=class="num">0; slopeIndex=(extMAData[i-class="num">1]-extMAData[i-class="num">1-SlopeShift]+Point()/class="num">100) /(extMAData[i-class="num">2]-extMAData[i-class="num">2-SlopeShift]+Point()/class="num">100); class=class="str">"cmt">//--- if( slopeIndex<=-SlopeThreshold ) { SlopeDownBuffer[i]=-class="num">1; } else if( slopeIndex>=SlopeThreshold ) { SlopeUpBuffer[i]=class="num">1; } } class=class="str">"cmt">// Main cycle
用单均线和级别包搭通道做逆势与突破
在 MT5 里建通道不用另写指标,直接加载标准 MA,再手动加水平级别即可。关键是每个时间帧的级别数值不同,切换周期会丢失,所以把级别按品种打包保存最省事。以 JPY 为例,H1 上能看到内部窄通道和稍大通道共存,触及级别并回滚的烛条就是逆势信号。
- 月 22 日 H1 图表里,价格触到上轨回滚,信号烛条中段或尾端可下空单;若回滚后入场,挂单价可放在信号烛条最低 115.100,止损 115.265,直接目标看均线、最终目标看对侧边界。同一日 9 时烛条收在窄通道上边界之上,两根看涨烛条收高于均线、看跌烛条未破下边界,且 MA 斜率明显走平,这构成突破做多信号,入场可算在 115.230、止损 114.570,尾随停止也能按烛条结构来设。
周期切换会改变主通道:D1 上 ±50 几乎看不见,±300 和 ±1500 成操作通道,月线偶尔给信号但最明显那层才是主通道;M1–M15 适合最内部通道。调级别大小的原则是——切到目标周期,选让接触点最少、振幅最大的数值,粗略办法是量当前周期基础调整幅度再除以 2,后续可微调。外汇与贵金属杠杆高,通道触碰回滚只是概率倾向,实盘前请在 MT5 历史数据里复验级别与止损位。
「用双均线加 ATR 画出自适应通道」
前文那种固定通道得手工调大小,且边界值不进指标缓冲区,程序里很难直接抓。换思路:拿周期 3 的两条移动平均线,一条绑 high、一条绑 low,再各自沿方向偏移 5 周期 ATR 的距离,通道就成型了。 这套 ATR3x5 不挑品种,突破少见,价格更多是在通道内回滚。代码里 DistanceCoefficient 是外参,能按品种波动改偏移倍数;实测系数超过 2 时箭头几乎全消失,等于没信号,没必要设那么大。 下方主循环就是边界触发的核心。上轨用前高刺穿但收盘收回判定下箭头,下轨用前低跌破但收盘拉回判定上箭头,箭头位置再叠一点 ATR/5 的偏移避免贴价。 外汇和贵金属杠杆高、滑点跳空频繁,这类通道只作回调参考,信号消失时别硬等成交。
class=class="str">"cmt">//--- main cycle for(i=start+class="num">3; i<rates_total && !IsStopped(); i++) { ArrowDownBuffer[i]=class="num">0; ArrowUpBuffer[i]=class="num">0; class=class="str">"cmt">//--- MAUpBuffer[i]=extMAUpData[i]+extATRData[i]*DistanceCoefficient; MADownBuffer[i]=extMADownData[i]-extATRData[i]*DistanceCoefficient; if( (high[i-class="num">1]>=MAUpBuffer[i-class="num">1] && close[i-class="num">1]<MAUpBuffer[i-class="num">1]) ||( close[i-class="num">2]>MAUpBuffer[i-class="num">2] && close[i-class="num">1]<MAUpBuffer[i-class="num">1] ) ) { ArrowDownBuffer[i]=high[i]+extATRData[i]/class="num">5; } else if( (low[i-class="num">1]<=MADownBuffer[i-class="num">1] && close[i-class="num">1]>MADownBuffer[i-class="num">1]) ||( close[i-class="num">2]<MADownBuffer[i-class="num">2] &&close[i-class="num">1]>MADownBuffer[i-class="num">1] ) ) { ArrowUpBuffer[i]=low[i]-extATRData[i]/class="num">5; } }class=class="str">"cmt">// main cycle