fix: ECR-004 威科夫区间评分硬化与 VP 绘图减负(已审)

评分选 TR、阶段最小跨度、elements_only 门闩、Top-8 VP;无币种独立参数。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
jackyu66git
2026-08-06 18:46:08 +08:00
co-authored by Cursor
parent ac6be80278
commit d3188ca83c
19 changed files with 275 additions and 89 deletions
+25 -18
View File
@@ -187,29 +187,25 @@ def build_phases(
tr: Dict[str, Any],
bias: str,
events: List[Dict[str, Any]],
min_bars: int = 3,
) -> List[Dict[str, Any]]:
"""按时间切分 AE 粗阶段。"""
"""按时间切分 AE 粗阶段;保证非重叠且每段至少 min_bars 根(空间不足则截断尾部阶段)"""
s = int(tr["abs_start_idx"])
e = int(tr["abs_end_idx"])
hi = float(tr["high"])
lo = float(tr["low"])
mid = float(tr["mid"])
tol = float(tr.get("tol") or (hi - lo) * 0.05)
n_last = len(df) - 1
min_span = max(2, min_bars - 1)
event_idx = {}
for ev in events:
# 找回 idx 近似:按时间匹配
t = ev.get("time")
for i in range(s, min(len(df), e + 20)):
if _bar_time(df, i) == t:
event_idx[ev["type"]] = i
break
# 分段点
a_end = s + max(3, (e - s) // 5)
a_end = s + max(min_bars, (e - s) // 5)
c_anchor = event_idx.get("Spring") or event_idx.get("UTAD") or (s + (e - s) // 2)
d_anchor = event_idx.get("SOS") or event_idx.get("SOW") or e
e_start = d_anchor
def _lab(phase: str) -> str:
if bias == "distribution":
@@ -218,17 +214,27 @@ def build_phases(
m = {"A": "A停止下跌", "B": "B筑底", "C": "C测试", "D": "D拉升", "E": "E离开"}
return m.get(phase, phase)
cuts = [
# 理想切点(随后再强制非重叠 + 最小跨度)
raw = [
("A", s, a_end),
("B", a_end, max(a_end + 1, c_anchor)),
("C", max(a_end + 1, c_anchor), max(c_anchor + 1, d_anchor)),
("D", max(c_anchor + 1, d_anchor), max(d_anchor + 1, min(len(df) - 1, e_start + max(3, (e - s) // 6)))),
("E", max(d_anchor, e_start), min(len(df) - 1, max(e, e_start + 5))),
("B", a_end, c_anchor),
("C", c_anchor, d_anchor),
("D", d_anchor, min(n_last, d_anchor + max(min_bars, (e - s) // 6))),
("E", min(n_last, d_anchor + max(min_bars, (e - s) // 6)), min(n_last, max(e, d_anchor + max(min_bars * 2, 8)))),
]
phases = []
for phase, a, b in cuts:
a = int(np.clip(a, 0, len(df) - 1))
b = int(np.clip(b, a, len(df) - 1))
phases: List[Dict[str, Any]] = []
cursor = s
for phase, _a, _b in raw:
if cursor >= n_last:
break
a = max(int(_a), cursor)
b = int(max(_b, a + min_span))
b = int(np.clip(b, a, n_last))
if b - a < min_span:
# 尾部空间不足:并入上一段终点并停止新增
if phases:
phases[-1]["end_time"] = _bar_time(df, n_last)
break
phases.append(
{
"phase": phase,
@@ -237,4 +243,5 @@ def build_phases(
"end_time": _bar_time(df, b),
}
)
cursor = b
return phases