117 lines
4.5 KiB
Python
117 lines
4.5 KiB
Python
from app.core.factor_roles import RISK, TRIGGER, factor_role, factor_roles_for_codes
|
|
from app.core.strategy_contract import StrategySignal, default_main_composite_signal
|
|
from app.core.strategy_registry import BOX_RETEST_4H_STRATEGY, MAIN_COMPOSITE_STRATEGY, strategy_label
|
|
from app.db.recommendation_commands import create_recommendation
|
|
from app.db.strategy_signal_queries import insert_strategy_signal
|
|
from app.db.paper_trading import _open_trade, _order_payload_from_rec
|
|
|
|
|
|
def test_factor_roles_never_promote_unknown_to_trigger():
|
|
assert factor_role("box_breakout_pullback_4h") == TRIGGER
|
|
assert factor_role("false_breakout") == RISK
|
|
assert factor_role("new_unknown_factor") == "unknown"
|
|
assert factor_roles_for_codes(["box_breakout_pullback_4h", "new_unknown_factor"]) == {
|
|
"box_breakout_pullback_4h": "trigger",
|
|
"new_unknown_factor": "unknown",
|
|
}
|
|
|
|
|
|
def test_default_main_composite_strategy_signal_is_stable():
|
|
signal = default_main_composite_signal(
|
|
symbol="AAA/USDT",
|
|
score=70,
|
|
signal_codes=["vp_fly_1h_current"],
|
|
entry_plan={"entry_action": "观察"},
|
|
).to_json_dict()
|
|
|
|
assert signal["strategy_code"] == MAIN_COMPOSITE_STRATEGY
|
|
assert signal["strategy_name"] == "综合确认主链路"
|
|
assert signal["factor_roles"]["vp_fly_1h_current"] == "trigger"
|
|
|
|
|
|
def test_strategy_signal_insert_and_recommendation_lineage(pg_conn):
|
|
signal = insert_strategy_signal(
|
|
StrategySignal(
|
|
strategy_code=BOX_RETEST_4H_STRATEGY,
|
|
symbol="BOX/USDT",
|
|
score=10,
|
|
confidence=80,
|
|
trigger={"factor_code": "box_breakout_pullback_4h"},
|
|
factor_roles={"box_breakout_pullback_4h": "trigger"},
|
|
entry_plan={"entry_action": "等回踩", "entry_price": 1.0},
|
|
)
|
|
)
|
|
|
|
rec_id = create_recommendation(
|
|
symbol="BOX/USDT",
|
|
rec_state="爆发",
|
|
rec_score=30,
|
|
entry_price=1.0,
|
|
stop_loss=0.94,
|
|
tp1=1.12,
|
|
signals=["4H箱体突破回踩(箱体上沿 $1, 量2x)"],
|
|
entry_plan={"entry_action": "等回踩", "entry_price": 1.0, "stop_loss": 0.94, "tp1": 1.12},
|
|
strategy_code=signal["strategy_code"],
|
|
strategy_signal_id=signal["strategy_signal_id"],
|
|
strategy_snapshot=signal,
|
|
factor_roles=signal["factor_roles"],
|
|
)
|
|
row = pg_conn.execute("SELECT * FROM recommendation WHERE id=%s", (rec_id,)).fetchone()
|
|
|
|
assert row["strategy_code"] == BOX_RETEST_4H_STRATEGY
|
|
assert row["strategy_signal_id"] == signal["strategy_signal_id"]
|
|
assert "box_breakout_pullback_4h" in row["factor_roles_json"]
|
|
|
|
|
|
def test_paper_order_and_trade_inherit_strategy_lineage(pg_conn):
|
|
rec = {
|
|
"id": 1,
|
|
"symbol": "BOX/USDT",
|
|
"rec_score": 100,
|
|
"entry_price": 1.0,
|
|
"stop_loss": 0.94,
|
|
"tp1": 1.12,
|
|
"tp2": 1.2,
|
|
"execution_status": "buy_now",
|
|
"action_status": "可即刻买入",
|
|
"strategy_version": "v-test",
|
|
"strategy_code": BOX_RETEST_4H_STRATEGY,
|
|
"strategy_signal_id": 42,
|
|
"strategy_snapshot_json": '{"strategy_code":"box_retest_4h_v1"}',
|
|
"factor_roles_json": '{"box_breakout_pullback_4h":"trigger"}',
|
|
"entry_plan": {"entry_action": "可即刻买入", "entry_price": 1.0, "stop_loss": 0.94, "tp1": 1.12},
|
|
}
|
|
|
|
payload = _order_payload_from_rec(rec, 1.01, "2026-05-27T00:00:00", {"trade_notional_usdt": 100})
|
|
assert payload["strategy_code"] == BOX_RETEST_4H_STRATEGY
|
|
assert payload["strategy_signal_id"] == 42
|
|
|
|
result = _open_trade(
|
|
pg_conn,
|
|
rec,
|
|
1.0,
|
|
"2026-05-27T00:00:00",
|
|
config={
|
|
"enabled": True,
|
|
"trade_notional_usdt": 100,
|
|
"trade_leverage": 1,
|
|
"account_equity_usdt": 20000,
|
|
"fee_rate": 0,
|
|
"min_rec_score": 0,
|
|
"min_rr": 0,
|
|
"max_stop_loss_leverage_risk_pct": 999,
|
|
"max_cumulative_leverage": 999,
|
|
"max_account_drawdown_pause_pct": 0,
|
|
"weak_entry_pause": {"enabled": False},
|
|
},
|
|
push_open_card=False,
|
|
)
|
|
assert result["opened"] is True
|
|
row = pg_conn.execute("SELECT * FROM paper_trades WHERE id=%s", (result["trade_id"],)).fetchone()
|
|
event = pg_conn.execute("SELECT * FROM paper_trade_events WHERE trade_id=%s", (result["trade_id"],)).fetchone()
|
|
|
|
assert row["strategy_code"] == BOX_RETEST_4H_STRATEGY
|
|
assert row["strategy_signal_id"] == 42
|
|
assert event["strategy_code"] == BOX_RETEST_4H_STRATEGY
|
|
assert strategy_label(row["strategy_code"]) == "4H箱体突破回踩"
|