a
This commit is contained in:
parent
ee4b577519
commit
82fd5e3f58
|
|
@ -273,6 +273,92 @@ async def get_recommendations(
|
|||
# 保留推荐生成时的 current_price,但给出来源/时间(用于提示“可能过时”)
|
||||
rec.setdefault("current_price_source", rec.get("current_price_source") or "snapshot")
|
||||
rec.setdefault("price_updated", False)
|
||||
|
||||
# 4) 过滤“过期/不再适用”的推荐(短期可借鉴)
|
||||
# 规则:
|
||||
# - 时间过期:超过 max_age_sec 直接丢弃
|
||||
# - 价格偏离:当前价偏离 planned_entry_price / suggested_limit_price 过大丢弃
|
||||
# - 合法性校验:BUY 需要 SL < entry < TP;SELL 需要 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:
|
||||
|
|
@ -291,6 +377,13 @@ async def get_recommendations(
|
|||
"price_source": "mark_price" if mark_items else None,
|
||||
"price_updated_at": mark_updated_at,
|
||||
"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
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user