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))
|
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)
|
global_ok, global_detail = _global_risk_entry_check(conn, rec, base_notional, cfg)
|
||||||
if not global_ok:
|
if not global_ok:
|
||||||
result = _cancel_paper_order(conn, order, "global_risk_rejected", event_time)
|
# Market/account risk is a temporary execution gate, not proof that the
|
||||||
result["risk_detail"] = global_detail
|
# original limit order is invalid. Keep the order pending so it can fill
|
||||||
return result
|
# 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)
|
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)
|
pause_ok, pause_reason, pause_detail = _portfolio_entry_pause_check(conn, adjusted_notional, event_time, cfg)
|
||||||
if not pause_ok:
|
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)
|
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):
|
def test_wait_pullback_order_cancels_when_recommendation_invalid(monkeypatch):
|
||||||
monkeypatch.setenv("ALPHAX_PAPER_TRADING_ENABLED", "1")
|
monkeypatch.setenv("ALPHAX_PAPER_TRADING_ENABLED", "1")
|
||||||
altcoin_db.init_db()
|
altcoin_db.init_db()
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user