Show trade record prices at exchange tick precision.
API enriches entry/SL/TP with price_to_precision display strings; OKX formatter now uses the same path as Gate/Binance. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -9530,6 +9530,7 @@ register_trade_records_api(
|
||||
to_effective_trade_dict=to_effective_trade_dict,
|
||||
filter_trade_records_excluding_miss=filter_trade_records_excluding_miss,
|
||||
app_tz=APP_TZ,
|
||||
format_price_fn=format_price_for_symbol,
|
||||
)
|
||||
|
||||
def _dashboard_enrich_orders(items):
|
||||
|
||||
@@ -9368,6 +9368,7 @@ register_trade_records_api(
|
||||
to_effective_trade_dict=to_effective_trade_dict,
|
||||
filter_trade_records_excluding_miss=filter_trade_records_excluding_miss,
|
||||
app_tz=APP_TZ,
|
||||
format_price_fn=format_price_for_symbol,
|
||||
)
|
||||
|
||||
def _dashboard_enrich_orders(items):
|
||||
|
||||
@@ -2107,6 +2107,7 @@ def to_effective_trade_dict(row):
|
||||
|
||||
|
||||
def format_price_for_symbol(symbol, value):
|
||||
"""价格展示:与交易所 price_to_precision 一致(与入库 round_price_to_exchange 对齐)."""
|
||||
if value in (None, ""):
|
||||
return "-"
|
||||
try:
|
||||
@@ -2115,8 +2116,15 @@ def format_price_for_symbol(symbol, value):
|
||||
return str(value)
|
||||
if v == 0:
|
||||
return "0"
|
||||
try:
|
||||
ex_sym = normalize_okx_symbol(str(symbol or "").strip()) if symbol else ""
|
||||
if ex_sym:
|
||||
ensure_markets_loaded()
|
||||
return str(exchange.price_to_precision(ex_sym, v))
|
||||
except Exception:
|
||||
pass
|
||||
av = abs(v)
|
||||
# 根据币价量级动态精度:低价币保留更多小数,高价币减少噪音位数
|
||||
# 无法加载市场或无该合约时:按价格量级回退(尽量不阻断页面)
|
||||
if av >= 10000:
|
||||
d = 2
|
||||
elif av >= 100:
|
||||
@@ -9035,6 +9043,7 @@ register_trade_records_api(
|
||||
to_effective_trade_dict=to_effective_trade_dict,
|
||||
filter_trade_records_excluding_miss=filter_trade_records_excluding_miss,
|
||||
app_tz=APP_TZ,
|
||||
format_price_fn=format_price_for_symbol,
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -42,6 +42,25 @@
|
||||
return n.toFixed(digits == null ? 2 : digits);
|
||||
}
|
||||
|
||||
/** 优先用后端交易所精度字符串;否则回退量级格式(与 formatPriceForInput 一致). */
|
||||
function fmtPx(display, raw) {
|
||||
if (display != null && display !== "") return esc(display);
|
||||
if (raw == null || raw === "") return "—";
|
||||
var n = Number(raw);
|
||||
if (!Number.isFinite(n)) return esc(raw);
|
||||
var av = Math.abs(n);
|
||||
var d;
|
||||
if (av >= 10000) d = 2;
|
||||
else if (av >= 100) d = 3;
|
||||
else if (av >= 1) d = 4;
|
||||
else if (av >= 0.01) d = 6;
|
||||
else if (av >= 0.0001) d = 8;
|
||||
else d = 10;
|
||||
var text = n.toFixed(d);
|
||||
if (text.indexOf(".") >= 0) text = text.replace(/\.?0+$/, "");
|
||||
return text;
|
||||
}
|
||||
|
||||
function fmtTime(s) {
|
||||
if (!s) return "—";
|
||||
return esc(String(s).slice(0, 16));
|
||||
@@ -199,13 +218,13 @@
|
||||
dirTxt +
|
||||
"</span></td>" +
|
||||
"<td>" +
|
||||
fmtNum(t.trigger_price, 4) +
|
||||
fmtPx(t.trigger_price_display, t.trigger_price) +
|
||||
"</td>" +
|
||||
"<td>" +
|
||||
fmtNum(stopShow, 4) +
|
||||
fmtPx(t.stop_loss_display, stopShow) +
|
||||
"</td>" +
|
||||
"<td>" +
|
||||
fmtNum(tpShow, 4) +
|
||||
fmtPx(t.take_profit_display, tpShow) +
|
||||
"</td>" +
|
||||
"<td>" +
|
||||
margin +
|
||||
|
||||
@@ -18,6 +18,7 @@ def register_trade_records_api(
|
||||
to_effective_trade_dict: Callable[[Any], dict[str, Any]],
|
||||
filter_trade_records_excluding_miss: Callable[[list], list],
|
||||
app_tz: Any,
|
||||
format_price_fn: Callable[[Any, Any], str] | None = None,
|
||||
) -> None:
|
||||
from lib.instance.records_list_lib import list_trade_records_page
|
||||
|
||||
@@ -48,6 +49,7 @@ def register_trade_records_api(
|
||||
filter_fn=filter_trade_records_excluding_miss,
|
||||
limit=limit,
|
||||
offset=offset,
|
||||
format_price_fn=format_price_fn,
|
||||
)
|
||||
return jsonify(payload)
|
||||
finally:
|
||||
|
||||
@@ -2,7 +2,32 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any, Callable
|
||||
from typing import Any, Callable, Optional
|
||||
|
||||
|
||||
def enrich_trade_price_displays(
|
||||
item: dict[str, Any],
|
||||
format_price_fn: Optional[Callable[[Any, Any], str]] = None,
|
||||
) -> dict[str, Any]:
|
||||
"""为成交/止损/止盈补交易所精度展示字段(供交易记录表直接渲染)."""
|
||||
if not format_price_fn or not isinstance(item, dict):
|
||||
return item
|
||||
sym = item.get("symbol")
|
||||
stop_show = item.get("display_open_stop_loss")
|
||||
if stop_show in (None, ""):
|
||||
stop_show = item.get("initial_stop_loss")
|
||||
if stop_show in (None, ""):
|
||||
stop_show = item.get("stop_loss")
|
||||
tp_show = item.get("effective_take_profit")
|
||||
if tp_show in (None, ""):
|
||||
tp_show = item.get("take_profit")
|
||||
try:
|
||||
item["trigger_price_display"] = format_price_fn(sym, item.get("trigger_price"))
|
||||
item["stop_loss_display"] = format_price_fn(sym, stop_show)
|
||||
item["take_profit_display"] = format_price_fn(sym, tp_show)
|
||||
except Exception:
|
||||
pass
|
||||
return item
|
||||
|
||||
|
||||
def list_trade_records_page(
|
||||
@@ -16,6 +41,7 @@ def list_trade_records_page(
|
||||
limit: int = 5,
|
||||
offset: int = 0,
|
||||
fetch_cap: int = 1000,
|
||||
format_price_fn: Optional[Callable[[Any, Any], str]] = None,
|
||||
) -> dict[str, Any]:
|
||||
"""按列表窗拉取、enrich、过滤「错过」后分页."""
|
||||
limit = max(1, min(100, int(limit or 5)))
|
||||
@@ -33,6 +59,8 @@ def list_trade_records_page(
|
||||
page = pages
|
||||
offset = (page - 1) * limit
|
||||
items = records[offset : offset + limit]
|
||||
if format_price_fn is not None:
|
||||
items = [enrich_trade_price_displays(dict(it), format_price_fn) for it in items]
|
||||
return {
|
||||
"ok": True,
|
||||
"items": items,
|
||||
|
||||
@@ -78,6 +78,25 @@ class RecordsListLibTest(unittest.TestCase):
|
||||
self.assertEqual(out["page"], 2)
|
||||
self.assertEqual(len(out["items"]), 5)
|
||||
|
||||
def test_price_display_enrich(self):
|
||||
from lib.instance.records_list_lib import enrich_trade_price_displays
|
||||
|
||||
item = {
|
||||
"symbol": "BTC/USDT",
|
||||
"trigger_price": 63902.0,
|
||||
"display_open_stop_loss": 64500.0,
|
||||
"effective_take_profit": 62800.0,
|
||||
}
|
||||
|
||||
def _fmt(sym, v):
|
||||
self.assertEqual(sym, "BTC/USDT")
|
||||
return f"{float(v):.1f}"
|
||||
|
||||
out = enrich_trade_price_displays(item, _fmt)
|
||||
self.assertEqual(out["trigger_price_display"], "63902.0")
|
||||
self.assertEqual(out["stop_loss_display"], "64500.0")
|
||||
self.assertEqual(out["take_profit_display"], "62800.0")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
||||
Reference in New Issue
Block a user