test_eth_nextgen_micro_executor.py 3.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. import importlib.util
  2. import sys
  3. from pathlib import Path
  4. from okx_codex_trader.live_execution import TargetPosition
  5. def load_executor():
  6. path = Path(__file__).resolve().parents[1] / "scripts" / "run_eth_nextgen_micro_executor.py"
  7. spec = importlib.util.spec_from_file_location("run_eth_nextgen_micro_executor", path)
  8. assert spec is not None
  9. module = importlib.util.module_from_spec(spec)
  10. assert spec.loader is not None
  11. sys.modules[spec.name] = module
  12. spec.loader.exec_module(module)
  13. return module
  14. executor = load_executor()
  15. def payload_with_nextgen_long():
  16. return {
  17. "decision": {"active_engine": "nextgen", "selected_signal": "long"},
  18. "execution_intent": {"entry_signal": "long", "entry_unit": 0.5, "target_position_known": False, "target_position": None},
  19. "nextgen": {
  20. "data": {"decision_candle_ts": 1000},
  21. "legs": [
  22. {"leg_id": "a", "suggested_weight": 0.5, "signal": True, "exit_signal": False},
  23. {"leg_id": "b", "suggested_weight": 0.5, "signal": False, "exit_signal": False},
  24. ],
  25. },
  26. }
  27. def test_executor_snapshot_does_not_render_orders_when_current_position_is_unknown(monkeypatch, tmp_path):
  28. monkeypatch.setattr(executor.eth_nextgen_micro, "build_payload", payload_with_nextgen_long)
  29. monkeypatch.setattr(
  30. executor,
  31. "account_current_position",
  32. lambda _: (TargetPosition(side="flat", unit=0.0, known=False, reason="no credentials"), {"account_error": "no credentials"}),
  33. )
  34. snapshot = executor.build_snapshot(state_dir=tmp_path, margin_per_unit_usdt=1000.0, max_new_margin_usdt=500.0, max_total_margin_usdt=1000.0)
  35. assert snapshot["orders_submitted"] == 0
  36. assert snapshot["target_position"]["known"] is True
  37. assert snapshot["target_position"]["unit"] == 0.5
  38. assert snapshot["current_position"]["known"] is False
  39. assert snapshot["rendered_orders"] == []
  40. def test_executor_snapshot_renders_order_body_when_positions_are_known(monkeypatch, tmp_path):
  41. monkeypatch.setattr(executor.eth_nextgen_micro, "build_payload", payload_with_nextgen_long)
  42. monkeypatch.setattr(
  43. executor,
  44. "account_current_position",
  45. lambda _: (
  46. TargetPosition(side="flat", unit=0.0, known=True, reason="flat"),
  47. {"mark_price": 3000.0, "instrument_meta": {"ct_val": 0.1, "lot_sz": 1.0, "min_sz": 1.0}},
  48. ),
  49. )
  50. snapshot = executor.build_snapshot(state_dir=tmp_path, margin_per_unit_usdt=1000.0, max_new_margin_usdt=500.0, max_total_margin_usdt=1000.0)
  51. assert snapshot["orders_submitted"] == 0
  52. assert snapshot["rendered_orders"] == [
  53. {
  54. "action": "open",
  55. "margin_usdt": 500.0,
  56. "body": {
  57. "instId": "ETH-USDT-SWAP",
  58. "tdMode": "isolated",
  59. "side": "buy",
  60. "posSide": "long",
  61. "ordType": "market",
  62. "sz": "5",
  63. "clOrdId": "ethnm-1000-1-open",
  64. },
  65. }
  66. ]
  67. def test_executor_uses_executor_state_file(monkeypatch, tmp_path):
  68. monkeypatch.setattr(executor.eth_nextgen_micro, "build_payload", payload_with_nextgen_long)
  69. monkeypatch.setattr(
  70. executor,
  71. "account_current_position",
  72. lambda _: (
  73. TargetPosition(side="flat", unit=0.0, known=True, reason="flat"),
  74. {"mark_price": 3000.0, "instrument_meta": {"ct_val": 0.1, "lot_sz": 1.0, "min_sz": 1.0}},
  75. ),
  76. )
  77. (tmp_path / "runtime-state.json").write_text('{"last_candle_ts":1000,"micro_side":null,"nextgen_active_legs":[]}\n', encoding="utf-8")
  78. snapshot = executor.build_snapshot(state_dir=tmp_path, margin_per_unit_usdt=1000.0, max_new_margin_usdt=500.0, max_total_margin_usdt=1000.0)
  79. assert snapshot["target_position"]["unit"] == 0.5