- Added support for a detailed chart mode in plot_converging_triangles.py, allowing users to visualize all pivot points and fitting lines. - Improved pivot fitting logic to utilize multiple representative points, enhancing detection accuracy and reducing false positives. - Introduced a new real-time detection mode with flexible zone parameters for better responsiveness in stock analysis. - Updated README.md and USAGE.md to reflect new features and usage instructions. - Added multiple documentation files detailing recent improvements, including pivot point fitting and visualization enhancements. - Cleaned up and archived outdated scripts to streamline the project structure.
339 lines
8.5 KiB
Markdown
339 lines
8.5 KiB
Markdown
# 枢轴点边界问题分析
|
||
|
||
## 问题描述
|
||
|
||
当前算法存在**边界盲区**问题:
|
||
|
||
### 枢轴点检测的范围限制
|
||
|
||
```python
|
||
for i in range(k, n - k): # k=15时,从索引15到n-16
|
||
if high[i] == np.max(high[i - k : i + k + 1]):
|
||
ph.append(i)
|
||
```
|
||
|
||
**问题**:最近 `k` 天(k=15,即最近15天)的数据**无法被识别为枢轴点**!
|
||
|
||
---
|
||
|
||
## 图解说明
|
||
|
||
### 检测窗口(假设window=120, k=15)
|
||
|
||
```
|
||
索引: 0 ... 14 15 ... 104 105 ... 119 (窗口末端=当前点)
|
||
↓ ↓ ↓ ↓ ↓ ↓
|
||
|--------|---|---------|---|--------|
|
||
无法检测 可以检测枢轴点 无法检测
|
||
(前15天) (中间90天) (后15天)
|
||
|
||
枢轴点检测范围: [15, 104] ← 只有这90天可以被识别
|
||
边界盲区: [0, 14] 和 [105, 119] ← 这30天无法识别!
|
||
```
|
||
|
||
### 实际影响
|
||
|
||
#### 场景1:当前点就是最高点(突破中)
|
||
|
||
```
|
||
价格
|
||
│ ○ (枢轴高点)
|
||
50│ / \
|
||
│ / \
|
||
45│ / \
|
||
│ / \ ★ (当前点=最高点)
|
||
40│ / \ /
|
||
│ ○ \ / ← 无法识别为枢轴!
|
||
35│ ○
|
||
│ ← 这是枢轴低点
|
||
└──────────────────────────────────→ 时间
|
||
←─── 120天窗口 ───→ ↑
|
||
当前点
|
||
(索引119)
|
||
|
||
枢轴点检测:
|
||
- ○ 可识别: 索引 < 105 的点
|
||
- ★ 不可识别: 索引 > 104 的点(最近15天)
|
||
|
||
问题: 当前上升突破的最高点无法被确认为枢轴点!
|
||
```
|
||
|
||
#### 场景2:三角形顶点在最近15天
|
||
|
||
```
|
||
价格
|
||
│ ○ (枢轴高点1)
|
||
45│ / \ ★ (近期高点,但无法识别)
|
||
│ / \ /\ /
|
||
40│ / \ / ★
|
||
│/ \ /
|
||
35│ \ / ○ (枢轴低点)
|
||
│ ○ /
|
||
30│ /
|
||
└────────────────────────────→ 时间
|
||
←── 120天 ───→ ↑
|
||
当前点
|
||
|
||
问题: 三角形的后半部分高点/低点可能被忽略!
|
||
```
|
||
|
||
---
|
||
|
||
## 数值示例(k=15)
|
||
|
||
### 假设检测窗口
|
||
|
||
- 窗口大小: 120天
|
||
- 索引范围: [0, 119]
|
||
- 当前点: 索引119
|
||
|
||
### 枢轴点可检测范围
|
||
|
||
```python
|
||
for i in range(15, 120 - 15): # range(15, 105)
|
||
# 可检测范围: 索引 15~104
|
||
# 共90个位置
|
||
```
|
||
|
||
### 边界盲区
|
||
|
||
- **前15天**: 索引 0~14(需要左边的15天数据,不存在)
|
||
- **后15天**: 索引 105~119(需要右边的15天数据,不存在)
|
||
- **盲区大小**: 30天(占窗口的25%!)
|
||
|
||
---
|
||
|
||
## 实际案例分析
|
||
|
||
### 您的问题场景
|
||
|
||
```
|
||
当前是 2026-01-20
|
||
检测窗口: 2025-08-21 ~ 2026-01-20 (120天)
|
||
|
||
假设股票走势:
|
||
- 2025-12-20 (索引90): 高点 50元 ✓ 可识别为枢轴
|
||
- 2026-01-05 (索引105): 高点 48元 ✗ 无法识别!
|
||
- 2026-01-20 (索引119): 当前 52元 ✗ 无法识别!
|
||
|
||
结果: 算法可能遗漏最近的重要转折点
|
||
```
|
||
|
||
---
|
||
|
||
## 潜在影响
|
||
|
||
### 1. 遗漏近期突破点
|
||
|
||
如果当前点附近(最近15天内)有重要的高点/低点,无法被识别为枢轴点,
|
||
导致三角形边界线拟合不准确。
|
||
|
||
### 2. 检测滞后
|
||
|
||
三角形形态可能已经完整形成并突破,但因为最近的关键点无法确认,
|
||
检测结果会滞后15天左右。
|
||
|
||
### 3. 突破判断不准
|
||
|
||
当前点的突破判断依赖三角形边界线,如果边界线因遗漏近期枢轴点
|
||
而不准确,突破强度计算会有偏差。
|
||
|
||
---
|
||
|
||
## 解决方案选项
|
||
|
||
### 方案1:右边界放宽(推荐)
|
||
|
||
修改枢轴点检测,允许使用"不完整右窗口":
|
||
|
||
```python
|
||
def pivots_fractal_flexible(
|
||
high: np.ndarray, low: np.ndarray, k: int = 3
|
||
) -> Tuple[np.ndarray, np.ndarray]:
|
||
"""
|
||
灵活枢轴点检测:
|
||
- 中间部分:严格左右各k天
|
||
- 右边界:放宽要求,只需要"已有的"右边数据
|
||
"""
|
||
n = len(high)
|
||
ph: List[int] = []
|
||
pl: List[int] = []
|
||
|
||
# 标准检测:中间部分(左右各k天)
|
||
for i in range(k, n - k):
|
||
if high[i] == np.max(high[i - k : i + k + 1]):
|
||
ph.append(i)
|
||
if low[i] == np.min(low[i - k : i + k + 1]):
|
||
pl.append(i)
|
||
|
||
# 右边界扩展:最后k天,使用"已有的"右边数据
|
||
for i in range(n - k, n):
|
||
# 右边窗口缩短到可用范围
|
||
right_window = min(k, n - 1 - i)
|
||
if high[i] == np.max(high[i - k : i + right_window + 1]):
|
||
ph.append(i)
|
||
if low[i] == np.min(low[i - k : i + right_window + 1]):
|
||
pl.append(i)
|
||
|
||
return np.array(ph, dtype=int), np.array(pl, dtype=int)
|
||
```
|
||
|
||
**优点**:
|
||
- 可以捕获最近的高低点
|
||
- 适合实时检测场景
|
||
|
||
**缺点**:
|
||
- 最近的枢轴点"确认度"较低(右边数据不完整)
|
||
- 可能引入噪音
|
||
|
||
---
|
||
|
||
### 方案2:减小k值
|
||
|
||
将 `pivot_k` 从15减小到5-8:
|
||
|
||
```python
|
||
DETECTION_PARAMS = ConvergingTriangleParams(
|
||
pivot_k=8, # 从15降到8,减少盲区
|
||
...
|
||
)
|
||
```
|
||
|
||
**优点**:
|
||
- 盲区从30天减少到16天
|
||
- 更灵敏,适合短期形态
|
||
|
||
**缺点**:
|
||
- 可能捕获更多噪音
|
||
- 三角形质量下降
|
||
|
||
---
|
||
|
||
### 方案3:使用"确认滞后"模式(当前方案)
|
||
|
||
保持现状,但明确告知用户:
|
||
- 检测结果有15天的"确认滞后"
|
||
- 适合历史复盘,不适合实时交易
|
||
|
||
**优点**:
|
||
- 枢轴点质量高(充分确认)
|
||
- 结果稳定可靠
|
||
|
||
**缺点**:
|
||
- 有滞后性
|
||
- 错过实时突破
|
||
|
||
---
|
||
|
||
### 方案4:混合策略(最佳)
|
||
|
||
分两类枢轴点:
|
||
|
||
```python
|
||
def pivots_fractal_hybrid(high, low, k=15, flexible_zone=5):
|
||
"""
|
||
混合枢轴点检测:
|
||
- 确认枢轴点:有完整左右k天数据(高质量)
|
||
- 候选枢轴点:右边数据不完整(低置信度)
|
||
"""
|
||
n = len(high)
|
||
|
||
# 确认枢轴点(完整窗口)
|
||
confirmed_ph = []
|
||
confirmed_pl = []
|
||
for i in range(k, n - k):
|
||
if high[i] == np.max(high[i - k : i + k + 1]):
|
||
confirmed_ph.append(i)
|
||
if low[i] == np.min(low[i - k : i + k + 1]):
|
||
confirmed_pl.append(i)
|
||
|
||
# 候选枢轴点(最近flexible_zone天,降低要求)
|
||
candidate_ph = []
|
||
candidate_pl = []
|
||
for i in range(n - flexible_zone, n):
|
||
right_avail = n - 1 - i
|
||
if high[i] == np.max(high[i - k : i + right_avail + 1]):
|
||
candidate_ph.append(i)
|
||
if low[i] == np.min(low[i - k : i + right_avail + 1]):
|
||
candidate_pl.append(i)
|
||
|
||
return (
|
||
np.array(confirmed_ph + candidate_ph),
|
||
np.array(confirmed_pl + candidate_pl)
|
||
)
|
||
```
|
||
|
||
**优点**:
|
||
- 兼顾质量和实时性
|
||
- 可以标记"待确认"的点
|
||
|
||
**缺点**:
|
||
- 逻辑较复杂
|
||
- 需要额外的置信度管理
|
||
|
||
---
|
||
|
||
## 建议
|
||
|
||
### 对于当前项目
|
||
|
||
**场景**: "当前点往过去看",用于历史回测和复盘
|
||
|
||
**推荐**: **保持方案3(当前模式)+ 文档说明**
|
||
|
||
理由:
|
||
1. 历史回测不需要实时性
|
||
2. 高质量枢轴点保证检测准确性
|
||
3. 滞后15天对回测影响不大
|
||
|
||
**改进措施**:
|
||
- 在文档中明确说明15天的"确认窗口"
|
||
- 建议用户查看 "T-15天" 的检测结果,作为当前参考
|
||
|
||
---
|
||
|
||
### 对于未来扩展
|
||
|
||
如果要支持**实时交易**场景,建议:
|
||
1. 实现方案4(混合策略)
|
||
2. 添加"置信度"字段区分确认枢轴和候选枢轴
|
||
3. 提供 `real_time_mode=True` 参数选项
|
||
|
||
---
|
||
|
||
## 验证脚本
|
||
|
||
创建测试用例,验证边界问题:
|
||
|
||
```python
|
||
def test_boundary_pivots():
|
||
# 模拟一个在窗口末端有高点的情况
|
||
high = np.zeros(120)
|
||
high[50] = 45 # 中间高点(可识别)
|
||
high[110] = 50 # 末端高点(k=15时无法识别)
|
||
|
||
low = np.ones(120) * 30
|
||
|
||
ph_idx, pl_idx = pivots_fractal(high, low, k=15)
|
||
|
||
print(f"检测到的高点枢轴: {ph_idx}")
|
||
print(f"是否检测到索引110的高点: {110 in ph_idx}") # False!
|
||
```
|
||
|
||
---
|
||
|
||
## 总结
|
||
|
||
您的观察**完全正确**:
|
||
|
||
1. ✅ **问题确实存在**: 最近k天(k=15)的数据无法被识别为枢轴点
|
||
2. ✅ **影响场景**: 当前点附近的重要转折点可能被遗漏
|
||
3. ✅ **盲区大小**: 30天(前15+后15),占窗口的25%
|
||
4. ⚠️ **当前项目**: 保持现状可接受(历史回测场景)
|
||
5. 🔧 **未来改进**: 实时交易场景需要方案4(混合策略)
|
||
|
||
**建议**:
|
||
- 短期:在文档中说明这个限制
|
||
- 长期:如果要做实时选股,需要实现灵活枢轴点检测
|
||
|