☰
通达信主图自动标注指标:无未来函数识别MACD背离与金叉死叉
2026/10/8 16:20:10 网站建设 项目流程

盯盘盯到眼神涣散、复盘复盘到鼠标冒烟的日子,我过了大概两年多。形态识别这件事,看多了真的会麻:金叉死叉来回切换、MACD柱子翻红翻绿、缩量放量堆在一起,每次都得把副图指标切来切去,再回到主图上手动标记位置。后来我干脆花了两周时间写了一个通达信主图自动标注指标,让底背离、顶背离、金叉死叉、缩倍量这些信号直接显示在K线图上,一眼扫过去就清楚。这篇内容把设计思路、无未来函数的写法、完整源码和排错经验都整理出来了,适合盯盘时间有限、想减少主观判断、或者刚学形态但总看错位置的朋友,你可以直接复制到通达信里跑起来看效果。

1. 主图自动标注公式,到底在解决什么问题

1.1 手工标注的三个痛点,戳中你就该看下去

先说最现实的问题:手工复盘形态,到底哪里烦。

第一个痛点是漏看。一张日线图上同时存在价格均线、成交量、MACD柱,你要在某一根K线上同时确认“价格创低点但MACD没创新低”,不把副图拉大、不来回切换光标位置,肉眼很容易漏掉。特别是背离这种东西,属于跨多个指标块的结构性比较,看漏一两次很正常。

第二个痛点是主观不一致。同一段双底,昨天你觉得是W底,今天再看又觉得只是普通反弹,不同时间打开同一张图得出的结论不一样。形态识别本身就有模糊性,人脑的判断基准不稳定,这是天然劣势。

第三个痛点是时间成本。一个票复盘5分钟,一百个票就是五百分钟,而且大部分时间花在“找”而不是“判”。信号明明在那里,但你得一个个翻。

自动标注主图解决的就是这三件事:把模糊的视觉判断改成明确的规则判断,把“人找信号”变成“信号找人”,把跨指标的复杂比较压缩成一行文字、一个图标。你做的是写规则,剩下的交给公式去算,规则一致了,主观偏差自然就消失了。

1.2 主图公式和副图指标的根本区别

很多人第一次写主图指标,会直接照搬副图写法:算完MACD,然后画线、画柱状图,出来的效果无非是在主图上多叠了几条曲线。这其实没有理解主图标注公式的核心逻辑。

副图指标的核心任务是展示连续数值,比如DIF、DEA、KDJ的K值D值,你通过曲线的相对位置和形态去做判断;主图标注公式的核心任务是把离散事件变成可视化标记。它更关心的是“什么时候发生了金叉”“什么时候出现了背离”,而不是“DIF现在等于多少”。所以主图公式里绘图函数才是主角,DRAWTEXT负责写文字,DRAWICON负责画图标,STICKLINE负责画柱段,DRAWLINE负责连线,所有的算法运算都只是为这些绘图函数服务。

这个定位想清楚之后,公式结构就不会写歪。我见过不少人把大段指标计算堆进主图,结果又是均线又是通道又是MACD柱,主图乱成蜘蛛网,信号反而看不清楚。主图自动标注讲究的是克制:只把最终结论类的事件展示出来,中间过程一律不画。

2. 无未来函数的形态识别思路与核心函数

2.1 未来函数是什么,为什么信号会“漂移”

如果要问自动标注指标最容易翻车的地方在哪,答案一定是未来函数。这个概念新手容易忽略,老手也偶尔踩坑。

未来函数,简单说就是“用未来数据改变过去判断”的函数。通达信里的BACKSET就是典型:BACKSET(条件,N)会把条件成立之前N根K线全部标记为1。比如第100根K线出现底部信号,用了BACKSET之后,第95根到第99根也会显示这个信号。复盘的时候看历史信号完美得一塌糊涂,实盘的时候信号根本没有提前出现,等你真按历史信号去操作,亏都亏完了。

更隐蔽的还有ZIG、PEAK、TROUGH这一类,它们需要先知道整段走势的转折点才能确定波峰波谷,所以天然带未来属性。HHVBARS和LLVBARS虽然本身是固定窗口的回看函数,但如果窗口设置太长,在新数据加入时历史高点的位置也可能发生跳变,使用时要非常谨慎。

