关键位现价改与顶栏同源公开行情,前端无价时回退 nav tickers。
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -2591,7 +2591,10 @@ def get_available_trading_usdt():
|
||||
|
||||
|
||||
def get_synced_leverage(exchange_symbol, direction):
|
||||
try:
|
||||
ensure_markets_loaded()
|
||||
except Exception:
|
||||
return None
|
||||
# 1) 优先读取交易所杠杆配置
|
||||
try:
|
||||
if hasattr(exchange, "fetch_leverage"):
|
||||
@@ -4178,31 +4181,46 @@ def sync_trade_records_from_exchange(conn, force=False):
|
||||
|
||||
# 获取实时价格
|
||||
def get_price(symbol):
|
||||
"""最新价:优先 ccxt 永续 ticker;失败则走 OKX 公开接口(模拟盘无密钥也能显示)."""
|
||||
ex_sym = ""
|
||||
"""最新价:公开 SWAP/现货 ticker 优先(与顶栏同源),再回退 ccxt."""
|
||||
sym = normalize_symbol_input(symbol) or (symbol or "").strip().upper()
|
||||
base = ""
|
||||
if "/" in sym:
|
||||
base = sym.split("/", 1)[0].strip().upper()
|
||||
elif sym:
|
||||
base = sym.split(":", 1)[0].strip().upper()
|
||||
# 1) 与顶栏 BTC/ETH 同一公开接口(模拟盘无密钥也可用)
|
||||
if base in ("BTC", "ETH"):
|
||||
try:
|
||||
ex_sym = normalize_okx_symbol(symbol)
|
||||
ensure_markets_loaded()
|
||||
last = exchange.fetch_ticker(ex_sym).get("last")
|
||||
if last is not None:
|
||||
from lib.market.nav_spot_tickers_lib import _ticker_row
|
||||
|
||||
for inst in (f"{base}-USDT-SWAP", f"{base}-USDT"):
|
||||
row = _ticker_row(exchange, inst)
|
||||
if not row:
|
||||
continue
|
||||
last = _safe_float(row.get("last") or row.get("lastPx") or row.get("markPx"))
|
||||
if last is not None and last > 0:
|
||||
return float(last)
|
||||
except Exception:
|
||||
pass
|
||||
# 2) 其它币种:公开 ticker
|
||||
if base and hasattr(exchange, "public_get_market_ticker"):
|
||||
try:
|
||||
sym = normalize_symbol_input(symbol) or (symbol or "").strip().upper()
|
||||
base = (sym.split("/")[0] if "/" in sym else sym.split(":")[0]).strip().upper()
|
||||
if not base:
|
||||
return None
|
||||
# SWAP 与现货公开 ticker 均可作为关键位现价
|
||||
for inst in (f"{base}-USDT-SWAP", f"{base}-USDT"):
|
||||
if not hasattr(exchange, "public_get_market_ticker"):
|
||||
break
|
||||
rows = (exchange.public_get_market_ticker({"instId": inst}) or {}).get("data") or []
|
||||
if not rows:
|
||||
continue
|
||||
row = rows[0] or {}
|
||||
last = row.get("last") or row.get("lastPx") or row.get("markPx")
|
||||
if last is not None and float(last) > 0:
|
||||
last = _safe_float(row.get("last") or row.get("lastPx") or row.get("markPx"))
|
||||
if last is not None and last > 0:
|
||||
return float(last)
|
||||
except Exception:
|
||||
pass
|
||||
# 3) ccxt 永续
|
||||
try:
|
||||
ensure_markets_loaded()
|
||||
last = exchange.fetch_ticker(normalize_okx_symbol(sym or symbol)).get("last")
|
||||
last = _safe_float(last)
|
||||
if last is not None and last > 0:
|
||||
return float(last)
|
||||
except Exception:
|
||||
pass
|
||||
@@ -6186,8 +6204,14 @@ def api_order_defaults():
|
||||
if direction not in ("long", "short"):
|
||||
direction = "long"
|
||||
exchange_symbol = normalize_okx_symbol(symbol)
|
||||
try:
|
||||
leverage = get_synced_leverage(exchange_symbol, direction) or infer_leverage(symbol)
|
||||
except Exception:
|
||||
leverage = infer_leverage(symbol)
|
||||
try:
|
||||
available = get_available_trading_usdt()
|
||||
except Exception:
|
||||
available = None
|
||||
last_price = get_price(symbol)
|
||||
return jsonify({
|
||||
"ok": True,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/**
|
||||
* 表单币种输入:防抖 + 定时刷新,展示交易所最新价(/api/order_defaults).
|
||||
* BTC/ETH 在 order_defaults 无价时回退 /api/nav_spot_tickers(与顶栏同源).
|
||||
*/
|
||||
(function (global) {
|
||||
"use strict";
|
||||
@@ -65,6 +66,41 @@
|
||||
el.title = "交易所最新价(约 " + pollMs() / 1000 + "s 刷新)";
|
||||
}
|
||||
|
||||
function symbolBase(sym) {
|
||||
return String(sym || "")
|
||||
.trim()
|
||||
.toUpperCase()
|
||||
.split("/")[0]
|
||||
.split(":")[0];
|
||||
}
|
||||
|
||||
function fetchNavLast(sym) {
|
||||
const base = symbolBase(sym);
|
||||
if (base !== "BTC" && base !== "ETH") {
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
return fetch("/api/nav_spot_tickers")
|
||||
.then(function (r) {
|
||||
return r.json().catch(function () {
|
||||
return null;
|
||||
});
|
||||
})
|
||||
.then(function (d) {
|
||||
if (!d || !d.ok || !Array.isArray(d.tickers)) return null;
|
||||
for (let i = 0; i < d.tickers.length; i++) {
|
||||
const t = d.tickers[i] || {};
|
||||
if (String(t.base || "").toUpperCase() === base && t.last != null) {
|
||||
const n = Number(t.last);
|
||||
return Number.isFinite(n) && n > 0 ? n : null;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
})
|
||||
.catch(function () {
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
function bindOne(el) {
|
||||
if (!el || bound.has(el)) return;
|
||||
bound.add(el);
|
||||
@@ -87,6 +123,15 @@
|
||||
pollTimer = setInterval(refresh, pollMs());
|
||||
}
|
||||
|
||||
function applyPrice(sym, px) {
|
||||
if (px === null || typeof px === "undefined") {
|
||||
paint(el, sym, null, "无法读取交易所价格");
|
||||
return;
|
||||
}
|
||||
paint(el, sym, px, "");
|
||||
if (!pollTimer) startPoll();
|
||||
}
|
||||
|
||||
function refresh() {
|
||||
const symEl = $(symId);
|
||||
const sym = symbolValue(symEl);
|
||||
@@ -116,22 +161,36 @@
|
||||
el.classList.remove("symbol-live-price--loading");
|
||||
const data = res.data || {};
|
||||
if (res.status >= 400 || !data || !data.ok) {
|
||||
paint(el, sym, null, (data && data.msg) || "读取失败");
|
||||
return fetchNavLast(sym).then(function (navPx) {
|
||||
if (seq !== fetchSeq) return;
|
||||
if (navPx != null) {
|
||||
applyPrice(sym, navPx);
|
||||
return;
|
||||
}
|
||||
paint(el, sym, null, (data && data.msg) || "读取失败");
|
||||
});
|
||||
}
|
||||
const px = data.last_price != null ? data.last_price : data.price;
|
||||
if (px === null || typeof px === "undefined") {
|
||||
paint(el, data.symbol || sym, null, "无法读取交易所价格");
|
||||
return;
|
||||
return fetchNavLast(sym).then(function (navPx) {
|
||||
if (seq !== fetchSeq) return;
|
||||
applyPrice(data.symbol || sym, navPx);
|
||||
});
|
||||
}
|
||||
paint(el, data.symbol || sym, px, "");
|
||||
if (!pollTimer) startPoll();
|
||||
applyPrice(data.symbol || sym, px);
|
||||
})
|
||||
.catch(function () {
|
||||
if (seq !== fetchSeq) return;
|
||||
el.classList.remove("symbol-live-price--loading");
|
||||
fetchNavLast(sym).then(function (navPx) {
|
||||
if (seq !== fetchSeq) return;
|
||||
if (navPx != null) {
|
||||
applyPrice(sym, navPx);
|
||||
return;
|
||||
}
|
||||
paint(el, sym, null, "网络错误");
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function schedule() {
|
||||
|
||||
@@ -135,7 +135,7 @@ const ORDER_ENTRY_MODEL_CODE_TO_CATEGORY = {{ entry_model_code_to_category | toj
|
||||
</script>
|
||||
<script src="/static/order_entry_model.js?v=5"></script>
|
||||
<script src="/static/manual_order_rr_preview.js?v=5"></script>
|
||||
<script src="/static/symbol_live_price.js?v=2"></script>
|
||||
<script src="/static/symbol_live_price.js?v=3"></script>
|
||||
<script src="/static/key_monitor_form.js?v=2"></script>
|
||||
<script src="/static/instance_stats.js?v=5"></script>
|
||||
{% include 'embed_boot_scripts.html' %}
|
||||
|
||||
@@ -458,7 +458,7 @@ const ORDER_ENTRY_MODEL_CODE_TO_CATEGORY = {{ entry_model_code_to_category | toj
|
||||
</script>
|
||||
<script src="/static/order_entry_model.js?v=5"></script>
|
||||
<script src="/static/manual_order_rr_preview.js?v=5"></script>
|
||||
<script src="/static/symbol_live_price.js?v=2"></script>
|
||||
<script src="/static/symbol_live_price.js?v=3"></script>
|
||||
<script src="/static/strategy_roll.js?v=6"></script>
|
||||
<script src="/static/instance_stats.js?v=5"></script>
|
||||
<script>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<script src="/static/instance_theme.js?v=5"></script>
|
||||
<title>{{ exchange_display }} | 关键位放大</title>
|
||||
<link rel="stylesheet" href="/static/instance_theme.css?v=50">
|
||||
<script src="/static/symbol_live_price.js?v=2"></script>
|
||||
<script src="/static/symbol_live_price.js?v=3"></script>
|
||||
<link rel="stylesheet" href="/static/focus_chart_page.css?v=1">
|
||||
</head>
|
||||
<body class="focus-page" data-price-refresh-ms="{{ price_refresh_seconds * 1000 }}">
|
||||
|
||||
Reference in New Issue
Block a user