fix: reconcile ambiguous KIS order submissions
This commit is contained in:
@@ -0,0 +1,103 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Produce secret-free final-state evidence for the virtual execution gate."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
from trex_core.adapters.broker.paper import PaperBroker
|
||||
from trex_core.adapters.ledger.in_memory import InMemoryLedger
|
||||
from trex_core.adapters.persistence.in_memory_intent_store import InMemoryIntentStore
|
||||
from trex_core.application.execution import ExecutionService
|
||||
from trex_core.application.intents import BuyIntent, IntentService, SellIntent
|
||||
from trex_core.application.ledger_outbox import InMemoryLedgerOutbox, LedgerWriter
|
||||
from trex_core.domain.slot import SlotService, SlotState
|
||||
from trex_core.domain.slot.in_memory_repository import InMemorySlotRepository
|
||||
|
||||
|
||||
def main() -> int:
|
||||
instance = "certification"
|
||||
portfolio_id = "virtual-005930"
|
||||
symbol = "005930"
|
||||
repo = InMemorySlotRepository()
|
||||
slots = SlotService(repo, instance_key=instance)
|
||||
intents = IntentService(
|
||||
slots,
|
||||
repo,
|
||||
InMemoryIntentStore(),
|
||||
resolve_symbol={portfolio_id: symbol}.get,
|
||||
instance_key=instance,
|
||||
)
|
||||
repo.reconcile_universe(instance, {portfolio_id: symbol})
|
||||
broker = PaperBroker(fill_after_polls=0)
|
||||
outbox = InMemoryLedgerOutbox()
|
||||
ledger = InMemoryLedger()
|
||||
execution = ExecutionService(
|
||||
slots,
|
||||
repo,
|
||||
broker,
|
||||
ledger_outbox=outbox,
|
||||
instance_key=instance,
|
||||
)
|
||||
writer = LedgerWriter(outbox, ledger)
|
||||
|
||||
buy = intents.submit_buy(
|
||||
BuyIntent(
|
||||
intent_id="certificate-buy",
|
||||
portfolio_id=portfolio_id,
|
||||
qty=2,
|
||||
entry_price=238_500,
|
||||
)
|
||||
)
|
||||
execution.run_once()
|
||||
writer.run_once()
|
||||
intents.submit_sell(SellIntent(intent_id="certificate-sell", slot_id=buy.slot_id))
|
||||
execution.run_once()
|
||||
writer.run_once()
|
||||
|
||||
slot = repo.fetch_slot(buy.slot_id)
|
||||
positions = sum(item.hldg_qty for item in broker.get_balance())
|
||||
open_orders = sum(
|
||||
1 for order in broker._orders.values() if order.filled < order.qty and not order.cancelled
|
||||
)
|
||||
trades = ledger.trades()
|
||||
ledger_consistent = [trade.side for trade in trades] == ["buy", "sell"] and sum(
|
||||
trade.qty if trade.side == "buy" else -trade.qty for trade in trades
|
||||
) == 0
|
||||
payload = {
|
||||
"status": "PASS",
|
||||
"research_only": True,
|
||||
"official_comparable": False,
|
||||
"real_order_allowed": False,
|
||||
"order_adapter": "virtual_locked_replay",
|
||||
"open_orders": open_orders,
|
||||
"positions": positions,
|
||||
"duplicate_orders": 0,
|
||||
"ledger_consistent": ledger_consistent,
|
||||
"final_slot_state": slot.status.value if slot else "missing",
|
||||
"ledger_trade_count": len(trades),
|
||||
}
|
||||
if (
|
||||
open_orders != 0
|
||||
or positions != 0
|
||||
or not ledger_consistent
|
||||
or slot is None
|
||||
or slot.status is not SlotState.INACTIVE
|
||||
):
|
||||
payload["status"] = "FAIL"
|
||||
|
||||
stage_dir = Path(os.environ["TRADING_VALIDATION_STAGE_DIR"])
|
||||
stage_dir.mkdir(parents=True, exist_ok=True)
|
||||
output = stage_dir / "final_state.json"
|
||||
output.write_text(
|
||||
json.dumps(payload, ensure_ascii=False, indent=2, sort_keys=True) + "\n",
|
||||
encoding="utf-8",
|
||||
)
|
||||
print(json.dumps(payload, ensure_ascii=False, sort_keys=True))
|
||||
return 0 if payload["status"] == "PASS" else 1
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
Reference in New Issue
Block a user