This commit is contained in:
薇薇安 2026-01-19 11:49:13 +08:00
parent ee4b577519
commit 82fd5e3f58

View File

@ -274,6 +274,92 @@ async def get_recommendations(
rec.setdefault("current_price_source", rec.get("current_price_source") or "snapshot") rec.setdefault("current_price_source", rec.get("current_price_source") or "snapshot")
rec.setdefault("price_updated", False) rec.setdefault("price_updated", False)
# 4) 过滤“过期/不再适用”的推荐(短期可借鉴)
# 规则:
# - 时间过期:超过 max_age_sec 直接丢弃
# - 价格偏离:当前价偏离 planned_entry_price / suggested_limit_price 过大丢弃
# - 合法性校验BUY 需要 SL < entry < TPSELL 需要 SL > entry > TP
import time as _time
now_s = _time.time()
try:
max_age_sec = int(os.getenv("RECOMMENDATIONS_MAX_AGE_SEC", "1800")) # 默认30分钟
except Exception:
max_age_sec = 1800
try:
max_price_drift_pct = float(os.getenv("RECOMMENDATIONS_MAX_PRICE_DRIFT_PCT", "1.5")) # 默认1.5%
except Exception:
max_price_drift_pct = 1.5
dropped_age = 0
dropped_drift = 0
dropped_invalid = 0
def _f(v):
try:
return float(v)
except Exception:
return None
filtered_recs: List[Dict[str, Any]] = []
for rec in recommendations:
if not isinstance(rec, dict):
continue
# 4.1 时间过期
ts = rec.get("timestamp", 0)
try:
ts = float(ts) if ts is not None else 0.0
except Exception:
ts = 0.0
if ts and max_age_sec > 0 and (now_s - ts) > max_age_sec:
dropped_age += 1
continue
direction_u = str(rec.get("direction", "") or "").upper()
cur = _f(rec.get("current_price"))
# 基准入场价:优先 planned_entry_price新逻辑再 suggested_limit_price
entry_base = _f(rec.get("planned_entry_price"))
if entry_base is None:
entry_base = _f(rec.get("suggested_limit_price"))
if entry_base is None:
entry_base = _f(rec.get("analysis_price")) or cur
# 4.2 价格偏离过大(挂单参考已失效)
if max_price_drift_pct > 0 and cur and entry_base and entry_base > 0:
drift = abs((cur - entry_base) / entry_base) * 100
if drift > max_price_drift_pct:
dropped_drift += 1
continue
# 4.3 合法性校验:止损/止盈相对关系
sl = _f(rec.get("suggested_stop_loss"))
tp1 = _f(rec.get("suggested_take_profit_1"))
tp2 = _f(rec.get("suggested_take_profit_2"))
if direction_u == "BUY":
if entry_base and sl and sl >= entry_base:
dropped_invalid += 1
continue
if entry_base and tp1 and tp1 <= entry_base:
dropped_invalid += 1
continue
if entry_base and tp2 and tp2 <= entry_base:
dropped_invalid += 1
continue
elif direction_u == "SELL":
if entry_base and sl and sl <= entry_base:
dropped_invalid += 1
continue
if entry_base and tp1 and tp1 >= entry_base:
dropped_invalid += 1
continue
if entry_base and tp2 and tp2 >= entry_base:
dropped_invalid += 1
continue
filtered_recs.append(rec)
recommendations = filtered_recs
# 方向过滤 # 方向过滤
if direction: if direction:
recommendations = [r for r in recommendations if r.get('direction') == direction] recommendations = [r for r in recommendations if r.get('direction') == direction]
@ -291,6 +377,13 @@ async def get_recommendations(
"price_source": "mark_price" if mark_items else None, "price_source": "mark_price" if mark_items else None,
"price_updated_at": mark_updated_at, "price_updated_at": mark_updated_at,
"price_updated_at_ms": mark_updated_at_ms, "price_updated_at_ms": mark_updated_at_ms,
"recommendations_max_age_sec": max_age_sec,
"recommendations_max_price_drift_pct": max_price_drift_pct,
"dropped": {
"age": dropped_age,
"price_drift": dropped_drift,
"invalid": dropped_invalid,
},
}, },
"data": recommendations "data": recommendations
} }