修复okx 趋势回调

This commit is contained in:
dekun
2026-05-30 10:06:54 +08:00
parent 9678cd54ce
commit 8501f7fe0e
2 changed files with 103 additions and 22 deletions
+55 -7
View File
@@ -34,8 +34,8 @@ MONITOR_TYPE_TREND = MONITOR_TYPE_TREND_PULLBACK
# 趋势回调:交易所报空仓需连续 N 次轮询确认,避免 OKX 等 API 瞬时误判立即结束计划
_TREND_FLAT_STREAK: dict[int, int] = {}
TREND_FLAT_CONFIRM_POLLS = max(1, int(os.getenv("TREND_FLAT_CONFIRM_POLLS", "3")))
TREND_OPEN_GRACE_SEC = max(0, int(os.getenv("TREND_OPEN_GRACE_SEC", "90")))
TREND_FLAT_CONFIRM_POLLS = max(1, int(os.getenv("TREND_FLAT_CONFIRM_POLLS", "5")))
TREND_OPEN_GRACE_SEC = max(0, int(os.getenv("TREND_OPEN_GRACE_SEC", "180")))
def trend_add_zone_label(direction: str) -> str:
@@ -417,24 +417,58 @@ def _trend_plan_open_age_sec(row, m) -> float:
to_ms = getattr(m, "_to_ms_with_fallback", None)
if callable(to_ms):
opened_ms = to_ms(opened_ms, row["opened_at"] if "opened_at" in row.keys() else None)
if opened_ms is None and "opened_at" in row.keys():
opened_ms = to_ms(None, row["opened_at"])
if not opened_ms:
return 999999.0
return 0.0
return max(0.0, (time.time() * 1000 - opened_ms) / 1000.0)
def _trend_hit_take_profit(direction: str, mark_price: float, take_profit: float, avg_entry: float) -> bool:
try:
pf = float(mark_price)
tp = float(take_profit)
entry = float(avg_entry)
except (TypeError, ValueError):
return False
if entry <= 0 or tp <= 0:
return False
direction = (direction or "long").lower()
if direction == "long":
return tp > entry and pf >= tp
return tp < entry and pf <= tp
def _should_finalize_trend_flat(row, pos, plan_id: int, m) -> bool:
"""首仓后交易所报无仓:需过开仓宽限期 + 连续空仓轮询,避免误判止损。"""
if pos is None or float(pos) > 0:
if pos is None:
return False
if float(pos) > 0:
_TREND_FLAT_STREAK.pop(plan_id, None)
return False
if not int(row["first_order_done"] or 0):
return False
if _trend_plan_open_age_sec(row, m) < TREND_OPEN_GRACE_SEC:
age = _trend_plan_open_age_sec(row, m)
if age < TREND_OPEN_GRACE_SEC:
_TREND_FLAT_STREAK.pop(plan_id, None)
return False
try:
local_open = float(row["order_amount_open"] or 0)
except (TypeError, ValueError):
local_open = 0.0
required = TREND_FLAT_CONFIRM_POLLS
if local_open > 0 and age < TREND_OPEN_GRACE_SEC * 2:
required = max(required, TREND_FLAT_CONFIRM_POLLS * 2)
streak = int(_TREND_FLAT_STREAK.get(plan_id, 0)) + 1
_TREND_FLAT_STREAK[plan_id] = streak
return streak >= TREND_FLAT_CONFIRM_POLLS
if streak >= required:
print(
f"[trend_pullback] flat finalize plan={plan_id} sym={row['symbol']} "
f"age={age:.0f}s streak={streak} local_open={local_open}",
flush=True,
)
return True
return False
def check_trend_pullback_plans(cfg: dict) -> None:
@@ -464,6 +498,19 @@ def check_trend_pullback_plans(cfg: dict) -> None:
pos = m.get_live_position_contracts(ex_sym, direction)
if pos is None:
continue
try:
local_open = float(row["order_amount_open"] or 0)
except (TypeError, ValueError):
local_open = 0.0
if float(pos) <= 0 and local_open > 0:
age = _trend_plan_open_age_sec(row, m)
if age < TREND_OPEN_GRACE_SEC * 2:
print(
f"[trend_pullback] pos fallback plan={plan_id} sym={sym} "
f"ex_pos=0 local_open={local_open} age={age:.0f}s",
flush=True,
)
pos = local_open
legs_done = int(row["legs_done"] or 0)
try:
leg_amounts = [float(x) for x in json.loads(row["leg_amounts_json"] or "[]")]
@@ -473,7 +520,8 @@ def check_trend_pullback_plans(cfg: dict) -> None:
grid = json.loads(row["grid_prices_json"] or "[]")
except Exception:
grid = []
hit_tp = (direction == "long" and pf >= tp) or (direction == "short" and pf <= tp)
avg_e = float(row["avg_entry_price"] or pf or 0)
hit_tp = _trend_hit_take_profit(direction, pf, tp, avg_e)
if hit_tp and pos > 0:
try:
close_resp = trend_market_close(cfg, ex_sym, direction, float(pos), lev)