判断你的公式有没有未来函数,最直接的办法是删掉最新的几根K线数据,看历史信号位置有没有变化。我实测下来,只要信号会漂移、会消失,十有八九就是未来函数在作怪。

2.2 无未来写法:只认REF和BARSLAST

无未来函数的写法本质上只有一条原则:只用“已经发生”的数据,只用“固定回看窗口”的数据,不依赖整段走势的最终形态。

REF是回看指定周期数的历史值,比如REF(CLOSE,5)取5根K线前的收盘价,这是纯历史数据,安全。BARSLAST是计算某个条件上一次满足到现在隔了多少根K线,比如BARSLAST(CROSS(MA5,MA10)),返回0表示当前就是金叉,返回3表示金叉已经过去3根K线了,这也是纯历史数据,安全。HHV(HIGH,20)和LLV(LOW,20)分别是最近20根K线的最高价和最低价,窗口固定,同样安全。

用这些函数构建形态识别的思路就是:先锁定一个“事件锚点”,再往前回溯若干个周期,然后比较两段的数据关系。以MACD底背离为例,锚点就是“DIF上穿DEA”这个金叉瞬间,然后向前找上一次金叉的位置,比较两次金叉点的价格和DIF。整个过程完全依赖已经收盘的K线,不涉及任何未来信息。

这里要特别强调一点:“无未来”不等同于“信号提前”。它保证的是信号一旦出现就不会漂移,但形态确认本身需要等到K线走完,有些结构类信号甚至要等后面一两根K线做确认,这是无未来写法的正常代价,不能反过来用BACKSET去“美化”信号。

2.3 标形态必会的函数清单

表格虽然枯燥,但函数这玩意儿列出来查起来最快。上面这些是我写自动标注公式最常用的几个绘图和控制函数,全都验证过。

函数作用典型用法注意事项
DRAWTEXT在指定位置显示文字DRAWTEXT(金叉,LOW*0.98,'金叉')条件为真时只在该K线显示
DRAWICON在指定位置画图标DRAWICON(底背离,LOW,1)图标编号有范围,不同版本样式不同
STICKLINE画柱状线段STICKLINE(底背离,LOW,LOW*0.95,3,0)第4参数是柱宽像素,第5参数0实心1空心
FILTER信号过滤FILTER(金叉,5)信号出现后5周期内不再重复输出
BARSLAST条件最近满足位置BARSLAST(CROSS(DIF,DEA))返回0表示当前K线满足条件
DRAWLINE连接两个条件点DRAWLINE(条件1,价格1,条件2,价格2,1)会从条件1位置连到条件2位置

DRAWTEXT和DRAWICON的坐标参数特别关键,很多人画不出来就是栽在坐标上。你写DRAWTEXT(金叉,LOW,'金叉'),文字会压在最低价的位置,K线实体和影线一多就遮住了,所以实际用的都是LOW0.98或HIGH1.02之类的偏移坐标,让文字浮在K线外面。DRAWICON也一样,图标坐标要留出空间,不然出来的效果就是K线和图标糊在一起,完全没法看。

3. 从零手写自动标注主图:完整源码拆解

3.1 第一步:画趋势骨架与高低点标记

写主图指标之前先把骨架搭好。骨架的作用不是输出最终信号,而是给后续标注提供参考系,同时把当前趋势状态可视化。

{========== 主图自动标注形态 骨架部分 ==========} N:=20; MA5:MA(CLOSE,5),COLORWHITE; MA10:MA(CLOSE,10),COLORYELLOW; MA20:MA(CLOSE,20),COLORMAGENTA; 前高:=HHV(HIGH,N); 前低:=LLV(LOW,N); 创新高:=HIGH>=前高 AND HIGH=HHV(HIGH,20); 创新低:=LOW<=前低 AND LOW=LLV(LOW,10); DRAWICON(创新高,HIGH,2); DRAWICON(创新低,LOW,1);

这里面N是高低点回溯窗口,默认20根K线。20这个值是我在日线上反复试出来的均衡点:太小的话一段趋势里会打出超多个高低点,看图全是图标;太大的话信号太稀疏,一周可能都触发不了一次。如果是日内短线,N建议缩到10到15,后面第4章会专门讲参数问题。

