feat: 增加命令行参数以支持自定义枢轴点窗口、收敛比和最小收敛比例
docs: 更新 README 示例以包含比亚迪的日、周、月 K 线图 fix: 修复趋势线绘制逻辑,支持周K/月K聚合后的日期匹配 docs: 添加 K 线形态参数调整建议文档
This commit is contained in:
parent
6f7bdcc9c1
commit
59622a6ef7
@ -43,8 +43,9 @@ pip install requests mplfinance
|
||||
python validate.py 中远海控
|
||||
|
||||
# 使用中文名称(自动搜索转换为股票代码)
|
||||
python validate.py 中控技术 日 --window 3Y --save
|
||||
|
||||
python validate.py 比亚迪 日 --window 3Y --save --no-show
|
||||
python validate.py 比亚迪 周 --window 10Y --save --no-show
|
||||
python validate.py 比亚迪 月 --window 3Y --save --no-show
|
||||
# 美股也支持
|
||||
python validate.py 英伟达 日 --window 3Y --save
|
||||
|
||||
|
||||
58
chart.py
58
chart.py
@ -163,6 +163,10 @@ def draw_triangle_chart(
|
||||
"""
|
||||
与前端 TechPattern.vue 的 getExtendedLinePoints 函数逻辑完全一致
|
||||
趋势线从 window_start_date 延伸到 window_end_date
|
||||
|
||||
关键修复:
|
||||
1. 使用 K 线数据的实际索引,而不是公式内部的 index
|
||||
2. 使用 get_closest_date_idx 查找日期,支持周K/月K 聚合后的日期匹配
|
||||
"""
|
||||
if not line_pts or len(line_pts) < 2:
|
||||
return None
|
||||
@ -170,36 +174,35 @@ def draw_triangle_chart(
|
||||
p1 = line_pts[0]
|
||||
p2 = line_pts[-1]
|
||||
|
||||
# 检查是否有 index 字段(公式返回的数据)
|
||||
has_index = 'index' in p1 and 'index' in p2 and pivot_point and 'index' in pivot_point
|
||||
if window_start and window_end:
|
||||
# 将枢轴点日期映射到 K 线数据的实际索引
|
||||
# 使用 get_closest_date_idx 支持周K/月K 聚合后的日期匹配
|
||||
idx1 = get_closest_date_idx(p1['date'], dates_str)
|
||||
idx2 = get_closest_date_idx(p2['date'], dates_str)
|
||||
|
||||
if has_index and window_start and window_end:
|
||||
# 使用原始 index 计算斜率(与前端一致)
|
||||
slope = (p2['price'] - p1['price']) / (p2['index'] - p1['index']) if p2['index'] != p1['index'] else 0
|
||||
d1 = _date_int_to_str(p1['date'])
|
||||
d2 = _date_int_to_str(p2['date'])
|
||||
|
||||
# 前端: startIdx = 0 (window_start_date 对应 index 0)
|
||||
start_idx = 0
|
||||
print(f'[chart] 枢轴点日期映射: {d1} -> K线索引{idx1}, {d2} -> K线索引{idx2}')
|
||||
|
||||
# 查找 window_end_date 对应的 index(与前端一致)
|
||||
end_idx = p2['index']
|
||||
all_points = (chart.get('upper_line', []) + chart.get('lower_line', []) +
|
||||
chart.get('upper_pivots', []) + chart.get('lower_pivots', []))
|
||||
for pt in all_points:
|
||||
if pt.get('date') == window_end:
|
||||
end_idx = pt.get('index', end_idx)
|
||||
break
|
||||
# 使用 K 线数据的实际索引计算斜率
|
||||
slope = (p2['price'] - p1['price']) / (idx2 - idx1) if idx2 != idx1 else 0
|
||||
|
||||
# 计算延伸后的价格(与前端一致)
|
||||
pivot_index = pivot_point['index']
|
||||
pivot_price = pivot_point['price']
|
||||
start_price = pivot_price + slope * (start_idx - pivot_index)
|
||||
end_price = pivot_price + slope * (end_idx - pivot_index)
|
||||
|
||||
# 将 window_start_date 和 window_end_date 映射到 K 线数据的索引
|
||||
# 找到 window_start_date 和 window_end_date 在 K 线数据中的索引
|
||||
kline_start_idx = get_closest_date_idx(window_start, dates_str)
|
||||
kline_end_idx = get_closest_date_idx(window_end, dates_str)
|
||||
|
||||
# 使用 K 线数据的索引计算延伸后的价格
|
||||
# 价格 = pivot_price + slope * (目标索引 - pivot索引)
|
||||
pivot_kline_idx = idx1 # 使用第一个枢轴点的 K 线索引
|
||||
pivot_price = p1['price']
|
||||
|
||||
start_price = pivot_price + slope * (kline_start_idx - pivot_kline_idx)
|
||||
end_price = pivot_price + slope * (kline_end_idx - pivot_kline_idx)
|
||||
|
||||
print(f'[chart] 趋势线延伸: {window_start_str}({kline_start_idx}) -> {window_end_str}({kline_end_idx})')
|
||||
print(f'[chart] 枢轴点: {d1}({idx1}) 价格={pivot_price:.2f}')
|
||||
print(f'[chart] 斜率: {slope:.4f}')
|
||||
print(f'[chart] 价格: {start_price:.2f} -> {end_price:.2f}')
|
||||
|
||||
return (
|
||||
@ -207,16 +210,13 @@ def draw_triangle_chart(
|
||||
(kline_end_idx, end_price)
|
||||
)
|
||||
|
||||
# 降级处理:仅连接两点(与前端一致)
|
||||
# 降级处理:仅连接两点
|
||||
d1 = _date_int_to_str(p1['date'])
|
||||
d2 = _date_int_to_str(p2['date'])
|
||||
|
||||
idx1 = date_to_idx.get(d1)
|
||||
idx2 = date_to_idx.get(d2)
|
||||
|
||||
if idx1 is None or idx2 is None:
|
||||
print(f'[chart] 警告: 趋势线日期不在 K 线数据中: {d1} 或 {d2}')
|
||||
return None
|
||||
# 使用 get_closest_date_idx 支持日期模糊匹配
|
||||
idx1 = get_closest_date_idx(p1['date'], dates_str)
|
||||
idx2 = get_closest_date_idx(p2['date'], dates_str)
|
||||
|
||||
return (
|
||||
(idx1, p1['price']),
|
||||
|
||||
67
docs/K线形态参数调整建议_202603041557.md
Normal file
67
docs/K线形态参数调整建议_202603041557.md
Normal file
@ -0,0 +1,67 @@
|
||||
根据你提供的比亚迪(BYD)日、周、月三个周期的 K 线图以及形态验证文档,我们先来复盘一下现状:
|
||||
|
||||
* **日K线**:成功识别,强度 **0.285**。上沿触碰 6 次(非常稳固),下沿仅 2 次。
|
||||
* **周K线**:成功识别,强度 **0.345**。上下沿各触碰 2 次,刚好达到形态成立的最低门槛。
|
||||
* **月K线**:**未识别到形态**(强度 0.000,触碰点均为 0)。
|
||||
|
||||
结合 `triangle-validator-guide` 文档,针对如何优化参数以获得更精准或更全面的识别结果,建议从以下几个维度进行调整:
|
||||
|
||||
---
|
||||
|
||||
## 1. 解决月K线“零识别”问题
|
||||
|
||||
月K线识别不到形态,通常是因为月度数据太稀疏,默认参数过于严格。
|
||||
|
||||
* **调小 `pivot_k` (枢轴点窗口)**:
|
||||
* **现状**:默认值为 3,意味着一个高点必须比前后各 3 个月(共 7 个月)的价格都高。
|
||||
* **建议**:修改为 **2**。月线级别 7 个月的跨度太长,很多波段高点会被过滤掉。调小它可以增加候选枢轴点,从而更容易连成三角形。
|
||||
|
||||
|
||||
* **放宽 `min_convergence` (收敛比例)**:
|
||||
* **现状**:默认 0.50。
|
||||
* **建议**:如果比亚迪目前的震荡幅度依然较大,未达到“缩减一半”的程度,可以调高到 **0.60**。
|
||||
|
||||
|
||||
|
||||
---
|
||||
|
||||
## 2. 优化日K线的“触碰不均衡”
|
||||
|
||||
日线图显示上沿(红色)被多次验证,但下沿(绿色)的斜率非常陡峭且触碰点极少,这说明形态可能有些“勉强”。
|
||||
|
||||
* **增加 `pivot_k` (日线级)**:
|
||||
* **现状**:默认 15。
|
||||
* **建议**:如果你希望过滤掉近期细微的波动,寻找更宏观、更稳健的支撑线,可以尝试调大到 **20** 或 **25**。这会强制程序寻找更具“重量级”的低点。
|
||||
|
||||
|
||||
* **调整 `window` (检测窗口)**:
|
||||
* **现状**:默认 240 根(约 1 年)。
|
||||
* **建议**:比亚迪的这一波整理从 2025 年初就开始了,可以尝试缩短窗口至 **180**,聚焦于最近半年的收敛状态,可能会得到一个斜率更平缓、更符合直觉的底部支撑线。
|
||||
|
||||
|
||||
|
||||
---
|
||||
|
||||
## 3. 提高识别强度(Intensity)与质量
|
||||
|
||||
如果你觉得当前的识别结果“噪音”太多,或者想提高所谓的强度数值:
|
||||
|
||||
* **收紧 `shrink_ratio` (收敛比)**:
|
||||
* **逻辑**:文档提到默认是 0.8。将此值调低(例如 **0.7**)会过滤掉那些收敛不明显的三角形,只留下最“尖”的形态,这样识别出的强度通常会更高。
|
||||
|
||||
|
||||
* **提高 `breakout_threshold` (突破阈值)**:
|
||||
* **建议**:对于周K线,如果想过滤假突破,可以将 **0.010 (1%)** 提高到 **0.015**。
|
||||
|
||||
|
||||
|
||||
---
|
||||
|
||||
## 参数调整建议总结表
|
||||
|
||||
| 目标周期 | 建议修改参数 | 推荐值 | 修改目的 |
|
||||
| --- | --- | --- | --- |
|
||||
| **月K (M)** | `pivot_k` | 3 → **2** | 增加枢轴点,解决数据稀疏无法连线的问题 |
|
||||
| **月K (M)** | `min_convergence` | 0.50 → **0.60** | 容忍更宽的三角形,适合大周期早期识别 |
|
||||
| **日K (D)** | `pivot_k` | 15 → **20** | 过滤小波动,寻找更扎实的下沿支撑 |
|
||||
| **通用** | `shrink_ratio` | 0.8 → **0.7** | 提升形态质量,过滤掉收敛不明显的案例 |
|
||||
41
validate.py
41
validate.py
@ -182,11 +182,19 @@ def parse_args():
|
||||
parser.add_argument('--window', type=str, default='3Y',
|
||||
choices=['1Y', '3Y', '5Y', 'ALL'],
|
||||
help='K线时间窗口:1Y=1年 3Y=3年 5Y=5年 ALL=全部(默认:3Y,与前端一致)')
|
||||
parser.add_argument('--pivot-k', type=int, default=-1, metavar='N',
|
||||
help='枢轴点窗口(默认:日K=15, 周K=5, 月K=3)')
|
||||
parser.add_argument('--shrink-ratio', type=float, default=-1.0, metavar='R',
|
||||
help='收敛比,三角形开口缩小程度(默认:0.8)')
|
||||
parser.add_argument('--min-convergence', type=float, default=-1.0, metavar='C',
|
||||
help='最小收敛比例(默认:日K=0.45, 周K=0.45, 月K=0.50)')
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
# ── Step 1:执行公式,拿 _id ──────────────────────────────────────────────────
|
||||
def run_formula(ticker: str, freq: str, mode: int, date) -> str:
|
||||
def run_formula(ticker: str, freq: str, mode: int, date,
|
||||
pivot_k: int = -1, shrink_ratio: float = -1.0,
|
||||
min_convergence: float = -1.0) -> str:
|
||||
"""
|
||||
调 innerServer/runOneFormula 接口执行收敛三角形详情公式。
|
||||
Returns:
|
||||
@ -194,10 +202,30 @@ def run_formula(ticker: str, freq: str, mode: int, date) -> str:
|
||||
"""
|
||||
import uuid
|
||||
|
||||
# 构建参数列表
|
||||
params = [ticker, freq, 'True', str(mode)]
|
||||
|
||||
# target_date
|
||||
if date:
|
||||
formula = f'结果=收敛三角形详情({ticker},{freq},True,{mode},{date})'
|
||||
params.append(str(date))
|
||||
else:
|
||||
formula = f'结果=收敛三角形详情({ticker},{freq},True,{mode})'
|
||||
params.append('None')
|
||||
|
||||
# window, min_convergence, breakout_threshold, volume_multiplier 使用默认值
|
||||
params.extend(['-1', '-1', '-1', '-1'])
|
||||
|
||||
# pivot_k, shrink_ratio
|
||||
params.append(str(pivot_k))
|
||||
params.append(str(shrink_ratio))
|
||||
|
||||
# 如果有自定义 min_convergence,需要调整参数位置
|
||||
# 参数顺序: ticker, freq, include_klines, mode, target_date,
|
||||
# window, min_convergence, breakout_threshold, volume_multiplier,
|
||||
# pivot_k, shrink_ratio, display_days, custom_weights, fast
|
||||
if min_convergence > 0:
|
||||
params[6] = str(min_convergence) # min_convergence 在索引 6
|
||||
|
||||
formula = f'结果=收敛三角形详情({",".join(params)})'
|
||||
|
||||
url = f'{GPT_SERVER_URL}/innerServer/runOneFormula'
|
||||
payload = {
|
||||
@ -357,7 +385,12 @@ def run(args):
|
||||
|
||||
# 1. 执行公式
|
||||
try:
|
||||
index_id = run_formula(args.ticker, args.freq, args.mode, args.date)
|
||||
index_id = run_formula(
|
||||
args.ticker, args.freq, args.mode, args.date,
|
||||
pivot_k=args.pivot_k,
|
||||
shrink_ratio=args.shrink_ratio,
|
||||
min_convergence=args.min_convergence,
|
||||
)
|
||||
except Exception as e:
|
||||
print(f'[ERROR] 公式执行失败: {e}')
|
||||
sys.exit(1)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user