This commit is contained in:
aaron 2026-05-28 23:47:37 +08:00
parent 15abdc3286
commit 5c86864d2f
2 changed files with 58 additions and 3 deletions

View File

@ -1122,9 +1122,18 @@ def _fill_paper_order(conn, order: dict, rec: dict, current_price: float, event_
base_notional = _safe_float(order.get("notional_usdt"), default_notional_usdt(cfg))
global_ok, global_detail = _global_risk_entry_check(conn, rec, base_notional, cfg)
if not global_ok:
result = _cancel_paper_order(conn, order, "global_risk_rejected", event_time)
result["risk_detail"] = global_detail
return result
# Market/account risk is a temporary execution gate, not proof that the
# original limit order is invalid. Keep the order pending so it can fill
# later if risk improves, instead of instantly wiping every touched order.
conn.execute("UPDATE paper_orders SET updated_at=%s WHERE id=%s", (event_time, order["id"]))
return {
"skipped": True,
"reason": "paper_order_risk_paused",
"paper_order_id": order.get("id"),
"target_price": order.get("target_price"),
"current_price": current_price,
"risk_detail": global_detail,
}
adjusted_notional = _market_risk_adjusted_notional(base_notional, global_detail, cfg)
pause_ok, pause_reason, pause_detail = _portfolio_entry_pause_check(conn, adjusted_notional, event_time, cfg)
if not pause_ok:

View File

@ -761,6 +761,52 @@ def test_pending_paper_order_reconciles_from_latest_price_cache(monkeypatch):
assert order["fill_price"] == pytest.approx(95)
def test_touched_wait_pullback_order_stays_pending_when_global_risk_pauses(monkeypatch):
monkeypatch.setenv("ALPHAX_PAPER_TRADING_ENABLED", "1")
monkeypatch.setenv("ALPHAX_PAPER_GLOBAL_RISK_GATE_ENABLED", "1")
monkeypatch.setattr(
"app.db.paper_trading.evaluate_global_risk",
lambda **kwargs: {
"allow_new_entries": False,
"decision": "block_critical_weak_score",
"risk_level": "critical",
"reasons": ["critical 市场环境下推荐分不足"],
},
)
altcoin_db.init_db()
rec_id = altcoin_db.create_recommendation(
symbol="RISKPAUSE/USDT",
rec_state="蓄力",
rec_score=22,
entry_price=95,
stop_loss=90,
tp1=105,
tp2=112,
signals=["等待回踩"],
entry_plan={"entry_action": "等回踩", "entry_price": 95, "stop_loss": 90, "tp1": 105, "risk_reward_ok": True, "rr1": 2.0},
)
rec = {
"id": rec_id,
"symbol": "RISKPAUSE/USDT",
"execution_status": "wait_pullback",
"action_status": "等回踩",
"entry_price": 95,
"stop_loss": 90,
"tp1": 105,
"tp2": 112,
"entry_plan": {"entry_action": "等回踩", "entry_price": 95, "stop_loss": 90, "tp1": 105, "risk_reward_ok": True, "rr1": 2.0},
}
created = sync_recommendation(rec, 100, event_time="2026-05-16T10:00:00")
paused = sync_recommendation(rec, 94.9, event_time="2026-05-16T10:05:00")
assert created["reason"] == "paper_order_created"
assert paused["reason"] == "paper_order_risk_paused"
assert list_paper_trades()["total"] == 0
assert list_paper_orders(status="pending")["items"][0]["symbol"] == "RISKPAUSE/USDT"
assert list_paper_orders(status="canceled")["total"] == 0
def test_wait_pullback_order_cancels_when_recommendation_invalid(monkeypatch):
monkeypatch.setenv("ALPHAX_PAPER_TRADING_ENABLED", "1")
altcoin_db.init_db()