创新高条件我特意加了HIGH=HHV(HIGH,20)这个等式,意思是“当前K线的最高价等于最近20根的最高价”才算创新高,这样能过滤掉那种盘中冲高但收盘回落的假突破。如果你只想标记真正的收盘突破,可以把比较基准换成CLOSE,或者把HHV窗口改成你想要的周期。

3.2 第二步:金叉死叉自动标注

骨架搭好之后,加金叉死叉标注。金叉死叉是最基础的形态信号,适合拿来练手DRAWTEXT和DRAWICON的坐标控制。

{===== 金叉死叉标注 =====} MA5:=MA(CLOSE,5); MA10:=MA(CLOSE,10); 金叉:=CROSS(MA5,MA10); 死叉:=CROSS(MA10,MA5); 金叉过滤:=FILTER(金叉,3); 死叉过滤:=FILTER(死叉,3); DRAWTEXT(金叉过滤,LOW*0.98,'金叉'),COLORRED; DRAWTEXT(死叉过滤,HIGH*1.02,'死叉'),COLORGREEN; DRAWICON(金叉过滤,LOW*0.95,1); DRAWICON(死叉过滤,HIGH*1.05,2);

FILTER(金叉,3)的意思是金叉出现之后3个周期内不再重复输出金叉信号。这在实际行情里非常重要:均线粘合的时候短周期均线可能来回穿越,金叉死叉连续触发,如果不加过滤,图上会像弹幕一样铺满文字。3个周期的过滤足够滤掉大部分黏连信号,又不会让有效信号被过滤掉。

文字坐标这块,我在LOW下方0.98倍的位置写“金叉”,在HIGH上方1.02倍位置写“死叉”,这样文字不会遮挡K线实体。图标我放在了更外侧一点,用0.95和1.05两个系数,让图标和文字错开位置,不会叠在一起。

3.3 第三步:MACD底背离与顶背离自动标注

这一步是全文的核心,也是当初写这套公式花最多时间调试的部分。MACD背离的自动识别,难点在于如何用无未来写法定位“前一次金叉”和“前一次死叉”。

直接给代码,逐行解释。

{===== MACD顶底背离自动标注 =====} DIF:=(EMA(CLOSE,12)-EMA(CLOSE,26)); DEA:=EMA(DIF,9); 金叉:=CROSS(DIF,DEA); 死叉:=CROSS(DEA,DIF); 近金叉:=BARSLAST(金叉); 远金叉:=REF(BARSLAST(金叉),近金叉+1); 当前金叉价:=REF(CLOSE,近金叉); 当前金叉DIF:=REF(DIF,近金叉); 前次金叉价:=REF(CLOSE,近金叉+远金叉+1); 前次金叉DIF:=REF(DIF,近金叉+远金叉+1); 底背离:=金叉 AND 当前金叉价<前次金叉价 AND 当前金叉DIF>前次金叉DIF; 近死叉:=BARSLAST(死叉); 远死叉:=REF(BARSLAST(死叉),近死叉+1); 当前死叉价:=REF(CLOSE,近死叉); 当前死叉DIF:=REF(DIF,近死叉); 前次死叉价:=REF(CLOSE,近死叉+远死叉+1); 前次死叉DIF:=REF(DIF,近死叉+远死叉+1); 顶背离:=死叉 AND 当前死叉价>前次死叉价 AND 当前死叉DIF<前次死叉DIF; 底背离F:=FILTER(底背离,5); 顶背离F:=FILTER(顶背离,5); DRAWTEXT(底背离F,LOW*0.95,'底背离'),COLORRED; DRAWTEXT(顶背离F,HIGH*1.05,'顶背离'),COLORGREEN; DRAWICON(底背离F,LOW*0.90,1); DRAWICON(顶背离F,HIGH*1.10,2);

逻辑链条是这样的:当DIF和DEA在当前K线发生金叉时,用BARSLAST(金叉)得到当前K线距离这个金叉的周期数,此时BARSLAST返回0,说明金叉就在本根。然后我用REF(BARSLAST(金叉),近金叉+1)去取“上一次金叉距离上上根K线有多远”,也就是往回数到当前金叉的前一根,再计算那根K线到前一次金叉的距离。这样近金叉和远金叉两个数加起来,就能从当前K线准确回推到前一次金叉的位置。

