增加关键位人工输入

This commit is contained in:
dekun
2026-05-22 22:15:46 +08:00
parent 593f8fcff5
commit ac762b540c
20 changed files with 1541 additions and 42 deletions
+99
View File
@@ -0,0 +1,99 @@
"""关键位 5m 硬门控(逻辑自 crypto_monitor_gate _key_hard_checks,使用 Gate K 线)。"""
from __future__ import annotations
from statistics import mean
from .candle_rows import rows_to_ohlcv
def key_hard_checks_from_rows(
rows: list[list[str]],
*,
direction: str,
upper: float,
lower: float,
volume_ma_bars: int = 20,
volume_ratio_min: float = 1.3,
breakout_amp_min_pct: float = 0.03,
breakout_amp_max_pct: float = 0.5,
volume_rank: int | None = None,
volume_rank_total: int = 0,
volume_rank_max: int = 30,
) -> dict:
"""rows:Gate K 线行,最后一根应为最近一根已闭合 5m(调用方负责剔除未闭合)。"""
out: dict = {"ok": False}
_, ah, al, ac, av = rows_to_ohlcv(rows)
vol_lb = max(5, int(volume_ma_bars))
min_need = vol_lb + 3
if len(ac) < min_need:
out["reason"] = f"insufficient_candles have={len(ac)} need>={min_need}"
return out
breakout_close = float(ac[-2])
confirm_close = float(ac[-1])
breakout_high = float(ah[-2])
breakout_low = float(al[-2])
try:
open_b = float(rows[-2][1])
except (IndexError, TypeError, ValueError):
open_b = breakout_close
prev_vol = av[-vol_lb - 2 : -2]
avg20 = mean(prev_vol) if prev_vol else 0.0
vol_break = float(av[-2])
vol_ok = vol_break > avg20 * volume_ratio_min if avg20 > 0 else False
amp_pct = abs(breakout_close - open_b) / open_b * 100 if open_b > 0 else 0.0
amp_ok = (amp_pct > breakout_amp_min_pct) and (amp_pct < breakout_amp_max_pct)
direction = (direction or "long").strip().lower()
edge = float(upper) if direction == "long" else float(lower)
breakout_ok = (breakout_close > float(upper)) if direction == "long" else (breakout_close < float(lower))
confirm_ok_raw = (confirm_close > edge) if direction == "long" else (confirm_close < edge)
amp_ok = amp_ok and breakout_ok
confirm_ok = confirm_ok_raw and breakout_ok
rank_ok = (volume_rank is not None) and (int(volume_rank) <= volume_rank_max)
try:
seg = rows[-48:] if len(rows) >= 48 else rows
hh = max(float(x[2]) for x in seg)
ll = min(float(x[3]) for x in seg)
swing4h_pct = ((hh - ll) / ll * 100.0) if ll > 0 else 0.0
except Exception:
swing4h_pct = 0.0
out.update(
{
"ok": all([vol_ok, amp_ok, breakout_ok, confirm_ok, rank_ok]),
"vol_ok": vol_ok,
"avg20": avg20,
"vol_break": vol_break,
"amp_ok": amp_ok,
"amp_pct": amp_pct,
"breakout_ok": breakout_ok,
"breakout_close": breakout_close,
"confirm_ok": confirm_ok,
"confirm_close": confirm_close,
"edge_price": edge,
"rank": volume_rank,
"rank_total": volume_rank_total,
"rank_ok": rank_ok,
"breakout_high": breakout_high,
"breakout_low": breakout_low,
"swing4h_pct": swing4h_pct,
"direction": direction,
}
)
return out
def key_hard_lines_from_checks(checks: dict, *, volume_ratio_min: float) -> list[str]:
return [
f"量能:{'通过' if checks.get('vol_ok') else '不通过'}(突破K量 {round(float(checks.get('vol_break') or 0), 4)} / 前20均量 {round(float(checks.get('avg20') or 0), 4)},阈值{volume_ratio_min:g}x",
f"突破价位:{'通过' if checks.get('breakout_ok') else '不通过'}(突破K收盘 {round(float(checks.get('breakout_close') or 0), 8)},关键位 {checks.get('edge_price')}",
f"突破K幅度:{'通过' if checks.get('amp_ok') else '不通过'}{round(float(checks.get('amp_pct') or 0), 4)}%,要求0.03%~0.5%",
f"第二根确认:{'通过' if checks.get('confirm_ok') else '不通过'}(确认收盘 {checks.get('confirm_close')},关键位 {checks.get('edge_price')}",
f"日成交量排名:{'通过' if checks.get('rank_ok') else '不通过'}{checks.get('rank')}/{checks.get('rank_total')},要求前30",
]