修复趋势突破
This commit is contained in:
@@ -86,6 +86,7 @@ class KeyMonitorConfig(BaseModel):
|
||||
volume_ratio_min: float = Field(1.3, gt=0.0)
|
||||
breakout_amp_min_pct: float = Field(0.03, ge=0.0)
|
||||
breakout_amp_max_pct: float = Field(0.5, gt=0.0)
|
||||
trend_breakout_amp_max_pct: float = Field(1.5, gt=0.0)
|
||||
daily_volume_rank_max: int = Field(30, ge=1)
|
||||
# 全市场 5m TRIGGER 是否仍转发执行器(默认关;关键位走 forward_executor)
|
||||
auto_scan_forward_executor: bool = False
|
||||
|
||||
@@ -114,6 +114,8 @@ def key_hard_checks_from_rows(
|
||||
"breakout_open": open_b,
|
||||
"direction": direction,
|
||||
"swing4h_pct": swing4h_pct,
|
||||
"amp_min_pct": breakout_amp_min_pct,
|
||||
"amp_max_pct": breakout_amp_max_pct,
|
||||
}
|
||||
)
|
||||
return out
|
||||
@@ -122,6 +124,8 @@ def key_hard_checks_from_rows(
|
||||
def key_hard_lines_from_checks(checks: dict, *, volume_ratio_min: float) -> list[str]:
|
||||
breach = float(checks.get("breach_pct") if checks.get("breach_pct") is not None else checks.get("amp_pct") or 0)
|
||||
body = float(checks.get("body_pct") or 0)
|
||||
amp_min = float(checks.get("amp_min_pct") or 0.03)
|
||||
amp_max = float(checks.get("amp_max_pct") or 0.5)
|
||||
br_hi = checks.get("breakout_high")
|
||||
br_lo = checks.get("breakout_low")
|
||||
return [
|
||||
@@ -129,9 +133,9 @@ def key_hard_lines_from_checks(checks: dict, *, volume_ratio_min: float) -> list
|
||||
f"突破价位:{'通过' if checks.get('breakout_ok') else '不通过'}(突破K收盘 {round(float(checks.get('breakout_close') or 0), 8)},关键位 {checks.get('edge_price')})",
|
||||
(
|
||||
f"突破越过关键位:{'通过' if checks.get('amp_ok') else '不通过'}"
|
||||
f"(越过 {round(breach, 4)}%,K线实体 {round(body, 4)}%,要求越过 0.03%~0.5%)"
|
||||
f"(越过 {round(breach, 4)}%,K线实体 {round(body, 4)}%,要求越过 {amp_min:g}%~{amp_max:g}%)"
|
||||
),
|
||||
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)",
|
||||
f"突破K极值:高 {br_hi}|低 {br_lo}(止损据此 ± 外扩%)",
|
||||
f"突破K极值:高 {br_hi}|低 {br_lo}(空→高点+外扩%|多→低点−外扩%)",
|
||||
]
|
||||
|
||||
@@ -10,6 +10,7 @@ from .config import Settings
|
||||
from .gate import GateClient
|
||||
from .key_gate import key_hard_checks_from_rows, key_hard_lines_from_checks
|
||||
from .key_sl_tp import (
|
||||
breakout_amp_max_for_mode,
|
||||
calc_planned_rr,
|
||||
normalize_sl_tp_mode,
|
||||
plan_key_sl_tp,
|
||||
@@ -54,6 +55,12 @@ class KeyMonitorService:
|
||||
sorted_insts = sorted(vol_map.keys(), key=lambda x: float(vol_map.get(x, 0.0)), reverse=True)
|
||||
rank_map = {i: idx + 1 for idx, i in enumerate(sorted_insts)}
|
||||
rank = rank_map.get(inst)
|
||||
sl_tp_mode = normalize_sl_tp_mode(row.get("sl_tp_mode"))
|
||||
amp_max = breakout_amp_max_for_mode(
|
||||
sl_tp_mode,
|
||||
standard_max_pct=cfg.breakout_amp_max_pct,
|
||||
trend_max_pct=cfg.trend_breakout_amp_max_pct,
|
||||
)
|
||||
checks = key_hard_checks_from_rows(
|
||||
closed,
|
||||
direction=direction,
|
||||
@@ -62,7 +69,7 @@ class KeyMonitorService:
|
||||
volume_ma_bars=cfg.volume_ma_bars,
|
||||
volume_ratio_min=cfg.volume_ratio_min,
|
||||
breakout_amp_min_pct=cfg.breakout_amp_min_pct,
|
||||
breakout_amp_max_pct=cfg.breakout_amp_max_pct,
|
||||
breakout_amp_max_pct=amp_max,
|
||||
volume_rank=rank,
|
||||
volume_rank_total=len(sorted_insts),
|
||||
volume_rank_max=cfg.daily_volume_rank_max,
|
||||
@@ -119,6 +126,12 @@ class KeyMonitorService:
|
||||
closed = raw_rows[:-1]
|
||||
|
||||
rank = rank_map.get(inst)
|
||||
sl_tp_mode = normalize_sl_tp_mode(row.get("sl_tp_mode"))
|
||||
amp_max = breakout_amp_max_for_mode(
|
||||
sl_tp_mode,
|
||||
standard_max_pct=cfg.breakout_amp_max_pct,
|
||||
trend_max_pct=cfg.trend_breakout_amp_max_pct,
|
||||
)
|
||||
checks = key_hard_checks_from_rows(
|
||||
closed,
|
||||
direction=direction,
|
||||
@@ -127,7 +140,7 @@ class KeyMonitorService:
|
||||
volume_ma_bars=cfg.volume_ma_bars,
|
||||
volume_ratio_min=cfg.volume_ratio_min,
|
||||
breakout_amp_min_pct=cfg.breakout_amp_min_pct,
|
||||
breakout_amp_max_pct=cfg.breakout_amp_max_pct,
|
||||
breakout_amp_max_pct=amp_max,
|
||||
volume_rank=rank,
|
||||
volume_rank_total=rank_total,
|
||||
volume_rank_max=cfg.daily_volume_rank_max,
|
||||
@@ -135,7 +148,6 @@ class KeyMonitorService:
|
||||
if not checks.get("ok"):
|
||||
return
|
||||
|
||||
sl_tp_mode = normalize_sl_tp_mode(row.get("sl_tp_mode"))
|
||||
outside = float(row.get("stop_outside_pct") or stop_outside_pct_for_mode(sl_tp_mode))
|
||||
trend_out = cfg.trend_stop_outside_pct
|
||||
manual_tp = row.get("manual_take_profit")
|
||||
|
||||
@@ -36,6 +36,16 @@ def stop_outside_pct_for_mode(sl_tp_mode: str) -> float:
|
||||
return 1.0 if normalize_sl_tp_mode(sl_tp_mode) == "trend_manual" else 0.3
|
||||
|
||||
|
||||
def breakout_amp_max_for_mode(
|
||||
sl_tp_mode: str,
|
||||
*,
|
||||
standard_max_pct: float,
|
||||
trend_max_pct: float,
|
||||
) -> float:
|
||||
"""标准突破越过关键位上限默认 0.5%;趋势突破放宽(默认 1.5%)。"""
|
||||
return float(trend_max_pct) if normalize_sl_tp_mode(sl_tp_mode) == "trend_manual" else float(standard_max_pct)
|
||||
|
||||
|
||||
def plan_key_sl_tp(
|
||||
mode: str,
|
||||
direction: str,
|
||||
@@ -127,10 +137,16 @@ def sl_tp_plan_summary_text(
|
||||
trend_outside_pct: float,
|
||||
) -> str:
|
||||
mode_n = normalize_sl_tp_mode(mode)
|
||||
dir_n = (direction or "long").strip().lower()
|
||||
if mode_n == "trend_manual":
|
||||
sl_side = (
|
||||
f"空=突破K高点+{trend_outside_pct:g}%"
|
||||
if dir_n == "short"
|
||||
else f"多=突破K低点−{trend_outside_pct:g}%"
|
||||
)
|
||||
return (
|
||||
f"方案:{sl_tp_mode_label(mode_n)}|E={e}|"
|
||||
f"SL=突破K极值外{trend_outside_pct:g}%|TP={tp_raw}(录入)"
|
||||
f"SL={sl_side}|TP={tp_raw}(录入)"
|
||||
)
|
||||
return (
|
||||
f"方案:{sl_tp_mode_label(mode_n)}|E={e}|"
|
||||
|
||||
@@ -530,10 +530,11 @@ def create_app(settings: Settings) -> FastAPI:
|
||||
km = settings.key_monitor
|
||||
return (
|
||||
f"周期 5m|突破K/确认K:倒数第2/第1根闭合K|量能:突破K量 > 前{km.volume_ma_bars}均量×{km.volume_ratio_min}|"
|
||||
f"突破越过关键位 {km.breakout_amp_min_pct:g}%~{km.breakout_amp_max_pct:g}%(非K线实体)|"
|
||||
f"越过关键位:标准 {km.breakout_amp_min_pct:g}%~{km.breakout_amp_max_pct:g}%|"
|
||||
f"趋势 {km.breakout_amp_min_pct:g}%~{km.trend_breakout_amp_max_pct:g}%|"
|
||||
f"计划RR须 > {km.min_planned_rr:g}|日成交额排名前{km.daily_volume_rank_max}|"
|
||||
f"箱体/收敛方案:标准突破(止损突破K外{km.standard_stop_outside_pct:g}%|止盈1×H)或 "
|
||||
f"趋势突破(止损突破K外{km.trend_stop_outside_pct:g}%|止盈手填)|"
|
||||
f"箱体/收敛方案:标准突破(止损突破K低/高外{km.standard_stop_outside_pct:g}%|止盈1×H)或 "
|
||||
f"趋势突破(空=突破K高点+{km.trend_stop_outside_pct:g}%|多=突破K低点−{km.trend_stop_outside_pct:g}%|止盈手填)|"
|
||||
f"触发后企微+{'转发执行器' if km.forward_executor else '不转发执行器'}"
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user