为什么用金叉做底背离的锚点而不是用MACD柱翻红?因为MACD柱每根K线都在变化,用它做锚点,柱从绿变红的那一刻可能有连续两根都满足条件,锚点不稳定;金叉是一个单点事件,一个位置只触发一次,锚点干净利落。顶背离我用死叉做锚点,因为顶背离对应的结构转折发生在动能衰竭的死叉阶段,逻辑是对称的。

比较时我用的是前后两次金叉点的收盘价和DIF值。价格比较用CLOSE不用LOW或HIGH,是因为收盘价是已经确认的一致基准,影线容易被个别极端K线干扰。DIF的比较直接反映动能:价格创新低但DIF没有创新低,说明下跌动能在衰竭,底背离成立;价格创新高但DIF没有创新高,说明上涨动能在衰减,顶背离成立。

这套代码跑在历史数据上不会漂移,因为每一步都只用已经发生的K线数据。实测下来底背离的信号会有1根K线的确认延迟,这是无未来写法的正常现象,千万不要为了消除延迟去用BACKSET。

3.4 第四步:缩量放量事件标注与信号过滤

背离和均线金叉属于结构信号,量能属于事件信号。把量能事件也标出来,配合结构信号用,能过滤掉一大批假信号。

{===== 量能异常标注 =====} 缩半量:=VOL<REF(VOL,1)*0.5 AND CLOSE>OPEN AND VOL<HHV(VOL,20); 倍量:=VOL>=REF(VOL,1)*2 AND CLOSE>OPEN; DRAWTEXT(缩半量,LOW*0.88,'缩量'),COLORCYAN; DRAWTEXT(倍量,HIGH*1.08,'倍量'),COLORMAGENTA;

缩半量条件里我加了CLOSE>OPEN,要求当天收阳,因为下跌途中的缩量也经常出现,但那种缩量只是没人卖,不代表有人愿意买,参考价值不大。同时我用VOL<HHV(VOL,20)限制了它必须创20日内量能新低,这样筛选出来的是真正的地量。倍量条件我只要求相对昨日放量2倍以上且收阳,放量突破的时候看到“倍量”两个字的概率明显增加。

量能标注配合背离信号有个经典用法:底背离出现的当根如果同时出现缩量,说明抛压已经衰竭,背离的可靠性大幅提升;顶背离出现的当根如果伴随倍量阴线,说明有资金在出货,则更要警惕。这就是我说的信号过滤思路,第4章会展开讲。

4. 参数调优、误报过滤与公式瘦身

4.1 不同周期的参数怎么选

同样的公式在不同周期上参数不能一刀切,尤其是MACD和高低点回溯窗口。我实测下来的经验参数放到下面这张表里,供你参考。

使用周期高低点窗口NMACD快慢线信号过滤周期适用场景
1分钟/5分钟日内10-155,13,53-5期货日内高低点波段、分时短线
15分钟/30分钟15-208,17,95日内波段、短线进出
日线20-3012,26,95-8常规日线复盘、波段选股
周线30-4012,26,98中期趋势判断、大级别背离

日内周期最大的问题是默认MACD参数太钝,12,26,9放在1分钟图上,DIF和DEA的来回穿越频率低得可怜,可能一整天都等不到一次金叉。我实际测下来,1分钟和5分钟周期用5,13,5这类缩短参数效果更合适,信号出现的节奏跟盘口节奏能对上。高低点窗口N在日内也一定要缩,不然日内价格来回震荡,20根K线的前高前低早就被突破又突破,图标会打成一串。

日线周期反而是最省心的,12,26,9就是MACD经典参数,高低点窗口20也足够覆盖一波日线级别的波段。周线周期高低点窗口建议放到30到40,周线本身K线数量少,窗口太小的话找出来的高低点都是中级别波动内的临时转折,不具备参考意义。

4.2 三招压住误报率

误报率是自动标注公式能不能实盘用的关键。我总结出三招,按效果排序,你可以在公式里叠加使用。

