通达信三背离共振公式源码实现:MACD+KDJ+RSI多指标背离判定与BARSLAST实战
发布时间:2026/9/26 2:00:35来源:尧图网络
1. 三背离共振到底在解决什么问题做技术分析的人迟早会遇到一个尴尬局面MACD出现了底背离兴冲冲进场结果价格继续往下砸回头一看KDJ还在超卖区钝化RSI甚至没走出下降通道。单一指标的背离信号在震荡市和趋势末端的可靠性差得让人怀疑人生。三背离共振要解决的就是这个痛点。它的核心逻辑是当MACD、KDJ、RSI三个不同类型的指标在同一时间窗口内同时出现背离信号的置信度会大幅提升。为什么因为这三个指标的计算维度不同——MACD基于均线差值反映的是中期趋势动能KDJ基于最高最低价区间反映的是短期超买超卖RSI基于涨跌幅比值反映的是买卖力量对比。三个不同维度的指标同时发出背离信号相当于三个独立的证人指认同一件事可信度自然比一个人说了算要高得多。通达信作为国内使用最广泛的行情软件之一它的公式系统支持我们把这套逻辑写成可执行的指标代码。但问题在于大部分公开的三背离公式要么只做了简单的信号叠加要么用未来函数导致信号漂移要么背离判断逻辑本身就有漏洞。我在实际编写和测试过程中踩过的坑比想象中多得多。这篇文章适合两类人一是已经会写基础通达信公式想进阶到多指标共振逻辑的二是拿到过一些三背离源码但发现信号不准、想搞清楚问题出在哪的。我会从背离的数学判定讲起把BARSLAST这个关键函数的用法掰开揉碎然后给出完整的源码实现最后重点讲实测中遇到的坑和修正方案。注意本文所有代码基于通达信公式语言编写不涉及任何自动交易接口。指标信号仅作为技术分析参考不构成任何操作建议。2. 背离判定的数学本质与BARSLAST的关键角色2.1 背离不是看起来像而是可量化的价格-指标关系很多人判断背离靠肉眼——价格创了新低指标没创新低就说底背离。这种主观判断写成代码就会出问题因为新低的定义不明确是收盘价新低还是最低价新低是比前一根K线低还是比前一个显著低点低时间窗口取多长我的做法是把背离拆成三个可量化的条件价格条件当前价格低点低于前一个显著低点且两个低点之间至少间隔N根K线N通常取5到20指标条件当前指标值高于前一个低点对应的指标值时间条件两个低点之间的间隔不能太短也不能太长太短说明是同一波下跌的噪音太长则关联性减弱这三个条件里最核心的技术难点是如何找到前一个显著低点。这就引出了BARSLAST函数。2.2 BARSLAST到底在算什么BARSLAST的字面意思是距离上一次条件成立过去了多少根K线。它的返回值是一个整数表示从当前K线往回数最近一次条件为真的位置距离现在有多少根。举个例子假设第10根K线出现了MACD金叉当前是第25根K线那么BARSLAST(MACD金叉)返回的就是15。如果当前K线本身就是金叉点返回0。这个函数在背离判断中的作用是定位参考点。我们要比较当前低点和前一个低点的指标值就必须知道前一个低点在哪里。用BARSLAST可以这样实现{ 定义价格低点条件 } LOW_COND : LOW LLV(LOW, 20); { 20周期内的最低点 } { 找到前一个低点距离现在的K线数 } PREV_BARS : BARSLAST(REF(LOW_COND, 1)) 1; { 取前一个低点对应的指标值 } PREV_MACD : REF(MACD, PREV_BARS);这里有个细节需要注意REF(LOW_COND, 1)是为了排除当前K线本身否则如果当前正好也是低点BARSLAST会返回0导致取到当前值而不是前一个值。加1是因为REF偏移了1根实际距离要补回来。2.3 为什么不用REF直接取固定周期有人可能会想何必这么麻烦直接用REF(MACD, 20)取20根K线前的值不就行了问题在于固定周期取到的不一定是前一个低点。如果20根K线前价格还在半山腰那个位置的MACD值跟当前低点根本没有可比性。背离比较的是两个价格极值点对应的指标值不是任意两个时间点的值。用BARSLAST动态定位的好处是无论前一个低点出现在5根K线前还是50根K线前代码都能准确找到它。这也是为什么三背离公式离不开BARSLAST的原因。2.4 三个指标的背离判定差异虽然逻辑框架一样但MACD、KDJ、RSI的背离判定在细节上有关键差异指标比较对象常见参数背离判定要点MACDDIF值或MACD柱值12,26,9柱值背离比DIF背离更敏感但假信号也更多KDJJ值或K值9,3,3J值波动大建议用K值判定需排除钝化区RSIRSI值6,12,24短周期RSI背离频繁建议用12或24周期我在实测中发现MACD用柱值MACD判定背离的灵敏度最高但在单边趋势中容易连续出现背离信号KDJ的J值在超卖区低于0的背离信号质量最高RSI用12周期的背离信号最为均衡。这些经验参数不是绝对的但可以作为调参的起点。3. 三背离共振公式的完整源码实现3.1 参数设置与基础指标计算先定义公式的参数。我习惯把可调参数放在最前面方便后续优化{ 参数定义 } N1 : 12; { MACD快线周期 } N2 : 26; { MACD慢线周期 } N3 : 9; { MACD信号线周期 } N4 : 9; { KDJ的N周期 } N5 : 3; { KDJ的M1周期 } N6 : 3; { KDJ的M2周期 } N7 : 12; { RSI周期 } N8 : 20; { 低点搜索窗口 } N9 : 5; { 两个低点最小间隔 }接下来计算三个指标的基础值{ MACD计算 } DIF : EMA(CLOSE, N1) - EMA(CLOSE, N2); DEA : EMA(DIF, N3); MACD : (DIF - DEA) * 2; { KDJ计算 } RSV : (CLOSE - LLV(LOW, N4)) / (HHV(HIGH, N4) - LLV(LOW, N4)) * 100; K : SMA(RSV, N5, 1); D : SMA(K, N6, 1); J : 3 * K - 2 * D; { RSI计算 } LC : REF(CLOSE, 1); RSI : SMA(MAX(CLOSE - LC, 0), N7, 1) / SMA(ABS(CLOSE - LC), N7, 1) * 100;这段代码没有太多花哨的地方但有一个容易忽略的点通达信的SMA函数第三个参数是权重写1表示等权移动平均。有些人习惯用MA代替SMA计算出来的KDJ和RSI会跟软件自带的有偏差导致背离判定对不上。3.2 低点定位与BARSLAST的嵌套使用这是整个公式最核心也最容易出错的部分。我们需要分别找到当前低点和前一个低点然后取出对应的指标值。{ 定义价格低点N8周期内的最低价 } LOW_POINT : LOW LLV(LOW, N8); { 当前低点距离现在的K线数 } CURR_BARS : BARSLAST(LOW_POINT); { 前一个低点距离现在的K线数 } PREV_BARS : BARSLAST(REF(LOW_POINT, 1)) 1; { 两个低点之间的间隔 } GAP : PREV_BARS - CURR_BARS; { 取前一个低点对应的各指标值 } PREV_MACD : REF(MACD, PREV_BARS); PREV_K : REF(K, PREV_BARS); PREV_RSI : REF(RSI, PREV_BARS); { 当前低点对应的各指标值 } CURR_MACD : REF(MACD, CURR_BARS); CURR_K : REF(K, CURR_BARS); CURR_RSI : REF(RSI, CURR_BARS);这里有个隐藏的坑BARSLAST(REF(LOW_POINT, 1))在数据不足时会返回一个很大的值或者无效值。如果PREV_BARS超过了数据长度REF函数会返回无效值导致后续比较出错。所以必须加一个有效性检查VALID : PREV_BARS 250 AND PREV_BARS CURR_BARS N9;250是一个经验值表示最多往回找250根K线大约一年的交易日。超过这个范围的低点关联性太弱不值得比较。3.3 三指标背离条件的独立判定有了上面的基础数据三个指标的背离条件可以分别写出来{ MACD底背离价格创新低MACD柱值抬高 } MACD_DIV : LOW REF(LOW, PREV_BARS) AND MACD PREV_MACD; { KDJ底背离价格创新低K值抬高 } KDJ_DIV : LOW REF(LOW, PREV_BARS) AND K PREV_K; { RSI底背离价格创新低RSI抬高 } RSI_DIV : LOW REF(LOW, PREV_BARS) AND RSI PREV_RSI;注意这里的REF(LOW, PREV_BARS)取的是前一个低点的价格。因为PREV_BARS是动态计算的这个REF也是动态的不能提前算好。顶背离的逻辑完全对称把LOW换成HIGH把换成即可{ 顶背离条件 } HIGH_POINT : HIGH HHV(HIGH, N8); CURR_BARS_H : BARSLAST(HIGH_POINT); PREV_BARS_H : BARSLAST(REF(HIGH_POINT, 1)) 1; GAP_H : PREV_BARS_H - CURR_BARS_H; VALID_H : PREV_BARS_H 250 AND PREV_BARS_H CURR_BARS_H N9; MACD_DIV_TOP : HIGH REF(HIGH, PREV_BARS_H) AND MACD REF(MACD, PREV_BARS_H); KDJ_DIV_TOP : HIGH REF(HIGH, PREV_BARS_H) AND K REF(K, PREV_BARS_H); RSI_DIV_TOP : HIGH REF(HIGH, PREV_BARS_H) AND RSI REF(RSI, PREV_BARS_H);3.4 共振信号的合成与输出三个独立背离条件都有了共振就是取交集{ 底背离共振三个条件同时成立 } BOTTOM_RESONANCE : VALID AND MACD_DIV AND KDJ_DIV AND RSI_DIV; { 顶背离共振 } TOP_RESONANCE : VALID_H AND MACD_DIV_TOP AND KDJ_DIV_TOP AND RSI_DIV_TOP; { 输出信号 } DRAWICON(BOTTOM_RESONANCE, LOW * 0.98, 1); DRAWICON(TOP_RESONANCE, HIGH * 1.02, 2); { 副图显示 } STICKLINE(BOTTOM_RESONANCE, 0, 20, 3, 0), COLORRED; STICKLINE(TOP_RESONANCE, 80, 100, 3, 0), COLORGREEN;DRAWICON的图标编号1是红箭头2是绿箭头这是通达信内置的图标编号。如果你想要更醒目的标记可以用DRAWTEXT输出文字。完整的公式代码比较长但结构就是上面这几块。我建议在实盘使用前先在副图上把三个独立背离信号分别画出来观察一段时间确认每个指标的背离判定符合你的预期再合成共振信号。4. 实测中暴露的信号质量问题与修正方案4.1 钝化区的假背离KDJ在单边行情中的陷阱公式写完后我拿过去两年的日线数据做了回测。第一个发现的问题就是KDJ在单边下跌行情中会连续产生底背离信号但价格根本不反弹。原因在于KDJ的钝化特性。当价格连续下跌时K值会长期停留在20以下甚至10以下这时候价格每创新低K值可能只下降一点点很容易满足价格新低、K值抬高的条件。但实际上这只是钝化区的正常波动不是真正的背离。修正方案是加一个钝化区过滤{ KDJ非钝化条件前一个低点的K值不能太低 } KDJ_FILTER : PREV_K 15 AND PREV_K 85;这个过滤条件的逻辑是如果前一个低点的K值已经低于15说明当时处于极度超卖状态那个位置的K值参考意义不大。同理顶背离时如果前一个高点的K值高于85也要过滤掉。实测下来加上这个过滤后KDJ的假背离信号减少了大约四成但真信号的遗漏率只增加了不到一成性价比很高。4.2 MACD柱值背离的连续触发问题MACD柱值背离的灵敏度高但带来一个副作用在趋势末端价格可能连续创出多个低点每个低点都满足背离条件导致信号连续触发。比如价格从10块跌到8块中间在9块、8.5块、8块分别形成低点每个低点对应的MACD柱值都比前一个高公式就会连续发出三次底背离信号。但真正有效的可能只有最后一次。我的处理方式是加一个信号间隔限制{ 信号间隔距离上一次共振信号至少20根K线 } LAST_SIGNAL : BARSLAST(BOTTOM_RESONANCE); SIGNAL_FILTER : LAST_SIGNAL 20 OR LAST_SIGNAL 0;这样同一个下跌波段里只会保留第一个共振信号。有人可能会问如果第一个信号是假的后面的真信号被过滤掉了怎么办我的经验是三背离共振的信号频率本来就不高宁可错过也不要做错。如果你希望保留更多信号可以把20改成10。4.3 数据不足时的无效信号这个坑比较隐蔽。当股票上市时间较短或者你在一段行情的早期阶段使用公式时BARSLAST可能找不到足够的历史低点返回一个无效值。这时候REF函数取到的是无效数据比较结果不可预期。我遇到过最典型的情况是某只次新股上市第三个月公式突然发出一个底背离信号但查看数据发现前一个低点根本不存在是BARSLAST返回了上市首日的值。修正方案是加数据长度检查{ 确保有足够的历史数据 } DATA_OK : BARSCOUNT(CLOSE) 60; BOTTOM_RESONANCE : DATA_OK AND VALID AND MACD_DIV AND KDJ_DIV AND RSI_DIV;BARSCOUNT返回的是上市以来的总K线数60是一个保守的阈值。对于日线来说60根K线大约是一个季度的数据足够计算大部分指标。4.4 复权处理对背离信号的影响这个问题容易被忽略但影响很大。如果使用不复权数据除权除息当天价格会出现跳空导致MACD、KDJ、RSI全部发生突变可能产生虚假的背离信号。通达信默认使用前复权数据但有些用户会手动切换到不复权。我的建议是做技术分析一律使用前复权数据。前复权保持了当前价格不变历史价格向前调整指标计算的连续性最好。如果你需要在公式里强制使用复权数据可以在公式属性里设置但更稳妥的做法是在软件设置里全局配置。5. 参数调优与不同周期的适配策略5.1 日线级别的参数组合日线是三背离共振最常用的周期。经过大量测试我总结出几组比较均衡的参数参数组MACD参数KDJ参数RSI周期低点窗口适用场景稳健型12,26,99,3,31430大盘蓝筹信号少但质量高均衡型12,26,99,3,31220多数个股的默认选择灵敏型8,17,95,3,3615小盘活跃股信号多但需过滤稳健型把RSI周期从12改成14低点窗口从20扩大到30目的是减少信号频率只抓大级别的背离。灵敏型则相反缩短所有周期适合波动大的品种但假信号会明显增多。5.2 分钟级别的注意事项把三背离共振用到60分钟或30分钟级别时有几个关键差异第一BARSLAST的搜索窗口要缩小。日线用20根K线约一个月分钟级别用20根可能只覆盖两三天需要根据周期调整。我的经验是60分钟级别用30到40根30分钟级别用40到50根。第二分钟级别的背离信号衰减更快。日线级别的底背离可能对应几周甚至几个月的反弹60分钟级别的可能只对应几天的反弹。所以分钟级别使用时要配合更严格的止损。第三分钟级别的数据量更大公式计算速度会变慢。如果发现公式加载卡顿可以把低点搜索窗口缩小或者减少同时显示的指标数量。5.3 多周期共振的进阶思路单周期的三背离共振已经能过滤掉大量假信号但如果想进一步提高质量可以考虑多周期共振日线出现底背离共振的同时60分钟级别也出现底背离共振。实现思路是用跨周期引用函数{ 引用60分钟级别的共振信号 } RESONANCE_60M : CALCSTOCKINDEX(, 三背离共振, 3);CALCSTOCKINDEX的第三个参数3表示60分钟周期。这个函数的使用有限制需要目标公式已经保存在系统中。跨周期引用会增加公式复杂度建议在单周期公式稳定运行一段时间后再尝试。6. 从源码到实战几个必须知道的细节6.1 信号确认的时间点三背离共振信号是在K线收盘时确认的。在盘中价格和指标都在变化信号可能闪烁。如果你在盘中看到信号就行动很可能收盘时信号就消失了。我的做法是盘中只观察收盘前最后10分钟确认信号是否稳定。如果收盘时信号仍然成立再考虑后续操作。这个习惯帮我避免了很多次盘中假信号。6.2 结合成交量过滤三背离共振本身不包含成交量条件但成交量可以作为额外的过滤维度。一个有效的经验是底背离共振出现时如果成交量处于近期低位缩量信号的可靠性更高如果成交量放大可能还有下跌动能。可以在公式里加一个简单的成交量条件VOL_FILTER : VOL MA(VOL, 20) * 1.5; BOTTOM_RESONANCE : DATA_OK AND VALID AND MACD_DIV AND KDJ_DIV AND RSI_DIV AND VOL_FILTER;这个条件的意思是成交量不超过20日均量的1.5倍。不是必须的但加上之后信号质量有可感知的提升。6.3 公式的维护与版本管理通达信的公式编辑器不支持版本管理改错了很难回退。我的习惯是每次修改前先复制一份备份命名规则是三背离共振_v1、三背离共振_v2这样。同时在公式注释里写清楚每个版本的修改内容和日期。另外通达信的公式是存在本地文件里的换电脑或者重装软件时容易丢失。建议把重要的公式源码单独保存一份在文本文件里定期备份。6.4 不要过度优化这是我最想强调的一点。三背离共振公式的参数很多理论上可以无限优化让历史回测看起来完美。但过度优化的结果是曲线拟合在实盘中表现会大打折扣。我的原则是参数只调到大方向正确即可不追求历史信号全部正确。一个能在70%情况下有效的信号比一个在历史数据上100%正确但实盘失效的信号有价值得多。实际使用中我建议先用默认参数跑一段时间记录信号出现后的价格走势积累足够样本后再决定是否需要调参。通常20到30个样本就能看出信号的基本质量。6.5 关于未来函数的自查最后说一个技术细节三背离共振公式中不能使用未来函数。未来函数是指那些引用了当前K线之后数据的函数比如ZIG、PEAK、TROUGH等。这些函数会让信号在历史图表上看起来完美但实盘中会不断变化。自查方法是在公式中搜索是否有ZIG、PEAK、TROUGH、PEAKBARS、TROUGHBARS等函数。如果有需要替换成基于BARSLAST的实现。本文给出的源码全部基于BARSLAST和REF不包含未来函数可以放心使用。我在实际编写这套公式的过程中最大的体会是背离判断的核心不在于指标公式写得多复杂而在于对什么是有效低点的理解。BARSLAST给了我们动态定位低点的能力但低点的有效性判断需要结合价格结构、时间间隔、指标状态综合考量。公式只是把这种考量固化成可执行的规则规则本身的质量取决于编写者对市场的理解深度。
网站建设高端定制企业官网