Skip to content

Commit 4fed02e

Browse files
committed
refactor(quick-trade): move fill history orchestration into service
1 parent aaa08b7 commit 4fed02e

3 files changed

Lines changed: 49 additions & 39 deletions

File tree

‎backend_api_python/app/routes/quick_trade.py‎

Lines changed: 3 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@
5555
)
5656
from app.services.quick_trade.symbols import is_supported_crypto_exchange, symbols_match as quick_trade_symbols_match
5757
from app.services.quick_trade.history import parse_quick_trade_metadata, history_order_status
58+
from app.services.quick_trade.trade_history import resolve_trade_history
5859
from app.services.quick_trade.fee_reconciliation import fee_update_from_fill, reconcile_quick_trade_fees
5960
from app.services.quick_trade.order_reconciliation import reconcile_quick_trade_orders
6061
from app.services.quick_trade.account_warmup import configure_quick_trade_derivatives, warm_quick_trade_account
@@ -1876,43 +1877,8 @@ def get_history():
18761877
"created_at": to_utc_iso(r.get("created_at")) or str(r.get("created_at") or ""),
18771878
})
18781879

1879-
exchange_history = {"supported": False, "trades": []}
1880-
if credential_id > 0 and symbol and market_type in ("spot", "swap"):
1881-
try:
1882-
from app.services.quick_trade.trade_history import exchange_trade_history
1883-
1884-
config = build_exchange_config(credential_id, user_id, {"market_type": market_type})
1885-
client = create_exchange_client(config, market_type=market_type)
1886-
exchange_history = exchange_trade_history(
1887-
client,
1888-
symbol,
1889-
market_type=market_type,
1890-
limit=limit,
1891-
offset=offset,
1892-
)
1893-
except Exception as exc:
1894-
logger.info("Native exchange trade history unavailable: %s", exc)
1895-
1896-
if exchange_history.get("supported"):
1897-
active_statuses = {
1898-
"new", "open", "pending", "submitted", "partially_filled",
1899-
"partially-filled", "accepted", "cancel_pending",
1900-
}
1901-
pending_orders = [
1902-
trade for trade in trades
1903-
if str(trade.get("status") or "").strip().lower() in active_statuses
1904-
]
1905-
trades = pending_orders + list(exchange_history.get("trades") or [])
1906-
trades.sort(key=lambda trade: str(trade.get("created_at") or ""), reverse=True)
1907-
1908-
return jsonify({
1909-
"code": 1,
1910-
"msg": "success",
1911-
"data": {
1912-
"trades": trades,
1913-
"source": "exchange" if exchange_history.get("supported") else "local_fallback",
1914-
},
1915-
})
1880+
data = resolve_trade_history(trades, user_id, credential_id, symbol, market_type, limit, offset)
1881+
return jsonify({"code": 1, "msg": "success", "data": data})
19161882
except Exception as e:
19171883
logger.error(f"get_history failed: {e}")
19181884
return jsonify({"code": 0, "msg": str(e)}), 500

‎backend_api_python/app/services/quick_trade/trade_history.py‎

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,17 @@
2424
to_okx_spot_inst_id,
2525
to_okx_swap_inst_id,
2626
)
27+
from app.services.quick_trade.credentials import build_exchange_config, create_exchange_client
2728
from app.utils.logger import get_logger
2829

2930

3031
logger = get_logger(__name__)
3132

33+
ACTIVE_ORDER_STATUSES = frozenset({
34+
"new", "open", "pending", "submitted", "partially_filled",
35+
"partially-filled", "accepted", "cancel_pending",
36+
})
37+
3238

3339
def _number(value: Any, default: float = 0.0) -> float:
3440
try:
@@ -617,3 +623,41 @@ def exchange_trade_history(
617623
result["trades"] = _normalize_rows(result.get("trades") or [], limit=limit, offset=offset)
618624
return result
619625
return {"supported": False, "trades": []}
626+
627+
628+
def resolve_trade_history(
629+
local_trades: Iterable[Dict[str, Any]],
630+
user_id: int,
631+
credential_id: int,
632+
symbol: str,
633+
market_type: str,
634+
limit: int,
635+
offset: int,
636+
) -> Dict[str, Any]:
637+
"""Prefer authoritative exchange fills while retaining active local orders."""
638+
local_rows = list(local_trades)
639+
fallback = {"trades": local_rows, "source": "local_fallback"}
640+
if credential_id <= 0 or not symbol or market_type not in {"spot", "swap"}:
641+
return fallback
642+
try:
643+
config = build_exchange_config(credential_id, user_id, {"market_type": market_type})
644+
client = create_exchange_client(config, market_type=market_type)
645+
exchange_history = exchange_trade_history(
646+
client,
647+
symbol,
648+
market_type=market_type,
649+
limit=limit,
650+
offset=offset,
651+
)
652+
except Exception as exc:
653+
logger.info("Native exchange trade history unavailable: %s", exc)
654+
return fallback
655+
if not exchange_history.get("supported"):
656+
return fallback
657+
pending_orders = [
658+
trade for trade in local_rows
659+
if str(trade.get("status") or "").strip().lower() in ACTIVE_ORDER_STATUSES
660+
]
661+
trades = pending_orders + list(exchange_history.get("trades") or [])
662+
trades.sort(key=lambda trade: str(trade.get("created_at") or ""), reverse=True)
663+
return {"trades": trades, "source": "exchange"}

‎backend_api_python/tests/test_quick_trade_history.py‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -184,9 +184,9 @@ def fake_connection():
184184
}
185185
monkeypatch.setattr(quick_trade, "get_db_connection", fake_connection)
186186
monkeypatch.setattr(quick_trade, "_sync_exchange_close_fills", lambda **kwargs: 0)
187-
monkeypatch.setattr(quick_trade, "build_exchange_config", lambda *args, **kwargs: {})
188-
monkeypatch.setattr(quick_trade, "create_exchange_client", lambda *args, **kwargs: object())
189187
from app.services.quick_trade import trade_history
188+
monkeypatch.setattr(trade_history, "build_exchange_config", lambda *args, **kwargs: {})
189+
monkeypatch.setattr(trade_history, "create_exchange_client", lambda *args, **kwargs: object())
190190
monkeypatch.setattr(
191191
trade_history,
192192
"exchange_trade_history",

0 commit comments

Comments
 (0)