第一招是量能确认。以底背离为例,在原始底背离条件后面追加缩量条件。下跌末端出现缩量说明砸盘力量已经减弱,背离的含金量远高于带量下跌中的背离。代码写成底背离:=金叉 AND 当前金叉价<前次金叉价 AND 当前金叉DIF>前次金叉DIF AND VOL<REF(VOL,1) AND REF(VOL,1)>REF(VOL,2);意思就是金叉当天缩量,而且不是突然的偶发缩量,是连续缩量收敛的状态。

第二招是趋势过滤。我把趋势状态定义成20日均线的斜率方向,让底背离只在下跌趋势中出现,让顶背离只在上升趋势中出现。看似奇怪,实则有逻辑:下跌趋势中的底背离才是真正意义上的底部信号,上升趋势中的DIF短暂下穿DEA再上穿很难构成结构级别的大底;同理,顶背离挂在上升趋势里才有参考价值。

趋势向上:=MA(CLOSE,20)>REF(MA(CLOSE,20),3); 趋势向下:=MA(CLOSE,20)<REF(MA(CLOSE,20),3); 底背离F:=FILTER(底背离 AND 趋势向下,5); 顶背离F:=FILTER(顶背离 AND 趋势向上,5);

第三招是限制信号密度。FILTER(条件,5)之后,同一个方向上5根K线内最多出一次信号,宁可少标也不让它反复横跳。信号太密的公式看起来热闹,实际决策时反而不知道听谁的,这一点是在实测里踩出来的教训。

4.3 公式卡顿和后处理

主图公式的卡顿往往不是因为算法复杂,而是因为绘图语句太多。我测过,一个主图公式里挂30个DRAWTEXT,在5000根K线数据上加载大概需要0.5秒;如果把绘图语句堆到100个以上,加载时间直接翻倍,翻页的时候肉眼可见地卡。

解决办法有三个方向。第一,减少绘图函数调用次数,把多个信号合并到同一个DRAWTEXT里去,比如用字符串拼接把“倍量突破”和“金叉”写在同一个位置;第二,用FILTER控制输出密度,避免无意义的重复绘图;第三,删掉公式里调试用的临时输出,很多人在调试阶段习惯性地写一堆临时变量和画线语句,改完逻辑就忘了删,这是卡顿的隐形元凶。

另外提一个很容易被忽略的问题:跨周期引用。如果你在分钟图上用#DAY或者#WEEK引用日线数据,通达信每次刷新都要重新对齐两个周期的K线数据,几百只股票同时刷的时候性能下降会非常明显。不是必须用跨周期就别用,手动切到目标周期看效果更稳妥。

5. 常见问题排查与选股联动

5.1 标注晚一根K线是怎么回事

最早写完这套公式,我在实盘翻页的时候总觉得信号比感觉上晚了一根K线,后来想明白了:DRAWTEXT的条件是当根K线收盘以后才成立的。比如金叉信号,盘中DIF和DEA可能已经在纠缠,但只有等到收盘确立CROSS,文字才会显示,你看到的时候自然就是“晚”了。

这种情况怎么处理?如果你希望信号更快显示,可以用前一根收盘数据来做条件,比如把金叉条件改成REF(CROSS(DIF,DEA),1),这样信号会在条件成立的后一根K线开盘时就显示,但代价是信号整体后移一根,并不会“更早”。

我自己的做法是接受这个延迟,并且在公式里加一个确认偏移参数,默认等于1。也就是说,我在信号成立当根不画,故意等到下一根K线开盘再画,用多等一根的代价换信号的稳定性。道理很简单:当根收盘确认的信号,收盘价本身已经定格,不会盘中反复消失,多等一根的延迟对日线级别操作几乎没有影响,对日内操作也只需要习惯开盘一瞬间的确认。

5.2 历史信号一刷新就变,怎么揪出未来函数

这是自动标注公式最隐蔽的坑,信号刷新后变了位置,基本可以断定公式里存在未来函数。

