跳转至

线段:特征序列划分

适用范围:本文描述 fqchan06 内核的线段算法——正统的特征序列实现(源码 cpp/chanlun/xd.cpp)。fqchan04 的高低点完全分类路线见线段:划分与缺口处理;2026 年起,本文的算法可通过 OPTS 参数在 fqchan04 公式中直接调用。

线段的定义与意义(三笔起点、顶底交替、趋势骨架)在 fqchan04 的线段文档中已经讲清,本文不重复。这里回答的是另一个问题:如果严格按缠师原文的特征序列定义来划分线段,算法应该怎么写?

背景:fqchan04 没有使用特征序列的方法(特征序列的严格程序化定义本身存在难点,见 fqchan04 文档的取舍说明)。这个问题作者搏斗多年,2026 年 1 月在 fqchan06 中落地了正统实现。这是缠论程序化公认最硬的一块骨头:人眼一眼能看出来的东西,让计算机理解却非常有难度。

特征序列:线段的 DNA

判断线段的关键,在于观察「对手笔」。

向上线段中,对手笔是那些向下走的笔——它们像一群想阻止你上山的人,力量有强有弱,但整体在向下用力。这些向下笔构成的序列,就是向上线段的特征序列;向下线段的特征序列则由内部的向上笔构成。一句话:

特征序列:线段中那些「反向」的笔,它们包含了线段生死的秘密。

趋势是足迹,特征序列是足迹的纹理,缺口是足迹间的犹豫。找到它们,你就找到了市场的节奏。

向上线段中的特征序列示意

从笔构造特征序列元素

特征序列的一个元素,就是一笔的区间。以向上线段为例,从某个顶点(type=1)出发,找到下一个底点(type=-1),这一段向下笔的最高价与最低价构成一个元素 [high, low]:

// 提取一个特征序列元素:向上线段中,从一个顶点到下一个底点
FeatureElement extract_one(vertexes, start_idx) {
    // 起点:顶点(type=1)
    // 方向:向上线段,查找下一个底点(type=-1)
    // 返回:这个区间的最高价和最低价 [high, low]
}

特征序列的包含处理

和 K 线一样,相邻的特征序列元素之间也会出现「包含」:后一个元素的区间完全落在前一个元素的区间之内。处理方式与 K 线包含合并的规则同构——方向决定取法,只是处理对象从 K 线换成了反向笔:

  • 向上线段(特征序列是向下笔):合并取更高的 high 和更高的 low,新区间延伸到后一个元素的结束位置;
  • 向下线段(特征序列是向上笔):合并取更低的 high 和更低的 low,镜像相反。
void merge_include(features, Direction::UP) {
    // 向上线段:取更高的 high 和更高的 low
    prev.high = max(prev.high, curr.high);
    prev.low  = max(prev.low,  curr.low);
    prev.end_pos = curr.end_pos;   // 延伸到后者
}

为什么向上线段取更高值?因为特征序列都是向下笔,后笔被前笔包含,说明下探力量不足——回调连前低都摸不到,取更高的值才能保留「趋势仍强」这个信息。

处理完包含关系,特征序列就成了一个干净的区间序列,接下来的一切判定都在它上面进行。

第一种情况:无缺口的分段判定

单调性:线段活着的证据

观察向上线段的特征序列(一串向下笔区间):只要线段还在延续,这些元素的高低点会依次抬高——单调递增排列;向下线段的特征序列则依次降低——单调递减。这就是单调特征序列。就像音乐,一直高音或一直低音都不算转折;单调性还在,节奏就还在,线段就还活着。

反过来,线段在特征序列的单调性破坏中诞生:向上线段的特征序列里,一旦出现一个元素整体低于前一个元素(顶分型的雏形),说明向下力量第一次真正压过了向上力量,线段的终点候选出现了。

无缺口:破坏即成立

原文的第一种情况:转折点处,特征序列分型的相邻两个元素区间有重叠(无缺口)。此时分型足以确认线段结束——转折点就是线段终点,新线段从转折点直接开始,无需额外证据。

fqchan06 的实现把这个判定写成一条「缺口封闭」检查:

// 向上线段检测到特征序列向下转换(单调性破坏)
if (relation == MONOTONIC_FALLING) {
    prev_extreme = 前向上线段的极值(最高点);
    if (新序列.low < prev_extreme) {
        // 缺口封闭:反向走势已跌回前段极值区间,无缺口
        // → 转折成立,形成新向下线段
        segments.push_back(新向下线段);
    } else {
        // 缺口未封闭 → 进入第二种情况(见下节)
    }
}

直觉上:反向笔一旦回落、触及前段的极值区域,「破坏」就被市场确认了,不必再等。第一种情况是两种情况里的多数,也是分段判定最干脆的场景。

第二种情况:有缺口的分段判定

有时候特征序列确实发生了方向转换,但新线段并不能立即确认——因为转折处的特征序列分型相邻元素区间无重叠,存在缺口。缺口的含义是:价格跳过了一段区间,反向力量虽然出现,但还没有用真实成交回补这段「犹豫」。此时若直接分段,很容易把中继当成转折。

