Sync exchange PnL when hub loads trade records API.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -2440,6 +2440,11 @@ def insert_trade_record(
|
||||
opened_at_ms=open_ts_ms,
|
||||
closed_at_ms=close_ts_ms,
|
||||
)
|
||||
# 中控只拉 /api/trade_records,平仓当下也尝试回填交易所盈亏(内部 25s 节流)
|
||||
try:
|
||||
sync_trade_records_from_exchange(conn, force=False)
|
||||
except Exception:
|
||||
pass
|
||||
return tid
|
||||
|
||||
|
||||
@@ -6942,7 +6947,11 @@ def sync_trade_records_from_exchange(conn, force=False):
|
||||
matched += 1
|
||||
stats["matched"] = matched
|
||||
stats["ok"] = True
|
||||
_LAST_EXCHANGE_PNL_SYNC_AT = now
|
||||
# 仍有未匹配且历史非空:缩短节流,避免平仓后历史稍晚入库时卡在「估」
|
||||
if matched < stats["pending"] and hist:
|
||||
_LAST_EXCHANGE_PNL_SYNC_AT = now - 15.0
|
||||
else:
|
||||
_LAST_EXCHANGE_PNL_SYNC_AT = now
|
||||
try:
|
||||
conn.commit()
|
||||
except Exception:
|
||||
@@ -9378,6 +9387,7 @@ register_trade_records_api(
|
||||
filter_trade_records_excluding_miss=filter_trade_records_excluding_miss,
|
||||
app_tz=APP_TZ,
|
||||
format_price_fn=format_price_for_symbol,
|
||||
sync_exchange_pnl_fn=lambda conn: sync_trade_records_from_exchange(conn, force=False),
|
||||
)
|
||||
|
||||
def _dashboard_enrich_orders(items):
|
||||
|
||||
@@ -2359,6 +2359,11 @@ def insert_trade_record(
|
||||
opened_at_ms=open_ts_ms,
|
||||
closed_at_ms=close_ts_ms,
|
||||
)
|
||||
# 中控只拉 /api/trade_records,平仓当下也尝试回填交易所盈亏(内部 25s 节流)
|
||||
try:
|
||||
sync_trade_records_from_exchange(conn, force=False)
|
||||
except Exception:
|
||||
pass
|
||||
return tid
|
||||
|
||||
|
||||
@@ -4090,7 +4095,11 @@ def sync_trade_records_from_exchange(conn, force=False):
|
||||
matched += 1
|
||||
stats["matched"] = matched
|
||||
stats["ok"] = True
|
||||
_LAST_EXCHANGE_PNL_SYNC_AT = now
|
||||
# 仍有未匹配且历史非空:缩短节流,避免平仓后历史稍晚入库时卡在「估」
|
||||
if matched < stats["pending"] and hist:
|
||||
_LAST_EXCHANGE_PNL_SYNC_AT = now - 15.0
|
||||
else:
|
||||
_LAST_EXCHANGE_PNL_SYNC_AT = now
|
||||
try:
|
||||
conn.commit()
|
||||
except Exception:
|
||||
@@ -9066,6 +9075,7 @@ register_trade_records_api(
|
||||
filter_trade_records_excluding_miss=filter_trade_records_excluding_miss,
|
||||
app_tz=APP_TZ,
|
||||
format_price_fn=format_price_for_symbol,
|
||||
sync_exchange_pnl_fn=lambda conn: sync_trade_records_from_exchange(conn, force=False),
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -19,7 +19,12 @@ def register_trade_records_api(
|
||||
filter_trade_records_excluding_miss: Callable[[list], list],
|
||||
app_tz: Any,
|
||||
format_price_fn: Callable[[Any, Any], str] | None = None,
|
||||
sync_exchange_pnl_fn: Callable[[Any], Any] | None = None,
|
||||
) -> None:
|
||||
"""
|
||||
sync_exchange_pnl_fn(conn): 可选,列表前节流回填交易所已实现盈亏.
|
||||
中控只走本 API,不经实例整页渲染,必须在此触发,否则盈亏U会一直显示「估」.
|
||||
"""
|
||||
from lib.instance.records_list_lib import list_trade_records_page
|
||||
|
||||
@app.route("/api/trade_records")
|
||||
@@ -40,6 +45,11 @@ def register_trade_records_api(
|
||||
offset = 0
|
||||
conn = get_db()
|
||||
try:
|
||||
if sync_exchange_pnl_fn is not None:
|
||||
try:
|
||||
sync_exchange_pnl_fn(conn)
|
||||
except Exception:
|
||||
pass
|
||||
payload = list_trade_records_page(
|
||||
conn,
|
||||
start_bj,
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
"""records_api_register: list API can trigger exchange pnl sync."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import unittest
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
from flask import Flask
|
||||
|
||||
from lib.instance.records_api_register import register_trade_records_api
|
||||
|
||||
|
||||
class RecordsApiSyncHookTest(unittest.TestCase):
|
||||
def test_list_calls_sync_hook(self):
|
||||
app = Flask(__name__)
|
||||
sync_calls = []
|
||||
|
||||
def _login(fn):
|
||||
return fn
|
||||
|
||||
def _get_db():
|
||||
conn = MagicMock()
|
||||
conn.execute.return_value.fetchall.return_value = []
|
||||
return conn
|
||||
|
||||
def _win():
|
||||
return {"start_utc": None, "end_utc": None}
|
||||
|
||||
register_trade_records_api(
|
||||
app,
|
||||
login_required=_login,
|
||||
get_db=_get_db,
|
||||
list_window_from_request=_win,
|
||||
utc_window_to_bj_sql_strings=lambda *a, **k: ("2026-01-01", "2026-12-31"),
|
||||
sql_list_time_field=lambda *a, **k: "COALESCE(closed_at, created_at, opened_at)",
|
||||
to_effective_trade_dict=lambda r: dict(r) if hasattr(r, "keys") else r,
|
||||
filter_trade_records_excluding_miss=lambda xs: xs,
|
||||
app_tz=None,
|
||||
sync_exchange_pnl_fn=lambda conn: sync_calls.append(conn),
|
||||
)
|
||||
client = app.test_client()
|
||||
resp = client.get("/api/trade_records")
|
||||
self.assertEqual(resp.status_code, 200)
|
||||
self.assertEqual(len(sync_calls), 1)
|
||||
body = resp.get_json()
|
||||
self.assertTrue(body.get("ok"))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user