排查步骤依次来。第一步,把公式源码复制到记事本,搜索这几个关键词:BACKSET、ZIG、PEAK、TROUGH、HHVBARS、LLVBARS。出现任何一个都要高度警惕。第二步,手动删掉最新3根K线数据,再看之前的信号位置有没有变化。有变化就是未来函数在作怪,没变化基本可以放心。第三步,盘中刷新看信号行为,如果信号在盘中频繁出现又消失,大概率也是未来函数,因为实时行情下未来数据还没到齐,信号只能反复横跳。

我自己踩过的典型例子是用HHVBARS判断突破新高。当时想让公式标注“创20日新高”的位置,用了HHVBARS(HIGH,20),结果盘中每次价格刷新,这个函数标记的位置都在变,删掉最后的K线就发现历史信号对不上了。后来改成HIGH=HHV(HIGH,20)这个等式判断,信号马上就稳定了。这个教训我一直记着,现在写公式只要涉及高低点,一律用HHV加等式,不用HHVBARS。

5.3 文字和图标画不出来的四个原因

DRAWTEXT用得好好的,突然画不出来,或者整个公式加进去一点反应没有,这个问题我收到过不少次。按出现频率排,主要有四个原因。

第一,条件不成立。听起来像废话,但确实是最常见的原因。特别是底背离这类条件,本来就少,叠加了趋势过滤和量能过滤之后,可能翻完整段历史一个信号都没有。排查方法很简单:把条件单独输出成一条线,看看有没有任何位置等于1。我通常会把底背离F直接画成副图曲线,一眼就能看到信号分布。

第二,坐标被K线遮住。DRAWTEXT的第二个参数写的是LOW,文字默认从最低价的位置开始写,结果K线实体把文字盖住大半,看着就像没画出来。解决办法就是第3章说的,坐标写成LOW0.95或者HIGH1.05,把文字顶出去。

第三,DRAWICON图标编号不在有效范围内。通达信不同版本的图标编号范围不一样,有些版本一共就几十个编号,你写了个超范围的编号,图就画不出来。稳妥起见,图标编号从1到10之间挑,这是各版本都稳定的区间。

第四,变量名重复覆盖。通达信公式里变量名不能重复定义,如果你已经定义了“背离”这个变量,后面又用“背离:=”重新赋值,系统会直接报错或出现奇怪结果。排查方法是看公式输出窗口的报错提示,这类语法错误通常都有明确说明。

5.4 自动标注条件直接转成选股和预警

主图公式画出来之后,最大的福利就是这些条件可以直接复用成选股公式,不用另写一遍逻辑。

做法很简单。在公式末尾加一行输出:

选股信号:=底背离F OR 顶背离F OR 金叉过滤 OR 缩半量;

然后在通达信的条件选股公式编辑器新建一个公式,把上面整段逻辑粘贴进去,最后加一行:

XG:选股信号;

选股条件选“XG=1”,就能在历史行情里扫描出所有触发信号的自选票。我每天收盘后用条件选股扫一遍全市场,把出现底背离或者缩倍量突破的票加进自选,再人工复核图形,工作量瞬间小了很多。

盯盘预警也是同样的逻辑。把选股公式挂到通达信的预警系统里,设置实时刷新,盘中信号一触发就弹窗提醒。预警系统支持一次挂多只票,我通常把自选股全挂进去,配合1分钟或者5分钟周期使用,日内高低点波段行情基本能覆盖住。

如果你后续要把选股结果导出到数据库做统计,有一点要留意:多值形态筛选在SQL里的写法。很多人会把多个形态塞进一个字段,写出WHERE 形态IN('底背离','顶背离')结果里却没有数据,原因是你存的是单值字段,一个记录只有一个形态值。正确做法是先做一次UNION或者用子查询把多值拆成多行,再去做IN匹配,否则匹配永远为空。

写公式这些年,我最大的体会有两点。第一,公式只是把规则写清楚,它不会替你判断,自动标注省下来的是机械识别的时间,而不是决策的思考量。第二,信号不是越多越好,这套主图公式写完之后,我反而一直在做减法,把不重要的、重复的标注删掉,最后图上留下的信号才真的有参考价值。写完之后你还得花时间做一件事:把历史K线翻一遍,找一个信号密集的票,用键盘逐根走一遍,看看每个信号出现的环境是不是你想要的。这一步做完,你才算真正了解自己的公式。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询