原文的处理:有缺口时,分型不足以确认前段结束,必须等反方向的特征序列也走出分型(即新方向的走势自己也出现节奏破坏),前段的结束才算确认。fqchan06 把它落实为缺口未封闭时的两条路径:

// 缺口未封闭:查找反向(向上)的单调特征序列
reverse_result = find_monotonic_feature_sequence(...);

if (reverse_result.结束点 > 前向上线段.高点) {
    // 路径一:反向序列突破前高 → 缺口是中继,前向上线段延续
    segments.back().end_pos = reverse_result.end_pos;
} else {
    // 路径二:反向序列未突破前高,且自身单调性被破坏(将现底分型)
    // → 折返确认,形成两个新线段:向下 + 向上
    segments.push_back(向下线段);
    segments.push_back(向上线段);
}

两条路径对应的具体形态(回落创新低确认、突破前高延续、未破不立折返成两段等),fqchan04 文档中的缺口完全分类四图给出了完整图示——完全分类的目标对两条路线是相通的。

递归:用同样的逻辑解决不同阶段

第一根线段确定后,后续线段用同一套判定滚动推进。fqchan06 的实现采用递归:

find_subsequent_segments(已找到的线段列表) {
    从最后一根线段的终点继续;
    收集特征序列并做包含合并;

    if (检测到方向转换) {
        if (缺口封闭) { 添加新线段; 递归调用自己; }
        else {
            查找反向序列;
            if (反向序列突破前极值) 延伸当前线段;
            else                    添加两条新线段;   // 折返
            递归调用自己;
        }
    }
    if (后续创出更高/更低点) { 延伸当前线段; 递归调用自己; }
}

递归的本质是:用同样的逻辑,解决不同阶段的问题。分段算法的三个动作——单调性破坏、缺口试探、极值突破——在每个阶段都相同,这正是它适合程序化的原因。

第一个线段:双向单调法

递归有个前提:先得有第一根线段。序列的开头没有「前段」可参照,这是分段算法的冷启动问题。

fqchan06 的解法:同时向上和向下两个方向构造特征序列,观察哪个方向先出现单调特征序列——先出现单调递增,第一根就是向上线段;先出现单调递减,第一根就是向下线段。

find_first_segment() {
    for (每个候选起点) {
        提取特征序列元素;
        for (后续元素) {
            if (下一个包含当前) { 合并; continue; }
            if (当前被下一个包含) { break; }        // 这条路走不通
            if (出现单调递减特征序列) return 向下线段;
            if (出现单调递增特征序列) return 向上线段;
            break;                                   // 方向没变,不是第一根
        }
    }
}

fqchan04 对同一问题用的是「第一个三笔结构成立才成段」(见其文档),两种表述殊途同归:第一个线段的方向由市场自己走出来,而不是由序列的第一笔决定。

视觉差异:丑反而是正确的

fqchan06 按特征序列定义划分,图上「古怪」的情况确实不少;fqchan04 的完全分类视觉效果通常更舒服。但算法是按定义来的,有时候丑反而是正确的。下图是 fqchan06 特征序列段的实际划分效果——与 fqchan04 的习惯画法相比,风格差异一眼可见,理解了特征序列的判定逻辑,这些「别扭」大多能找到解释。

fqchan06 特征序列段的实际划分效果

在 fqchan04 公式中启用

2026 年 1 月起,fqchan06 的特征序列段算法通过参数接入 fqchan04 的公式体系。默认的段函数保持 fqchan04 划分:

DUAN:=TDXDLL6(3,BI,H,L);

切换到特征序列划分,只需改一行:给段函数追加 OPTS 参数,并确保 OPTS 已在参数区定义(示例缺省值 1560)、经 13 号函数注册:

NO2:=TDXDLL4(13,0,OPTS,0);        { 注册 OPTS 参数 }
DUAN:=TDXDLL6(3,BI,H,L,OPTS);     { 特征序列段:仅此一行与默认不同 }

公式修改:只需改 DUAN 一行

切换后,笔仍用 fqchan04 的划分(《笔:成笔规则与模式参数》),段改用 fqchan06 的特征序列划分,两套体系在同一张图上组合,供对比研究。线段信号值(-1/1 与 0.5/-0.5 成立信号)与 fqchan04 的定义一致,见其线段文档。

演进脉络

时间 事件 要点
2026-01-05 特征序列算法落地 fqchan06 实现正统特征序列分段(单调性 + 缺口 + 递归),源码 cpp/chanlun/xd.cpp
2026-01-06 图例作业 展示划分图例,验证算法效果
2026-01-12 公式改进 特征序列段通过 OPTS 参数接入 fqchan04 公式

一句话总结这套算法的精髓:

线段是在特征序列的单调性破坏中诞生的,在缺口的试探中确认的,在极值的突破中延续的。

知识来源

  • 《用特征序列划分线段,在K线的迷宫中寻找趋势的足迹》(2026-01-05,R3886,本文骨架,原文基于 fqchan06 项目线段算法实现)
  • 《特征序列划分线段,今天展示一些图例,是检查昨天的作业》(2026-01-06)
  • 《缠论特征序列公式改进 + 17连阳后还会涨吗?今日市场热点分析》(2026-01-12)
  • fqchan06 项目源码 cpp/chanlun/xd.cpp(小分队内容)