Vibe-Trading 缠论分型(FX)识别完全指南:去包含、顶底分型与笔端点实战解析
【免费下载链接】Vibe-Trading"Vibe-Trading: Your Personal Trading Agent"项目地址: https://gitcode.com/GitHub_Trending/vi/Vibe-Trading
本文是 Vibe-Trading 项目中
agent/src/skills/chanlun缠论技能包的核心概念系列之一。缠论(缠中说禅)是一套完全基于价格结构的形态分析方法,而分型(FX)是整个体系最底层的识别单元——去包含处理、顶底分型判定、笔端点确认,直至中枢构建与买卖点判定,全部建立在分型之上。读完本文,你将掌握分型的数学定义与条件、去包含合并规则、czsc中FX数据结构的字段语义,并能结合仓库中的example_signal_engine.py信号引擎,把分型识别直接用于 A 股、加密货币、期货等多市场 OHLCV 数据的实时分析与信号生成。
一、分型在缠论体系中的定位
缠论的核心链路是:
原始K线 → 去包含处理 → 分型识别 → 笔检测 → 中枢构建 → 买卖点判定分型位于整条链路的第三环,是连接原始价格数据与高层次结构(笔、中枢、买卖点)的必经桥梁。在 SKILL.md 中,分型被定义为整个体系的"最基础识别单元":
分型(FX):顶分型:中间K线最高;底分型:中间K线最低
- 没有分型,就无法定义笔(笔的两端必须是顶/底分型);
- 没有笔,就无法构建中枢(中枢由至少 3 笔构成);
- 没有中枢,一买/二买/三买等买卖点信号就无从谈起。
因此,分型识别的正确性直接决定了下游所有缠论信号的质量。
二、分型的定义:连续三根去包含后的 K 线
分型由连续三根去包含后的 K 线构成。这里有两个关键词需要精确理解:
- "去包含后":分型不是直接作用于原始 K 线,而是作用于经过"包含关系处理"之后的 K 线序列。包含关系会破坏分型的几何形态,必须先合并。
- "连续三根":分型是局部三根 K 线的形态判定,属于缠论中最小的局部结构。
顶分型(Mark.G):
██ ██ ██ ██ ██底分型(Mark.D):
██ ██ ██ ██ ██三、去包含处理:分型识别的前置步骤
3.1 包含关系的判定
当相邻两根 K 线存在价格区间完全覆盖时,即一根 K 线的高低点完全落在另一根的范围内(k1.high >= k2.high 且 k1.low <= k2.low,或反之),两者即为包含关系:
- 一根 K 线的最高价被另一根覆盖,且其最低价也被另一根覆盖。
3.2 合并规则
去包含处理的方向由前一根非包含 K 线的方向决定(上升或下降):
| 方向 | 合并取法 | 含义 |
|---|---|---|
| 上升方向 | 取两根 K 线中较大的高点和较大的低点 | 突出强势,向上延伸 |
| 下降方向 | 取较小的高点和较小的低点 | 突出弱势,向下延伸 |
用公式表达(以两根 K 线 k1、k2 合并为 k' 为例):
- 上升方向:
k'.high = max(k1.high, k2.high),k'.low = max(k1.low, k2.low) - 下降方向:
k'.high = min(k1.high, k2.high),k'.low = min(k1.low, k2.low)
从源码结构看,czsc 库内部正是以"去包含后的新 K 线(NewBar)"序列作为分型与笔的输入,这也解释了为什么FX.elements字段的类型是List[NewBar](详见下文第四节)。
3.3 为什么必须去包含
如果两根 K 线存在包含关系,它们实际上传达的是同一个方向的延伸信息,而非独立的价格行为。不去包含会导致:
- 本应构成分型的"中间高两边低"形态被包含 K 线破坏;
- 分型数量虚增或漏判,笔的端点错位;
- 下游中枢区间、买卖点信号全部失真。
四、顶分型与底分型的精确条件
设构成分型的三根去包含 K 线从左到右为k1, k2, k3。
4.1 顶分型(Mark.G)
条件:
k1.high < k2.high > k3.high 且 k1.low < k2.low > k3.low即:中间 K 线 k2 的最高价是三者中的最高,同时 k2 的最低价也是三者中的最高。
含义:价格在 k2 处冲到局部高点,随后 k3 的高点与低点均回落——上涨力量衰竭,可能转跌。顶分型是一卖、二卖、三卖等卖出信号确认的形态前提。
4.2 底分型(Mark.D)
条件:
k1.high > k2.high < k3.high 且 k1.low > k2.low < k3.low即:中间 K 线 k2 的最高价是三者中的最低,同时 k2 的最低价也是三者中的最低。
含义:价格在 k2 处探到局部低点,随后 k3 的高点与低点均回升——下跌力量衰竭,可能转涨。底分型是一买、二买、三买等买入信号确认的形态前提。
4.3 关键要点
- 顶分型与底分型判定同时要求 high 和 low 两个维度成立,单一维度不构成分型;
- 分型是必要条件而非充分条件:出现分型只代表"转折的可能",是否真正形成笔,还需满足笔的构成条件(顶底交替、无包含、最小 K 线数等,见 笔.md)。
五、czsc 中的 FX 数据结构
分型在czsc库中以FXdataclass 表示,字段语义如下:
@dataclass class FX: symbol: str # 标的代码 dt: datetime # 分型时间(取中间K线时间) mark: Mark # Mark.G(顶)/ Mark.D(底) high: float # 分型最高价 low: float # 分型最低价 fx: float # 分型值(顶取high,底取low) elements: List[NewBar] # 构成分型的三根去包含K线| 字段 | 类型 | 语义与来源 |
|---|---|---|
symbol | str | 标的代码,透传自输入 K 线的symbol |
dt | datetime | 分型时间,取中间 K 线(k2)的时间,代表转折发生的时点 |
mark | Mark | 分型类型枚举:Mark.G(顶)/Mark.D(底) |
high | float | 分型最高价,即三根 K 线的最高价 |
low | float | 分型最低价,即三根 K 线的最低价 |
fx | float | 分型值:顶分型取 high,底分型取 low。这是笔端点比较时的关键数值 |
elements | List[NewBar] | 构成该分型的三根去包含后的 K 线,印证了分型必须建立在去包含序列之上 |
其中fx字段的设计值得注意:顶分型用high、底分型用low,这使得在笔的判定中可以通过统一的"分型值"比较大小(例如上升笔要求fx_b.fx > fx_a.fx,详见 笔.md),从而避免在不同类型分型间做差异化的取价逻辑。
六、使用示例:从分型到笔端点
分型最常见的消费方式,是作为笔(BI)的端点。笔连接相邻的顶分型与底分型,因此遍历CZSC分析器输出的笔列表,即可获得每一笔的起点与终点分型:
from czsc import CZSC c = CZSC(bars) # 笔的端点就是分型 for bi in c.bi_list: print(f"起点分型: {bi.fx_a.mark.value} {bi.fx_a.dt}") print(f"终点分型: {bi.fx_b.mark.value} {bi.fx_b.dt}")其中:
bi.fx_a为该笔的起点分型(FX对象);bi.fx_b为该笔的终点分型(FX对象);- 上升笔满足
fx_a.mark = Mark.D、fx_b.mark = Mark.G;下降笔则相反; mark.value输出分型类型的字符串值(如"G"/"D")。
6.1 组合形态输出示例
结合 笔.md 的示例,可以更直观地观察分型时间与价格在笔中的体现:
from czsc import CZSC c = CZSC(bars) for bi in c.bi_list[-5:]: d = "↑" if bi.direction.value == "Up" else "↓" print(f"{d} {bi.fx_a.dt:%m-%d} -> {bi.fx_b.dt:%m-%d} " f"H={bi.high:.0f} L={bi.low:.0f} len={bi.length}")这里fx_a.dt与fx_b.dt正是分型的时间字段(取中间 K 线时间),反映了转折时点的精确刻度。
七、仓库集成:分型在信号引擎中的实战落地
分型本身是形态识别单元,但真正的实战价值体现在它如何驱动交易信号。仓库中的 example_signal_engine.py 演示了完整的落地链路。
7.1 引擎整体链路
OHLCV DataFrame → _df_to_bars → RawBar列表 → CZSC(bars[:30], get_signals=...) → 逐根 c.update(bar) 增量更新 → _evaluate_signals → 1(做多)/-1(做空)/0(观望)其中CZSC在内部完成去包含 → 分型 → 笔 → 中枢的自动构建,分型识别对用户完全透明,但信号判定逻辑需要显式引用分型的下游产物(笔与中枢)。
7.2 分型派生信号在引擎中的判定逻辑
_evaluate_signals方法展示了分型识别结果如何被逐级消费:
# 一买/一卖信号(背驰点 + 分型确认) buy1_key = [k for k in signals if "BUY1" in k] if buy1_key and "一买" in str(signals.get(buy1_key[0], "")): return 1 # 三笔形态:向上盘背做多 / 向下盘背做空 three_bi_key = [k for k in signals if "三笔" in k] if three_bi_key: val = str(signals.get(three_bi_key[0], "")) if "向上盘背" in val: return 1 if "向下盘背" in val: return -1 # 笔基础信号 + 中枢位置辅助 bi_key = [k for k in signals if "V230228" in k] if bi_key and len(c.bi_list) >= 3: val = str(signals.get(bi_key[0], "")) zs = _check_zhongshu(c.bi_list) if zs and zs.is_valid: last_close = c.bars_raw[-1].close if "向下_转折" in val and last_close <= zs.zd: return 1 if "向上_转折" in val and last_close >= zs.zg: return -1信号约定(与 SKILL.md 一致):
| 信号 | 含义 | 引擎输出 |
|---|---|---|
1 | 做多 | 一买、三笔向上盘背、五笔类一买、中枢下沿附近向下转折 |
-1 | 做空 | 一卖、三笔向下盘背、五笔类一卖、中枢上沿附近向上转折 |
0 | 观望 | 其余情况 |
注意:这里的"一买/一卖"信号需要底/顶分型作为最终确认条件(见 一买一卖.md),而中枢位置辅助判断依赖的是c.bi_list——笔的端点即分型,因此分型识别质量是这一切的根基。
7.3 完整可运行示例:BTC-USDT 日线信号
example_signal_engine.py的__main__部分给出了一个端到端示例,拉取 OKX 的 BTC-USDT 日线数据并运行信号引擎:
import requests import pandas as pd from czsc import Freq BASE_URL = "https://www.okx.com/api/v5" # 获取 BTC 日线数据 resp = requests.get(f"{BASE_URL}/market/candles", params={ "instId": "BTC-USDT", "bar": "1D", "limit": "300" }) candles = resp.json()["data"] # 转为 DataFrame(注意接口返回倒序,需 reversed) columns = ["ts", "open", "high", "low", "close", "vol", "volCcy", "volCcyQuote", "confirm"] df = pd.DataFrame(reversed(candles), columns=columns) df["ts"] = pd.to_datetime(df["ts"].astype("int64"), unit="ms") df = df.set_index("ts") for col in ["open", "high", "low", "close"]: df[col] = df[col].astype(float) df["volume"] = df["vol"].astype(float) df["amount"] = df["volCcy"].astype(float) # 运行信号引擎 engine = SignalEngine(freq=Freq.D) signals = engine.generate({"BTC-USDT": df}) # 输出结果 sig = signals["BTC-USDT"] buys = sig[sig == 1] sells = sig[sig == -1] print(f"BTC-USDT 缠论信号 ({len(df)} 根K线)") print(f" 做多信号: {len(buys)} 个") print(f" 做空信号: {len(sells)} 个") if len(buys) > 0: print(f" 最近做多: {buys.index[-1]:%Y-%m-%d}") if len(sells) > 0: print(f" 最近做空: {sells.index[-1]:%Y-%m-%d}")7.4 从 DataFrame 构造 RawBar
引擎的数据入口是_df_to_bars,它将任意 OHLCV DataFrame 规范化为czsc的RawBar列表,这也是分型识别的输入格式:
def _df_to_bars(df: pd.DataFrame, symbol: str, freq: Freq = Freq.D) -> list: bars = [] for i, (dt, row) in enumerate(df.iterrows()): if not isinstance(dt, datetime): dt = pd.Timestamp(dt).to_pydatetime() bars.append(RawBar( symbol=symbol, id=i, dt=dt, freq=freq, open=float(row["open"]), close=float(row["close"]), high=float(row["high"]), low=float(row["low"]), vol=float(row.get("volume", row.get("vol", 0))), amount=float(row.get("amount", 0)), )) return barsRawBar的完整字段约定(引自 SKILL.md):
| 字段 | 类型 | 说明 |
|---|---|---|
symbol | str | 标的代码 |
id | int | 序号(从 0 开始) |
dt | datetime | 时间 |
freq | Freq | 频率:Freq.F1/F5/F15/F30/F60/D/W/M |
open | float | 开盘价 |
close | float | 收盘价 |
high | float | 最高价 |
low | float | 最低价 |
vol | float | 成交量 |
amount | float | 成交额 |
7.5 引擎的增量更新机制
generate方法展示了分型/笔的增量计算模式:
if len(bars) < 30: result[code] = signal continue # 先用前 30 根K线初始化分析器,再逐根增量更新 c = CZSC(bars[:30], get_signals=_get_signals) for bar in bars[30:]: c.update(bar) sig = self._evaluate_signals(c) if sig != 0: signal.iloc[bar.id] = sig这种"初始批次 + 逐根c.update(bar)"的模式,充分利用了 czsc 的增量更新能力(SKILL.md 明确说明 czsc "支持增量更新,适合实时分析")。这意味着分型识别不是每次全量重算,而是新 K 线到达时局部刷新,适合实盘流式行情场景。同时少于 30 根 K 线的标的会被跳过,保证了分型、笔识别有足够的预热数据。
7.6 信号函数的选择
引擎选用的缠论信号函数(来自czsc.signals.cxt):
from czsc.signals.cxt import ( cxt_first_buy_V221126, cxt_first_sell_V221126, cxt_bi_base_V230228, cxt_three_bi_V230619, cxt_five_bi_V230619, )在 SKILL.md 中,czsc 共内置 43 个缠论信号函数,核心分类如下:
| 函数 | 说明 | 类型 |
|---|---|---|
cxt_first_buy_V221126 | 一买信号 | 买卖点 |
cxt_first_sell_V221126 | 一卖信号 | 买卖点 |
cxt_second_bs_V230320 | 均线辅助二买二卖 | 买卖点 |
cxt_third_bs_V230318 | 均线辅助三买三卖 | 买卖点 |
cxt_third_buy_V230228 | 笔三买辅助 | 买卖点 |
cxt_double_zs_V230311 | 两中枢组合判断 BS1 | 中枢 |
cxt_three_bi_V230618 | 三笔形态分类 | 形态 |
cxt_five_bi_V230619 | 五笔形态分类 | 形态 |
cxt_seven_bi_V230620 | 七笔形态分类 | 形态 |
cxt_nine_bi_V230621 | 九笔形态分类 | 形态 |
cxt_eleven_bi_V230622 | 十一笔形态分类 | 形态 |
cxt_bi_base_V230228 | BI 基础信号(方向/转折) | 基础 |
cxt_bi_end_V230312 | MACD 辅助笔结束 | 辅助 |
cxt_range_oscillation_V230620 | 区间震荡判断 | 辅助 |
cxt_zhong_shu_gong_zhen_V221221 | 大小级别中枢共振 | 中枢 |
其中一买/一卖信号函数还以di=1参数显式指定"倒数第 1 笔"作为判定基准(见 一买一卖.md),信号输出格式为{freq}_D{di}B_BUY1/{freq}_D{di}B_SELL1。
八、分型与其他核心概念的衔接
理解分型,必须同时理解它在缠论体系中的上下游关系:
| 概念 | 与分型的关系 | 详细文档 |
|---|---|---|
| 分型(FX) | 本文主题:三根去包含 K 线的形态单元 | 分型.md |
| 笔(BI) | 笔的端点就是分型(顶底交替、无包含、最小 7 根去包含 K 线) | 笔.md |
| 中枢(ZS) | 至少 3 笔构成的价格重叠区域,分型→笔→中枢的第三层 | 中枢.md |
| 一买/一卖 | 背驰 + 分型确认的趋势反转信号 | 一买一卖.md |
| 二买/二卖 | 一买/一卖后回调不破底/顶的确认信号 | 二买二卖.md |
| 三买/三卖 | 中枢上移/下移后回调不进入前中枢的信号 | 三买三卖.md |
从仓库结构看,chanlun技能还被用于多智能体协同场景:在 technical_analysis_panel.yaml 中,wave_analyst(波浪分析师)智能体被配置为同时加载elliott-wave与chanlun两个技能(skills: [elliott-wave, chanlun]),并将缠论的分型/笔/中枢结构作为艾略特波浪计数的交叉验证("Fractal strokes strict, Segments and central pivot ranges")。这表明分型识别不仅是单标的的技术指标,还能为多分析师团队的形态共振判断提供独立证据链。
九、实战注意事项与常见误区
- 分型必须基于去包含序列:直接对原始 K 线找"三根形态"会得到大量假分型,务必确认数据已通过 czsc 的包含处理。
- 分型不等于转折确认:顶分型出现后价格可能继续创新高(分型失败),实盘建议结合 MACD 背驰(
cxt_bi_end_V230312)或中枢位置辅助过滤。 - 数据预热要求:信号引擎要求至少 30 根 K 线(
len(bars) < 30直接跳过),更精细的买卖点判定需要更长的笔序列(如 一买一卖.md 要求至少两个向下/向上中枢)。 - 频率选择:
Freq.D(日线)适合趋势级分析;Freq.F30/F60适合日内;分型数量会随周期缩短而增多,注意噪声放大。 - 安装依赖:运行前需安装
czsc(v0.9.68+,纯 Python 实现,可选 Rust 加速后端):
pip install czsc requests pandas- 适用范围:分型识别只依赖 OHLCV 数据,因此适用于任何有 K 线数据的市场(A 股、加密货币、期货等),无需额外的基本面或新闻输入。
十、小结
分型是缠论最基础的识别单元:三根去包含后的 K 线,通过中间 K 线的高点/低点同时最高(顶分型)或同时最低(底分型)来判定局部力量衰竭。它的上游是去包含处理(上升取大、下降取小),下游则是笔、中枢与整个买卖点体系。在 Vibe-Trading 中,分型识别通过czsc的FX数据结构与CZSC分析器自动完成,并经由 example_signal_engine.py 的SignalEngine将分型派生的笔与中枢信号转化为1/-1/0的可执行交易信号,同时支持增量更新以适配实时行情。掌握分型的判定逻辑与数据结构,是理解并调优整套缠论信号引擎的第一步。
【免费下载链接】Vibe-Trading"Vibe-Trading: Your Personal Trading Agent"项目地址: https://gitcode.com/GitHub_Trending/vi/Vibe-Trading
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考