1
This commit is contained in:
parent
15abdc3286
commit
5c86864d2f
@ -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:
|
||||
|
||||
@ -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()
|
||||
|
||||
Loading…
Reference in New Issue
Block a user