chan-lun-core 0.1.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Chan Contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,157 @@
1
+ Metadata-Version: 2.4
2
+ Name: chan-lun-core
3
+ Version: 0.1.4
4
+ Summary: 缠论(缠中说禅理论)量化核心库: 分型/笔/线段/中枢/背驰/买卖点 + 30 分钟跨级别共振确认, 纯 Python 实现, 仅依赖 numpy/pandas
5
+ Author: Chan Contributors
6
+ License: MIT License
7
+
8
+ Copyright (c) 2026 Chan Contributors
9
+
10
+ Permission is hereby granted, free of charge, to any person obtaining a copy
11
+ of this software and associated documentation files (the "Software"), to deal
12
+ in the Software without restriction, including without limitation the rights
13
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14
+ copies of the Software, and to permit persons to whom the Software is
15
+ furnished to do so, subject to the following conditions:
16
+
17
+ The above copyright notice and this permission notice shall be included in all
18
+ copies or substantial portions of the Software.
19
+
20
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26
+ SOFTWARE.
27
+
28
+ Project-URL: Homepage, https://github.com/lushi78778/chan-lun
29
+ Project-URL: Repository, https://github.com/lushi78778/chan-lun
30
+ Keywords: chan,chanlun,缠论,缠中说禅,technical-analysis,quant,stock,kline,trading
31
+ Classifier: Development Status :: 4 - Beta
32
+ Classifier: Intended Audience :: Financial and Insurance Industry
33
+ Classifier: Intended Audience :: Science/Research
34
+ Classifier: License :: OSI Approved :: MIT License
35
+ Classifier: Natural Language :: Chinese (Simplified)
36
+ Classifier: Operating System :: OS Independent
37
+ Classifier: Programming Language :: Python :: 3
38
+ Classifier: Programming Language :: Python :: 3.6
39
+ Classifier: Programming Language :: Python :: 3.7
40
+ Classifier: Programming Language :: Python :: 3.8
41
+ Classifier: Programming Language :: Python :: 3.9
42
+ Classifier: Programming Language :: Python :: 3.10
43
+ Classifier: Programming Language :: Python :: 3.11
44
+ Classifier: Programming Language :: Python :: 3.12
45
+ Classifier: Programming Language :: Python :: 3.13
46
+ Classifier: Topic :: Office/Business :: Financial :: Investment
47
+ Requires-Python: >=3.6
48
+ Description-Content-Type: text/markdown
49
+ License-File: LICENSE
50
+ Requires-Dist: numpy>=1.14
51
+ Requires-Dist: pandas>=0.23
52
+ Dynamic: license-file
53
+
54
+ # chan-lun
55
+
56
+ 缠论(缠中说禅理论)量化核心库 —— 分型 / 笔 / 线段 / 中枢 / 背驰 / 三类买卖点,
57
+ 外加日线信号 → 30 分钟级别的跨级别共振确认(区间套)。
58
+
59
+ 纯 Python 实现,**不依赖任何行情接口**:输入标准化 bar 序列,输出结构对象与信号。
60
+ 只依赖 numpy(背驰计算)与 pandas(bars 归一化辅助)。
61
+
62
+ - 发行名:**chan-lun-core**(PyPI 上 `chan` 已被占用, `chan-lun` 与现有 `chanlun` 冲突, 故加 `-core` 后缀)
63
+ - import 名:`chan`
64
+ - 许可证:MIT
65
+
66
+ ## 安装
67
+
68
+ 从 PyPI 安装(打 `v*` tag 后 CI 自动发布):
69
+
70
+ ```bash
71
+ pip install chan-lun-core
72
+ ```
73
+
74
+ 从 GitHub Release 安装(同样由 CI 自动构建):
75
+
76
+ ```bash
77
+ pip install https://github.com/lushi78778/chan-lun/releases/download/v0.1.4/chan_lun_core-0.1.4-py3-none-any.whl
78
+ ```
79
+
80
+ 或源码安装:
81
+
82
+ ```bash
83
+ pip install git+https://github.com/lushi78778/chan-lun.git
84
+ ```
85
+
86
+ 要求 Python >= 3.6、numpy >= 1.14、pandas >= 0.23
87
+ (与聚宽研究环境 3.6.7 / numpy 1.14.6 / pandas 0.23.4 对齐,新版同样兼容)。
88
+
89
+ ## 数据约定
90
+
91
+ 所有模块的输入/输出都是**纯 Python 结构**(list of dict / 简单对象),
92
+ 与数据来源无关:
93
+
94
+ ```python
95
+ # 标准 bar: 按时间升序的 dict 列表
96
+ bars = [
97
+ {"dt": ..., "open": ..., "high": ..., "low": ..., "close": ..., "volume": ...},
98
+ ...
99
+ ]
100
+ ```
101
+
102
+ `chan.bars.normalize_bars` 负责把聚宽 `get_price`/`get_bars` 等返回的
103
+ DataFrame 转成标准 bar 序列(列名可配置)。
104
+
105
+ ## 模块与流水线
106
+
107
+ | 模块 | 功能 | 主要入口 |
108
+ |---|---|---|
109
+ | `chan.bars` | 行情归一化 | `normalize_bars`, `bars_to_df` |
110
+ | `chan.fx` | 包含处理 + 分型 | `remove_includes`, `find_fxs` |
111
+ | `chan.bi` | 笔识别 | `find_bis`, `chan_fx_bi` |
112
+ | `chan.xd` | 线段(特征序列两种标准) | `find_xds`, `chan_bis_xds` |
113
+ | `chan.zs` | 中枢与走势类型 | `find_zs`, `classify_trend` |
114
+ | `chan.bc` | 背驰(MACD 辅助) | `macd_series`, `find_trend_bc`, `find_pan_bc` |
115
+ | `chan.bs` | 三类买卖点 | `find_buy_points`, `find_sell_points` |
116
+ | `chan.cross30` | 30m 跨级别共振确认 | `confirm_buy3_30m`, `confirm_sell3_30m` |
117
+
118
+ 最小示例(完整管线):
119
+
120
+ ```python
121
+ from chan.bars import normalize_bars
122
+ from chan.bi import chan_fx_bi
123
+ from chan.xd import chan_bis_xds
124
+ from chan.zs import find_zs
125
+ from chan.bc import macd_series, find_trend_bc
126
+ from chan.bs import find_buy_points
127
+
128
+ bars = normalize_bars(df) # df -> 标准 bar 列表
129
+ bis = chan_fx_bi(bars) # 分型 -> 笔
130
+ xds = chan_bis_xds(bars) # 笔 -> 线段
131
+ zss = find_zs(xds) # 线段 -> 中枢
132
+ dif, dea, hist = macd_series(bars) # MACD
133
+ bc = find_trend_bc(bis, zss, bars) # 趋势背驰
134
+ buys = find_buy_points(bis, zss) # 三类买点
135
+ ```
136
+
137
+ 跨级别确认(日线三买 → 30 分钟底背驰 + 守中枢上沿):
138
+
139
+ ```python
140
+ from chan.cross30 import confirm_buy3_30m
141
+
142
+ r = confirm_buy3_30m(bars30, zd=zg_of_day_zs, zg=zg_of_day_zs, signal_dt=...)
143
+ # r["status"] in {"confirmed", "weak", "no_exhaustion", "broke", "stale", "no_data"}
144
+ ```
145
+
146
+ ## 兼容性
147
+
148
+ - Python 3.6+ 语法(无 walrus / dataclasses / f-string 自描述等 3.7+ 特性)
149
+ - pandas 0.23+ API(无 to_numpy / to_markdown 等新 API)
150
+
151
+ ## 免责声明
152
+
153
+ 本库仅用于研究与学习,输出不构成任何投资建议。
154
+
155
+ ## 许可证
156
+
157
+ MIT,见 [LICENSE](LICENSE)。
@@ -0,0 +1,104 @@
1
+ # chan-lun
2
+
3
+ 缠论(缠中说禅理论)量化核心库 —— 分型 / 笔 / 线段 / 中枢 / 背驰 / 三类买卖点,
4
+ 外加日线信号 → 30 分钟级别的跨级别共振确认(区间套)。
5
+
6
+ 纯 Python 实现,**不依赖任何行情接口**:输入标准化 bar 序列,输出结构对象与信号。
7
+ 只依赖 numpy(背驰计算)与 pandas(bars 归一化辅助)。
8
+
9
+ - 发行名:**chan-lun-core**(PyPI 上 `chan` 已被占用, `chan-lun` 与现有 `chanlun` 冲突, 故加 `-core` 后缀)
10
+ - import 名:`chan`
11
+ - 许可证:MIT
12
+
13
+ ## 安装
14
+
15
+ 从 PyPI 安装(打 `v*` tag 后 CI 自动发布):
16
+
17
+ ```bash
18
+ pip install chan-lun-core
19
+ ```
20
+
21
+ 从 GitHub Release 安装(同样由 CI 自动构建):
22
+
23
+ ```bash
24
+ pip install https://github.com/lushi78778/chan-lun/releases/download/v0.1.4/chan_lun_core-0.1.4-py3-none-any.whl
25
+ ```
26
+
27
+ 或源码安装:
28
+
29
+ ```bash
30
+ pip install git+https://github.com/lushi78778/chan-lun.git
31
+ ```
32
+
33
+ 要求 Python >= 3.6、numpy >= 1.14、pandas >= 0.23
34
+ (与聚宽研究环境 3.6.7 / numpy 1.14.6 / pandas 0.23.4 对齐,新版同样兼容)。
35
+
36
+ ## 数据约定
37
+
38
+ 所有模块的输入/输出都是**纯 Python 结构**(list of dict / 简单对象),
39
+ 与数据来源无关:
40
+
41
+ ```python
42
+ # 标准 bar: 按时间升序的 dict 列表
43
+ bars = [
44
+ {"dt": ..., "open": ..., "high": ..., "low": ..., "close": ..., "volume": ...},
45
+ ...
46
+ ]
47
+ ```
48
+
49
+ `chan.bars.normalize_bars` 负责把聚宽 `get_price`/`get_bars` 等返回的
50
+ DataFrame 转成标准 bar 序列(列名可配置)。
51
+
52
+ ## 模块与流水线
53
+
54
+ | 模块 | 功能 | 主要入口 |
55
+ |---|---|---|
56
+ | `chan.bars` | 行情归一化 | `normalize_bars`, `bars_to_df` |
57
+ | `chan.fx` | 包含处理 + 分型 | `remove_includes`, `find_fxs` |
58
+ | `chan.bi` | 笔识别 | `find_bis`, `chan_fx_bi` |
59
+ | `chan.xd` | 线段(特征序列两种标准) | `find_xds`, `chan_bis_xds` |
60
+ | `chan.zs` | 中枢与走势类型 | `find_zs`, `classify_trend` |
61
+ | `chan.bc` | 背驰(MACD 辅助) | `macd_series`, `find_trend_bc`, `find_pan_bc` |
62
+ | `chan.bs` | 三类买卖点 | `find_buy_points`, `find_sell_points` |
63
+ | `chan.cross30` | 30m 跨级别共振确认 | `confirm_buy3_30m`, `confirm_sell3_30m` |
64
+
65
+ 最小示例(完整管线):
66
+
67
+ ```python
68
+ from chan.bars import normalize_bars
69
+ from chan.bi import chan_fx_bi
70
+ from chan.xd import chan_bis_xds
71
+ from chan.zs import find_zs
72
+ from chan.bc import macd_series, find_trend_bc
73
+ from chan.bs import find_buy_points
74
+
75
+ bars = normalize_bars(df) # df -> 标准 bar 列表
76
+ bis = chan_fx_bi(bars) # 分型 -> 笔
77
+ xds = chan_bis_xds(bars) # 笔 -> 线段
78
+ zss = find_zs(xds) # 线段 -> 中枢
79
+ dif, dea, hist = macd_series(bars) # MACD
80
+ bc = find_trend_bc(bis, zss, bars) # 趋势背驰
81
+ buys = find_buy_points(bis, zss) # 三类买点
82
+ ```
83
+
84
+ 跨级别确认(日线三买 → 30 分钟底背驰 + 守中枢上沿):
85
+
86
+ ```python
87
+ from chan.cross30 import confirm_buy3_30m
88
+
89
+ r = confirm_buy3_30m(bars30, zd=zg_of_day_zs, zg=zg_of_day_zs, signal_dt=...)
90
+ # r["status"] in {"confirmed", "weak", "no_exhaustion", "broke", "stale", "no_data"}
91
+ ```
92
+
93
+ ## 兼容性
94
+
95
+ - Python 3.6+ 语法(无 walrus / dataclasses / f-string 自描述等 3.7+ 特性)
96
+ - pandas 0.23+ API(无 to_numpy / to_markdown 等新 API)
97
+
98
+ ## 免责声明
99
+
100
+ 本库仅用于研究与学习,输出不构成任何投资建议。
101
+
102
+ ## 许可证
103
+
104
+ MIT,见 [LICENSE](LICENSE)。
@@ -0,0 +1,55 @@
1
+ # chan-lun-core 发布配置(仓库根 = src/chan, 标准 src-layout, 见 PyPA 官方教程)
2
+ # 发行名 chan-lun-core(import 名仍是 chan): PyPI 拒绝 `chan-lun`(与现有
3
+ # `chanlun` 过于相似); chan-lun-core 已按 PyPI ultranormalize 规则
4
+ # (去 ._- / l,i->1 / o->0)逐变体验证无冲突。
5
+ # 注意: version 与 src/chan/__init__.py 的 __version__ 需保持一致。
6
+ [build-system]
7
+ requires = ["setuptools>=61"]
8
+ build-backend = "setuptools.build_meta"
9
+
10
+ [project]
11
+ name = "chan-lun-core"
12
+ version = "0.1.4"
13
+ description = "缠论(缠中说禅理论)量化核心库: 分型/笔/线段/中枢/背驰/买卖点 + 30 分钟跨级别共振确认, 纯 Python 实现, 仅依赖 numpy/pandas"
14
+ readme = "README.md"
15
+ requires-python = ">=3.6"
16
+ license = {file = "LICENSE"}
17
+ authors = [{name = "Chan Contributors"}]
18
+ keywords = [
19
+ "chan", "chanlun", "缠论", "缠中说禅",
20
+ "technical-analysis", "quant", "stock", "kline", "trading",
21
+ ]
22
+ classifiers = [
23
+ "Development Status :: 4 - Beta",
24
+ "Intended Audience :: Financial and Insurance Industry",
25
+ "Intended Audience :: Science/Research",
26
+ "License :: OSI Approved :: MIT License",
27
+ "Natural Language :: Chinese (Simplified)",
28
+ "Operating System :: OS Independent",
29
+ "Programming Language :: Python :: 3",
30
+ "Programming Language :: Python :: 3.6",
31
+ "Programming Language :: Python :: 3.7",
32
+ "Programming Language :: Python :: 3.8",
33
+ "Programming Language :: Python :: 3.9",
34
+ "Programming Language :: Python :: 3.10",
35
+ "Programming Language :: Python :: 3.11",
36
+ "Programming Language :: Python :: 3.12",
37
+ "Programming Language :: Python :: 3.13",
38
+ "Topic :: Office/Business :: Financial :: Investment",
39
+ ]
40
+ dependencies = [
41
+ # 与聚宽研究环境(3.6.7 / numpy 1.14.6 / pandas 0.23.4)对齐的下限;
42
+ # 新版 numpy/pandas 同样兼容。
43
+ "numpy>=1.14",
44
+ "pandas>=0.23",
45
+ ]
46
+
47
+ [project.urls]
48
+ Homepage = "https://github.com/lushi78778/chan-lun"
49
+ Repository = "https://github.com/lushi78778/chan-lun"
50
+
51
+ [tool.setuptools]
52
+ package-dir = {"" = "src"}
53
+
54
+ [tool.setuptools.packages.find]
55
+ where = ["src"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,19 @@
1
+ # -*- coding: utf-8 -*-
2
+ """chan 缠论量化核心包(纯 Python 3.6 兼容)
3
+
4
+ 模块:
5
+ bars - 行情数据归一化
6
+ fx - 包含处理 + 分型识别
7
+ bi - 笔识别
8
+ xd - 线段识别(特征序列两种标准)
9
+ zs - 中枢识别与走势类型
10
+ bc - 背驰识别(MACD 辅助: 趋势背驰/盘整背驰)
11
+ bs - 三类买卖点信号
12
+ cross30 - 日线买卖点 -> 30 分钟跨级别共振确认(区间套)
13
+
14
+ 发布: 发行名 chan-lun-core(import 名 chan), 仓库根 = src/chan(标准
15
+ src-layout, 本包位于仓库根的 src/chan/ 子目录, 见仓库根 pyproject.toml)。
16
+ 注意: __version__ 与 pyproject.toml 的 [project] version 需保持一致。
17
+ """
18
+
19
+ __version__ = "0.1.4"
@@ -0,0 +1,65 @@
1
+ # -*- coding: utf-8 -*-
2
+ """
3
+ chan.bars —— 行情数据归一化
4
+
5
+ 把聚宽 get_price / get_bars 返回的 DataFrame 转成标准的 bar 序列
6
+ (list of dict), 供缠论管线(分型/笔/线段)使用。
7
+
8
+ 兼容: Python 3.6, pandas 0.23
9
+ """
10
+
11
+ from __future__ import print_function
12
+
13
+ # 标准 bar 字段
14
+ BAR_KEYS = ["dt", "open", "high", "low", "close", "volume"]
15
+
16
+
17
+ def normalize_bars(df, dt_col="date", open_col="open", high_col="high",
18
+ low_col="low", close_col="close", volume_col="volume",
19
+ drop_paused=True):
20
+ """DataFrame -> 按时间升序的标准 bar 列表
21
+
22
+ 参数:
23
+ df: get_price/get_bars 返回的 DataFrame(单标的)
24
+ dt_col 等: 列名映射(聚宽默认列名即默认参数)
25
+ drop_paused: 丢弃停牌(成交量=0 且高低价持平)的 bar
26
+
27
+ 返回:
28
+ list of dict, 每项含 dt/open/high/low/close/volume;
29
+ dt 为原类型(datetime/Timestamp), 排序后保证时间递增。
30
+ """
31
+ if df is None or df.shape[0] == 0:
32
+ return []
33
+
34
+ # 时间列: get_bars 返回 date 列; get_price 返回时间为 index
35
+ use_index_dt = (dt_col not in df.columns)
36
+
37
+ price_cols = [open_col, high_col, low_col, close_col, volume_col]
38
+ for c in price_cols:
39
+ if c not in df.columns:
40
+ raise ValueError("缺少列: {}".format(c))
41
+
42
+ cols = price_cols
43
+ if use_index_dt:
44
+ out = df[cols].copy()
45
+ out.insert(0, "dt", df.index)
46
+ else:
47
+ out = df[[dt_col] + cols].copy()
48
+ out.columns = ["dt"] + price_cols
49
+ out.columns = BAR_KEYS
50
+ out = out.sort_values("dt")
51
+ # 数值化
52
+ for c in ["open", "high", "low", "close", "volume"]:
53
+ out[c] = out[c].astype(float)
54
+
55
+ bars = out.to_dict(orient="records")
56
+ if drop_paused:
57
+ bars = [b for b in bars
58
+ if not (b["volume"] == 0 and b["high"] == b["low"])]
59
+ return bars
60
+
61
+
62
+ def bars_to_df(bars):
63
+ """bar 列表 -> DataFrame(测试与展示用)"""
64
+ import pandas as pd
65
+ return pd.DataFrame(bars)
@@ -0,0 +1,193 @@
1
+ # -*- coding: utf-8 -*-
2
+ """
3
+ chan.bc —— 背驰识别(动力学, MACD 辅助)
4
+
5
+ 理论依据: doc/缠论知识库/04-背驰与区间套.md
6
+
7
+ 标准背驰(趋势背驰): 趋势(至少两个同向不重叠中枢)中, 最后中枢
8
+ 之后的离开段力度比前一连接段弱(MACD 柱面积), 且价格创新高/新低。
9
+ 盘整背驰: 中枢震荡中, 两段同向波动力度比较(用于中枢震荡短差)。
10
+
11
+ 力度度量(课24 MACD 辅助): 段对应的 MACD 柱(hist=(DIF-DEA)*2)面积,
12
+ 上涨段看红柱面积, 下跌段看绿柱面积; 简化: sum(hist) 的绝对值。
13
+
14
+ 兼容: Python 3.6, numpy。
15
+ """
16
+
17
+ from __future__ import print_function
18
+
19
+ import numpy as np
20
+
21
+
22
+ def ema(values, n):
23
+ """指数移动平均(纯 numpy 实现, 兼容老版本)"""
24
+ values = np.asarray(values, dtype=float)
25
+ out = np.empty(len(values))
26
+ k = 2.0 / (n + 1)
27
+ out[0] = values[0]
28
+ for i in range(1, len(values)):
29
+ out[i] = values[i] * k + out[i - 1] * (1 - k)
30
+ return out
31
+
32
+
33
+ def macd_series(bars, fast=12, slow=26, signal=9):
34
+ """MACD 指标序列
35
+
36
+ 返回: (dif, dea, hist) numpy 数组, hist = (dif - dea) * 2
37
+ """
38
+ closes = np.array([b["close"] for b in bars], dtype=float)
39
+ ema_fast = ema(closes, fast)
40
+ ema_slow = ema(closes, slow)
41
+ dif = ema_fast - ema_slow
42
+ dea = ema(dif, signal)
43
+ hist = (dif - dea) * 2.0
44
+ return dif, dea, hist
45
+
46
+
47
+ def _dt_index(bars):
48
+ """bars 的 dt -> 索引 映射(用最后一个匹配)"""
49
+ idx = {}
50
+ for i, b in enumerate(bars):
51
+ idx[str(b["dt"])] = i
52
+ return idx
53
+
54
+
55
+ def segment_area(hist, bars_index, dt_map, start_dt, end_dt):
56
+ """某段 [start_dt, end_dt] 的 MACD 柱面积(带符号 sum)
57
+
58
+ 返回: float(正=红柱主导/上涨, 负=绿柱主导/下跌)
59
+ """
60
+ i0 = dt_map.get(str(start_dt))
61
+ i1 = dt_map.get(str(end_dt))
62
+ if i0 is None or i1 is None:
63
+ return 0.0
64
+ if i0 > i1:
65
+ i0, i1 = i1, i0
66
+ i1 = min(i1 + 1, len(hist))
67
+ return float(np.sum(hist[i0:i1]))
68
+
69
+
70
+ def find_trend_bc(bis, zss, bars, hist=None):
71
+ """趋势背驰识别(基于笔级中枢)
72
+
73
+ 参数:
74
+ bis: 笔列表
75
+ zss: 中枢列表(通常由 find_zs(bis) 生成)
76
+ bars: 原始 bars(list of dict)
77
+ hist: MACD 柱序列(默认计算)
78
+
79
+ 返回: list of dict
80
+ {direction: 'up'/'down', dt, price, zs_idx, area_prev, area_last,
81
+ note}
82
+ 规则(向上趋势):
83
+ - 相邻两中枢后 DD > 前 GG(向上);
84
+ - 最后中枢之后离开段创新高;
85
+ - 离开段 MACD 面积 < 前一连接段面积 -> 顶背驰。
86
+ 向下趋势镜像 -> 底背驰。
87
+ """
88
+ if hist is None:
89
+ _, _, hist = macd_series(bars)
90
+ dt_map = _dt_index(bars)
91
+ out = []
92
+ if len(zss) < 2:
93
+ return out
94
+
95
+ for k in range(1, len(zss)):
96
+ prev, zs = zss[k - 1], zss[k]
97
+ up_trend = (zs.dd > prev.gg)
98
+ down_trend = (zs.gg < prev.dd)
99
+ if not (up_trend or down_trend):
100
+ continue
101
+ # 最后中枢(第 k 个)之后的离开段: 中枢 end_dt 之后的第一段同向笔
102
+ # 简化: 用最后一个中枢 end_dt 到最后一笔终点的区间
103
+ last_dt = bis[-1].end_dt
104
+ # 前一连接段: prev 中枢 end_dt -> zs 中枢 start_dt 之间
105
+ area_prev = segment_area(hist, bars, dt_map, prev.end_dt, zs.start_dt)
106
+ area_last = segment_area(hist, bars, dt_map, zs.end_dt, last_dt)
107
+ if up_trend:
108
+ # 离开段创新高
109
+ last_high = bis[-1].end_value if bis[-1].direction == "up" else bis[-1].start_value
110
+ prev_high = prev.gg
111
+ if last_high > prev_high and abs(area_last) < abs(area_prev) and area_last > 0:
112
+ out.append({"direction": "up", "dt": str(bis[-1].end_dt),
113
+ "price": last_high, "zs_idx": k,
114
+ "area_prev": abs(area_prev), "area_last": abs(area_last),
115
+ "note": "趋势顶背驰候选"})
116
+ else:
117
+ last_low = bis[-1].end_value if bis[-1].direction == "down" else bis[-1].start_value
118
+ prev_low = prev.dd
119
+ if last_low < prev_low and abs(area_last) < abs(area_prev) and area_last < 0:
120
+ out.append({"direction": "down", "dt": str(bis[-1].end_dt),
121
+ "price": last_low, "zs_idx": k,
122
+ "area_prev": abs(area_prev), "area_last": abs(area_last),
123
+ "note": "趋势底背驰候选"})
124
+ return out
125
+
126
+
127
+ def find_pan_bc(bis, zss, bars, hist=None, max_dev=0.15):
128
+ """盘整背驰识别(中枢震荡内两段同向波动力度比较)
129
+
130
+ 对每个中枢: 比较围绕中枢的相邻两段同向波动(向上离开 vs 进入)
131
+ 简化: 中枢区间内, 取笔序列中相邻两段同向笔(方向向上/向下),
132
+ 后段创新高/新低但面积更小 -> 盘整背驰。
133
+
134
+ v2 增强(位置过滤): 盘整背驰是"围绕中枢的波动"比较, 信号点必须
135
+ 距中枢不远; 创新高/新低后远离中枢(超过 max_dev 比例)的信号
136
+ 多为趋势延伸而非中枢震荡, 予以剔除。
137
+
138
+ 返回: list of dict
139
+ """
140
+ if hist is None:
141
+ _, _, hist = macd_series(bars)
142
+ dt_map = _dt_index(bars)
143
+ out = []
144
+ if not zss:
145
+ return out
146
+
147
+ for zi, zs in enumerate(zss):
148
+ # 找出中枢区间内的笔(起点或终点在中枢区间内)
149
+ segs = []
150
+ i = 0
151
+ n = len(bis)
152
+ while i < n:
153
+ bi = bis[i]
154
+ # 同向笔合并成"段"
155
+ seg = [bi]
156
+ j = i + 1
157
+ while j < n and bis[j].direction == bi.direction:
158
+ seg.append(bis[j])
159
+ j += 1
160
+ i = j
161
+ segs.append(seg)
162
+ # 同向段比较(A/B/C 模式: 隔一个反向段): 方向同为 up 或同为 down
163
+ for s in range(2, len(segs)):
164
+ a, b = segs[s - 2], segs[s]
165
+ if a[0].direction != b[0].direction:
166
+ continue
167
+ area_a = segment_area(hist, bars, dt_map,
168
+ a[0].start_dt, a[-1].end_dt)
169
+ area_b = segment_area(hist, bars, dt_map,
170
+ b[0].start_dt, b[-1].end_dt)
171
+ if abs(area_b) >= abs(area_a):
172
+ continue
173
+ if b[0].direction == "up":
174
+ if b[-1].end_value > a[-1].end_value:
175
+ price = b[-1].end_value
176
+ # 位置过滤: 信号价距中枢 GG 不超过 max_dev
177
+ if price <= zs.gg * (1 + max_dev):
178
+ out.append({"zs_idx": zi, "direction": "up",
179
+ "dt": str(b[-1].end_dt),
180
+ "price": price,
181
+ "area_prev": abs(area_a), "area_last": abs(area_b),
182
+ "note": "盘整顶背驰候选"})
183
+ else:
184
+ if b[-1].end_value < a[-1].end_value:
185
+ price = b[-1].end_value
186
+ # 位置过滤: 信号价距中枢 DD 不低于 max_dev
187
+ if price >= zs.dd * (1 - max_dev):
188
+ out.append({"zs_idx": zi, "direction": "down",
189
+ "dt": str(b[-1].end_dt),
190
+ "price": price,
191
+ "area_prev": abs(area_a), "area_last": abs(area_b),
192
+ "note": "盘整底背驰候选"})
193
+ return out