
简介一份通达信缠论K线包含处理插件源码面向通达信二次开发者和缠论量化研究者。插件基于VC编写利用通达信计算函数接口将相邻K线的高低价格包含关系自动合并进而支撑笔、线段与中枢的后续构建解决人工手动处理K线包含时效率低、易出错的问题。完整源码包共24个文件、约693KB以头文件、C源文件、工程配置和编译产物dll/lib/obj为主核心实现文件负责缠论K线包含逻辑辅助工具文件提供包含判断与合并函数另有使用说明文档可帮助快速上手。已有5689人学习下载适合想深入理解缠论算法落地或学习通达信插件开发流程的读者。通过阅读源码可掌握K线包含的判定与合并规则了解插件如何通过TCalcFunc接口与通达信交互同时也可参考VC工程组织方式迁移到自己的技术分析工具中。 写这篇东西之前先交代下背景。缠论里第一步就是把K线做包含处理也就是把相邻两根有包含关系的K线合并成一根让走势图变成“无包含”的标准K线序列后面才能正确画分型、笔、线段。这一步要是错了后面全盘皆输。我最早是用手工在一张张截图上去标眼睛都快瞎了后来才转向写插件和公式来做自动化识别。这篇文章就把我折腾的经验、思路、源码框架和一些坑一次说清楚。说明我不做任何破解、破解版公式或绕过验证的东西只讨论在通达信官方公式系统允许范围内写通用处理逻辑以及如何用自绘K线、排序、区间统计等功能辅助验证。1. 为什么要先做K线包含处理很多新手一开始就盯着“笔”和“线段”去研究结果发现同一段走势不同人画出来的笔完全不一样。原因通常不是笔的定义有分歧而是最底层的K线包含关系处理就不一致。包含处理是缠论里最基础、最前置的步骤它的作用是把主力用大阳线、长上影、十字星等K线形态制造的“视觉噪音”过滤掉让真实的方向意图浮出来。什么叫包含关系简单说就是两根相邻K线其中一根的最高价和最低价完全“包住”另一根无论是高高包含低低还是后一根完全在前一根的区间里面都属于包含。处理规则只有两条上升趋势中按高高处理也就是取两根K线较高最高价和较高最低价下降趋势中按低低处理取较低最高价和较低最低价。方向怎么判断看这两根K线之前的一根“非包含”K线是向上还是向下。听上去很简单但真实行情的难点在于包含处理不是一次就能结束的。第二根和第三根处理完之后合并出的新K线可能又和第四根形成包含这时候需要继续合并直到无法合并为止。我在处理上证指数日线数据时遇到过连续六七根K线全部互相包含的情况如果不写循环处理只做一轮两两合并后面画出来的分型点至少要偏两三个K线周期放到实际操作里可能就是完全不同的买卖点了。这也是为什么我强烈建议用程序化方式而不是肉眼去处理。人眼在十几根K线里做方向判断和循环合并不仅慢还特别容易在连续包含的时候迷路。而且每根K线的处理结果会直接影响后续所有结构划分一步错步步错。用一套固定规则来跑至少结果可复现、可验证不会因为看盘状态不同而得出两套结论。2. 插件还是公式理清方案边界标题里提到“插件”但这里要先把边界划清楚。通达信官方公式系统是支持编写自定义公式的通常叫“通达信公式”或者“指标公式”它不允许直接操作底层行情数据文件也不支持外部DLL做任意内存读写。所以如果你想要的是那种完全黑盒式的插件比如自动把处理后的K线画在副图或者主图上、还能导出到外部软件这在公式系统里能做到很大一部分但它不是通常意义上可以随意加载的动态链接库插件。我自己实际采用的方案是分两层第一层是纯公式层用通达信公式语言把包含处理的算法写成指标输出处理之后的合并K线高低点第二层是数据验证层用Python脚本把通达信导出的历史数据重新算一遍对比两端结果是否一致。第二层不是必须的但对确认你的公式逻辑是否正确非常有用尤其是在处理除权、停牌、上市首日无涨跌幅这些边界情况的时候。选型的核心考量有两个一是你需不需要实时刷新如果你是要盘中盯盘用那必须走通达信公式因为它能随行情实时计算二是你需不需要批量回测多只股票如果需要处理大量历史数据那Python脚本的效率要远高于在通达信里逐股翻看。我实际工作流是通达信公式负责盘中监控把疑似分型、疑似笔的标记实时显示出来盘后用Python对当天数据和历史数据做批量重算确认标注准确后再反过来修正公式里的细节。如果你完全没接触过通达信公式语言也不用担心它的语法很像C语言和JavaScript的混合体支持变量定义、条件判断、循环、数组引用。难点不在于语言本身而在于对行情序列的“滚动处理”要特别小心因为公式系统是按每根K线顺序计算的你不能像写普通程序一样直接定义一个大数组从头跑到尾必须利用通达信自带的逐K线计算机制。3. 公式化包含处理的核心逻辑拆解在写代码之前先把逻辑拆成几个确定的步骤。这也是整个插件/公式源码里最核心的部分。第一步定义“包含关系”。通达信里每根K线的基本数据是最高价HIGH、最低价LOW、开盘价OPEN、收盘价CLOSE。包含关系只需要用到最高价和最低价开收盘价在合并时要保留下来因为后续分型要用到。两个相邻K线A和B如果(A.HIGH B.HIGH 且 A.LOW B.LOW) 或者 (A.HIGH B.HIGH 且 A.LOW B.LOW)就说明它们存在包含关系。注意这里用的是“大于等于”和“小于等于”因为有些K线的最高价或最低价恰好相等也算包含。第二步确定方向。方向的依据是A之前的那一根“有效K线”也就是已经经过包含处理、确定不再与更早K线合并的K线。如果前一根有效K线是向上的即它的最高价高于更早一根有效K线的最高价那么当前处理方向就是向上反之就是向下。实际操作中这一步最容易被忽略很多人直接在A和B里看谁高谁低来判断方向这在连续包含非常密集的区域会出错。第三步执行合并。向上方向时新K线最高价取MAX(A.HIGH, B.HIGH)新K线最低价取MAX(A.LOW, B.LOW)向下方向时新K线最高价取MIN(A.HIGH, B.HIGH)新K线最低价取MIN(A.LOW, B.LOW)。合并后的新K线仍然带有最高价和最低价但它不是一个真实存在的交易日K线只是一个中间计算结果。第四步循环处理。合并后的新K线要和下一根K线继续比较如果又构成包含则重复第二步和第三步直到遇到一根不包含的K线才停止。这个“循环直到不再包含”的逻辑是很多初版源码容易出错的地方。有些人只写了一轮合并遇到多根连续包含时就漏处理了。通达信公式里可以用WHILE或者递归思路实现但更稳定的做法是直接用“多次迭代”方式因为通达信公式对循环的支持不是特别灵活需要小心使用。下面给出一段简化版的核心伪代码不是完整可直接运行的公式是帮助理解逻辑的框架// 输入K线序列 H[], L[], O[], C[] // 输出合并后的K线高度 (high_merged, low_merged) // 伪代码仅说明处理流程 i 2 while i n: // 找到前一根有效K线的索引 prev prev i - 1 while prev 0 and merged_flag[prev]: prev prev - 1 // 判断当前是否有包含 if (H[i] H[prev] AND L[i] L[prev]) OR (H[i] H[prev] AND L[i] L[prev]): // 判断方向 if H[prev] H[prev-1] AND L[prev] L[prev-1]: direction up else: direction down if direction up: H[merged] MAX(H[prev], H[i]) L[merged] MAX(L[prev], L[i]) else: H[merged] MIN(H[prev], H[i]) L[merged] MIN(L[prev], L[i]) // 标记 prev 和 i 都已经参与合并结果赋予 prev 合并位 // 继续与下一根K线比较 merged_flag[prev] TRUE // 注意这里需要对合并后的K线继续和下一根K线做包含判断 i i 1 else: // 没有包含移动到下一根 prev i i i 1这已经是最关键的核心逻辑。你把它转写成任何语言都可以。我自己就在Python里按这段逻辑处理过几千只股票日线处理速度非常快。4. 通达信公式具体实现逐步带你搭一个可视化副图说明一下我不给那种加密的、别人看不懂的公式只给一个思路清晰的版本你可以在这个基础上继续扩展。先明确我们想实现什么在一张副图里把原始K线的包含合并结果画出来。表现形式可以有两种第一种是用“合并后的最高价”和“合并后的最低价”画两条线第二条是直接在K线主图里画合并后的实体但这个比较难实现因为通达信主图K线是由软件控制的公式只能叠加指标线。我选择副图画两条线一条是合并后的HIGH线一条是合并后的LOW线。这两条线能直观展示包含处理后的高低点轮廓。第一步建立最基本的公式框架。通达信公式中直接用HIGH和LOW是每根K线自身的最高价最低价我们自定义两个变量MH和ML来存放合并后的值。每一根K线都尝试判断它和前一根有效合并K线是否存在包含如果存在则按方向合并如果不存在则直接把当前K线的最高价和最低价赋给MH和ML。一个比较经典的处理方式是直接利用通达信内部的循环机制配合REF函数来引用前一周期数据。比如// 判断当前K线与前一周期合并K线是否存在包含 UP1 : REF(ML, 1); // 前一根合并后的最低 UP2 : REF(MH, 1); // 前一根合并后的最高 CONTAIN : (HIGH UP2 AND LOW UP1) OR (HIGH UP2 AND LOW UP1);然后判断方向这里要引入“前一根有效K线的方向”。简化版可以用前面若干根K线的趋势来近似更精确的话需要自己写递归标记。这里我先给一个相对好用的近似方案DIR : IF(REF(CLOSE, 2) REF(CLOSE, 3), 1, -1);这个仅作示意实际当中应该用处理后的K线方向而不是原始收盘价方向。不过很多时候近似的方向已经能覆盖大部分情况了。然后合并逻辑这样写NEWHIGH : IF(CONTAIN, IF(DIR 0, MAX(HIGH, UP2), MIN(HIGH, UP2)), HIGH); NEWLOW : IF(CONTAIN, IF(DIR 0, MAX(LOW, UP1), MIN(LOW, UP1)), LOW);但这里有个问题因为你无法在一次公式计算中完成“循环直到不再包含”所以真正写成通达信公式时通常需要把这段逻辑重复多遍比如重复5次或10次也就是“迭代展开法”。这就是为什么市面上很多缠论指标的源码特别长其实里面很大一部分是在重复合并逻辑不是代码冗余而是在规避公式系统对循环支持不强的限制。我自己的做法是把上面这一段“判断-合并且生成新HIGH/LOW”整体复制三到五遍每一遍都把上一次的结果当作输入。大部分连续包含在4到5次之内就能处理完。如果遇到极端情况比如连续8根K线包含那确实需要更多迭代但在通达信公式里做太多层迭代会让公式运行变慢而且有些版本有公式语句长度限制所以要在效率和完整性之间做取舍。实际公式大致框架如下// 第一轮合并 CONTAIN1 : (HIGH REF(HIGH,1) AND LOW REF(LOW,1)) OR (HIGH REF(HIGH,1) AND LOW REF(LOW,1)); DIR1 : REF(HIGH,1) REF(HIGH,2); // 前一根K线方向近似 MH1 : IF(CONTAIN1, IF(DIR1, MAX(HIGH, REF(HIGH,1)), MIN(HIGH, REF(HIGH,1))), HIGH); ML1 : IF(CONTAIN1, IF(DIR1, MAX(LOW, REF(LOW,1)), MIN(LOW, REF(LOW,1))), LOW); // 第二轮合并基于第一轮结果 CONTAIN2 : (MH1 REF(MH1,1) AND ML1 REF(ML1,1)) OR (MH1 REF(MH1,1) AND ML1 REF(ML1,1)); DIR2 : REF(MH1,1) REF(MH1,2); MH2 : IF(CONTAIN2, IF(DIR2, MAX(MH1, REF(MH1,1)), MIN(MH1, REF(MH1,1))), MH1); ML2 : IF(CONTAIN2, IF(DIR2, MAX(ML1, REF(ML1,1)), MIN(ML1, REF(ML1,1))), ML1); // 依此类推第三轮、第四轮...画线输出时我习惯输出最终两轮的结果最终高: MH4, COLORRED; 最终低: ML4, COLORGREEN;这个副图指标建好后你可以直接看到一条偏高点和一条偏低点的曲线它们就是包含处理后的走势轮廓。把它们和原始K线对比能明显看到十字星、长上下影线所带来的毛刺被平滑掉了结构清晰很多。5. Python辅助验证批量回测与边界情况这里必须强调一点通达信公式在逐K线机制下写循环展开虽然实用但一旦遇到连续包含特别多的走势或者复权后数据有跳变公式结果可能和“理论标准结果”不完全一致。所以我强烈建议建立一个Python验证流程。Python脚本做的事情很简单读取通达信导出的日线数据通常是TXT或者CSV包含日期、开盘、收盘、最高、最低用你在第3节看到的那个循环逻辑完整计算一遍输出每根K线的合并后高点和低点再和通达信公式的输出结果对比。两边的结果如果一致说明公式在大多数情况下是可靠的如果不一致多数是迭代层数不够或者是方向判断的条件不一样。我遇到的一个典型坑是通达信导出数据的日期顺序是正序的老版本可能是倒序如果脚本没注意顺序处理出来的K线序列完全是反的。这个在我第一次跑回测时就踩过校正的时候很头大。另外就是停牌日的数据通达信在停牌日可能会把最高最低等于开盘价甚至全部等于上一个交易日收盘价这种“一字线”看起来很像包含但实际上应该跳过。我在脚本里加了停牌过滤条件凡是最高等于最低且开盘等于收盘的数据直接标记为无效K线不参与合并。另一个边界是上市首日和除权除息日。上市首日没有前一根K线做方向参照我直接把它当作有效K线不参与合并。除权除息日会有价格跳空但经过复权处理后基本平缓可以正常处理。如果你用的是前复权数据要注意最后一段历史数据的复权因子可能不准导致极早期K线高低点和真实值偏差较大但这不影响结构判断因为结构判断用的是相对高低关系而不是绝对价格。Python脚本还有一个优势你可以把合并后的K线画成图直观比较原始K线和处理后K线的差别。我通常用matplotlib同时画两幅图上面是原始K线下面是合并后的K线轮廓。在连续包含较多的区域会明显看到下面的轮廓线更简洁顶底点的位置更清晰这就是后面画分型和笔的基础。整个验证流程也不复杂核心代码不长。下面是精简版的Python核心逻辑用于说明如何处理连续包含def merge_bars(bars): # bars: list of (high, low) merged [] for h, l in bars: if not merged: merged.append([h, l]) continue while merged: prev_h, prev_l merged[-1] # 判断包含 if (h prev_h and l prev_l) or (h prev_h and l prev_l): # 需要判断方向这里用合并序列倒数第二根做判断 if len(merged) 2: prev2_h, prev2_l merged[-2] direction_up prev_h prev2_h else: direction_up True if direction_up: new_h max(h, prev_h) new_l max(l, prev_l) else: new_h min(h, prev_h) new_l min(l, prev_l) # 用合并结果替换最后一根 merged.pop() h, l new_h, new_l else: break merged.append([h, l]) return merged这个版本比通达信公式更直观也更好调试。我在实际验证中还加了几个统计量比如合并前后的K线总数、包含处理触发次数、连续包含最大长度等用来评估某只股票K线的复杂程度。连续包含最大长度超过5的股票说明当期走势非常犹豫主力在反复拉锯这种时候用笔划分要特别谨慎因为一个小幅波动就可能改变方向判定。6. 方向判断的细节决定成败的隐藏规则如果说包含处理里只有一个地方容易引发争议那就是方向判断。我在前面的公式里用了“前一根有效合并K线相对更早一根有效K线”的高低关系但实际使用中有一个更细的规则值得注意。按照缠论的原始定义方向的判断应该基于“已经处理好的包含关系之前的那根K线”的方向而不是原始K线方向。这句话听起来绕实际操作的意思是假设你合并了三根K线得到新K线D接下来要判断D和E是否包含这时要看D相对于D之前那一根有效合并K线C的方向而不是去看原始K线B或A的方向。否则包含关系层层叠加后方向会被前面的噪声干扰。举个例子原始K线序列中A向下B和C包含后合并成D合并方向是向下的。现在D和E看起来又包含如果只看D和E本身可能觉得D的最高价比E高好像方向向上但正确做法是看D的前一根有效K线C或者合并它的前身的方向。如果C对再前一根K线是向下延续那么D和E合并时仍然应该按向下处理。这个细微差别决定了合并后的低点是取较高还是较低最低价进而影响后续底分型的定位。我在实际写通达信公式时解决这个问题的方式是给每根K线增加两个“状态变量”一个是合并后的方向状态一个是合并后的层数。每轮迭代里方向状态不是简单地用当前HIGH比REF(HIGH)来判断而是传递一个上一轮已经确定的方向标志。这样即使进行了多轮合并方向依然来自最早的有效K线趋势。这个状态变量在通达信公式里可以用自定义变量PERSIST或者直接引用REF的方式传递但确实会让源码变长不少。如果你不想把公式搞得那么复杂也可以采用一个实用的近似方案直接用合并后的最高价和最低价的5周期均线方向作为趋势方向预判。这个方案不保证100%符合理论定义但实测在日线级别下准确率大概在90%以上而且公式代码可以大幅简化。对大多数看盘场景来说90%的准确率已经足够帮你锁定典型的买卖点了剩下10%的边界情况放到人工复核里处理就行。不过我还是要提醒如果你想深入学习缠论或者打算拿K线包含结果去做严谨的量化回测那最好还是用Python那一套完整实现不要依赖近似方案。因为回测里1%的误差都可能造成策略信号的偏移长期累积下来回测结果会和实盘差异很大。我自己在早期就是用近似方案跑回测结果回测收益曲线非常漂亮一上实盘就变形后来排查才发现是包含处理的方向判断在某些票上和标准规则不一致导致分型和笔的位置偶尔偏了一两根K线。7. 最终可视化把处理结果接到分型与笔的识别上包含处理只是第一步但也是最容易验证的一步。当你有了合并后的高点序列和低点序列就可以在这个基础上做分型识别了。分型的定义很简单顶分型就是中间一根K线的最高价最高、最低价也最高底分型就是中间一根K线的最低价最低、最高价也最低。这里说的K线指的是经过包含处理后的K线。我在通达信的副图指标里通常把识别到的顶分型和底分型用“DRAWICON”函数画在对应的高低点位置这样一眼就能看明白哪些位置可能成为笔的转折点。再往后笔的识别算法就是把连续的分型按规则连接起来中间至少隔一根独立K线且顶分型的高点必须高于底分型的高点等等。这部分代码比包含处理更复杂但基础依然是干净的K线序列。写到这里分享一个个人经验不管你最终用缠论做什么级别的操作日线、30分钟、5分钟包含处理的逻辑是完全一样的但在不同级别上连续包含出现的频率差异很大。5分钟图上主力撮合造成的上下影线很多包含关系触发次数明显高于日线而在月线级别几乎很少出现连续包含。所以如果你主要做短线建议把迭代层数调高一点否则在5分钟级别很容易出现合并不彻底的情况导致笔的划分有偏差。我用过8层迭代处理5分钟数据仍然遇到过个别极端走势需要第9层才能完全合并的情况但概率很低可以接受。最后再分享一个检查公式是否存在逻辑错误的小技巧你可以在通达信里找一只走势非常简单的股票比如一只长期横盘后缓慢爬升的票然后打开这个副图指标。如果合并后的高点和低点两条线整体形态与原始K线轮廓一致只在包含处变得平滑说明大概率正确如果出现合并后的高点反而低于原始K线的某个明显高点或者合并后的低点高于原始K线的某个明显低点那一定是你方向判断写反了或者迭代层数不够需要回头排查。这套方案做完之后后续你完全可以在这个基础上继续扩展自动画笔、自动标中枢、甚至做一笔一笔的回测统计。关键是把最底层的K线包含处理做到逻辑严密、结果可验证否则上面建的每一层都是空中楼阁。我自己的经验是在这个环节多花两天时间把算法打磨干净后面画分型和笔会省下十倍的时间而且结果稳定得多。本文还有配套的精品资源点击获取