修复趋势回调止盈误显与行情区成交量被裁切的问题
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -166,7 +166,7 @@ def _okx_normalize_orders(raw: dict, channel: str) -> list[dict[str, Any]]:
|
||||
info = {}
|
||||
sl_trig = _coerce_float(info.get("slTriggerPx"), raw.get("stopLossPrice"))
|
||||
tp_trig = _coerce_float(info.get("tpTriggerPx"), raw.get("takeProfitPrice"))
|
||||
if sl_trig is None or tp_trig is None:
|
||||
if sl_trig is None or tp_trig is None or sl_trig == tp_trig:
|
||||
return [n]
|
||||
base_id = n["id"]
|
||||
rows: list[dict[str, Any]] = []
|
||||
|
||||
@@ -1969,14 +1969,19 @@ body.login-page {
|
||||
.market-chart-wrap {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: min(72vh, 640px);
|
||||
min-height: 360px;
|
||||
height: min(76vh, 680px);
|
||||
min-height: 380px;
|
||||
border: 1px solid var(--border-soft);
|
||||
border-radius: var(--radius);
|
||||
background: #0a1018;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.market-chart-wrap.has-pos-panel {
|
||||
height: min(80vh, 740px);
|
||||
min-height: 440px;
|
||||
}
|
||||
|
||||
.market-ohlcv-bar {
|
||||
flex: 0 0 auto;
|
||||
padding: 8px 12px;
|
||||
@@ -2147,6 +2152,11 @@ body.login-page {
|
||||
font-size: 0.68rem;
|
||||
}
|
||||
|
||||
.market-pos-tp-monitored {
|
||||
color: #8fc8ff;
|
||||
font-size: 0.72rem;
|
||||
}
|
||||
|
||||
.sym-link {
|
||||
background: none;
|
||||
border: none;
|
||||
|
||||
@@ -506,14 +506,146 @@
|
||||
return (row && (row.key || row.id)) || exchangeId;
|
||||
}
|
||||
|
||||
function buildPositionMarketContext(pos, monitorOrder) {
|
||||
function findTrendPlan(trends, symbol, side) {
|
||||
const want = (side || "").toLowerCase();
|
||||
for (const t of trends || []) {
|
||||
const sym = t.symbol || t.exchange_symbol || "";
|
||||
if (!symbolsMatchHub(sym, symbol)) continue;
|
||||
const d = (t.direction || "").toLowerCase();
|
||||
if (!d || d === want) return t;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function inferTpslFromCondOrders(side, cond, entry) {
|
||||
const picked = pickExTpslOrders(cond);
|
||||
let sl = picked.sl && picked.sl.trigger_price != null ? picked.sl.trigger_price : "";
|
||||
let tp = picked.tp && picked.tp.trigger_price != null ? picked.tp.trigger_price : "";
|
||||
if (sl !== "" && tp !== "" && Number(sl) !== Number(tp)) {
|
||||
return { sl, tp };
|
||||
}
|
||||
|
||||
const triggers = (cond || [])
|
||||
.map(function (o) {
|
||||
return { price: Number(o.trigger_price), label: o.label || "" };
|
||||
})
|
||||
.filter(function (o) {
|
||||
return o.price != null && !Number.isNaN(o.price) && o.price > 0;
|
||||
});
|
||||
if (!triggers.length) return { sl: sl || "", tp: tp || "" };
|
||||
|
||||
const s = (side || "long").toLowerCase();
|
||||
const e = entry != null && Number.isFinite(Number(entry)) ? Number(entry) : null;
|
||||
|
||||
if (e != null) {
|
||||
const below = triggers.filter(function (t) {
|
||||
return t.price < e;
|
||||
});
|
||||
const above = triggers.filter(function (t) {
|
||||
return t.price > e;
|
||||
});
|
||||
if (s === "long") {
|
||||
if (sl === "" && below.length) {
|
||||
sl = Math.max.apply(
|
||||
null,
|
||||
below.map(function (t) {
|
||||
return t.price;
|
||||
})
|
||||
);
|
||||
}
|
||||
if (tp === "" && above.length) {
|
||||
tp = Math.min.apply(
|
||||
null,
|
||||
above.map(function (t) {
|
||||
return t.price;
|
||||
})
|
||||
);
|
||||
}
|
||||
} else {
|
||||
if (sl === "" && above.length) {
|
||||
sl = Math.min.apply(
|
||||
null,
|
||||
above.map(function (t) {
|
||||
return t.price;
|
||||
})
|
||||
);
|
||||
}
|
||||
if (tp === "" && below.length) {
|
||||
tp = Math.max.apply(
|
||||
null,
|
||||
below.map(function (t) {
|
||||
return t.price;
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (triggers.length === 1 && sl === "" && tp === "") {
|
||||
const one = triggers[0];
|
||||
const p = one.price;
|
||||
const lbl = one.label;
|
||||
if (e != null) {
|
||||
if (s === "long") {
|
||||
if (p < e) sl = p;
|
||||
else if (p > e) tp = p;
|
||||
} else if (p > e) sl = p;
|
||||
else if (p < e) tp = p;
|
||||
} else if (/止损/.test(lbl)) sl = p;
|
||||
else if (/止盈/.test(lbl) && !/止盈止损/.test(lbl)) tp = p;
|
||||
}
|
||||
|
||||
if (sl !== "" && tp !== "" && Number(sl) === Number(tp)) tp = "";
|
||||
return { sl: sl || "", tp: tp || "" };
|
||||
}
|
||||
|
||||
function resolvePositionTpsl(pos, monitorOrder, trendPlan) {
|
||||
const mo = monitorOrder || {};
|
||||
const tp = trendPlan || {};
|
||||
const cond = condOrdersFromPosition(pos);
|
||||
const entryRaw =
|
||||
pos.entry_price != null
|
||||
? pos.entry_price
|
||||
: mo.trigger_price != null
|
||||
? mo.trigger_price
|
||||
: tp.avg_entry_price;
|
||||
const entryN = entryRaw != null && entryRaw !== "" ? Number(entryRaw) : null;
|
||||
const isTrend =
|
||||
!!(trendPlan && trendPlan.id) || String(mo.monitor_type || "").trim() === "趋势回调";
|
||||
|
||||
let sl = mo.stop_loss != null && mo.stop_loss !== "" ? mo.stop_loss : "";
|
||||
let takeProfit = mo.take_profit != null && mo.take_profit !== "" ? mo.take_profit : "";
|
||||
let tpMonitored = false;
|
||||
|
||||
if (isTrend) {
|
||||
tpMonitored = true;
|
||||
takeProfit = "";
|
||||
if (trendPlan && trendPlan.stop_loss != null && trendPlan.stop_loss !== "") {
|
||||
sl = trendPlan.stop_loss;
|
||||
}
|
||||
}
|
||||
|
||||
const inferred = inferTpslFromCondOrders(pos.side, cond, entryN);
|
||||
if (sl === "" || sl == null) sl = inferred.sl;
|
||||
if (!tpMonitored && (takeProfit === "" || takeProfit == null)) takeProfit = inferred.tp;
|
||||
|
||||
if (sl !== "" && takeProfit !== "" && Number(sl) === Number(takeProfit)) {
|
||||
takeProfit = "";
|
||||
}
|
||||
|
||||
return {
|
||||
entry: entryRaw,
|
||||
sl,
|
||||
tp: takeProfit,
|
||||
tp_monitored: tpMonitored,
|
||||
is_trend: isTrend,
|
||||
};
|
||||
}
|
||||
|
||||
function buildPositionMarketContext(pos, monitorOrder, trendPlan) {
|
||||
const tpsl = resolvePositionTpsl(pos, monitorOrder, trendPlan);
|
||||
const cond = condOrdersFromPosition(pos);
|
||||
const reg = Array.isArray(pos.regular_orders) ? pos.regular_orders : [];
|
||||
const guess = guessTpslFromCondOrders(pos.side, cond);
|
||||
const entry = pos.entry_price != null ? pos.entry_price : mo.trigger_price;
|
||||
const sl = mo.stop_loss != null ? mo.stop_loss : guess.sl;
|
||||
const tp = mo.take_profit != null ? mo.take_profit : guess.tp;
|
||||
const num = function (v) {
|
||||
if (v == null || v === "") return null;
|
||||
const n = Number(v);
|
||||
@@ -538,9 +670,11 @@
|
||||
});
|
||||
return {
|
||||
side: (pos.side || "long").toLowerCase(),
|
||||
entry: num(entry),
|
||||
stop_loss: num(sl),
|
||||
take_profit: num(tp),
|
||||
entry: num(tpsl.entry),
|
||||
stop_loss: num(tpsl.sl),
|
||||
take_profit: num(tpsl.tp),
|
||||
tp_monitored: !!tpsl.tp_monitored,
|
||||
is_trend: !!tpsl.is_trend,
|
||||
contracts: num(pos.contracts),
|
||||
orders: orders,
|
||||
};
|
||||
@@ -565,10 +699,13 @@
|
||||
}
|
||||
}
|
||||
|
||||
function marketOpenBtnAttrs(exchangeId, exchangeKey, symbol, pos, monitorOrder) {
|
||||
function marketOpenBtnAttrs(exchangeId, exchangeKey, symbol, pos, monitorOrder, trendPlan) {
|
||||
const symAttr = esc(symbol || "").replace(/"/g, """);
|
||||
const exKeyAttr = esc(exchangeKey || exchangeId || "").replace(/"/g, """);
|
||||
const ctxEnc = esc(encodePosCtx(buildPositionMarketContext(pos, monitorOrder))).replace(/"/g, """);
|
||||
const ctxEnc = esc(encodePosCtx(buildPositionMarketContext(pos, monitorOrder, trendPlan))).replace(
|
||||
/"/g,
|
||||
"""
|
||||
);
|
||||
return (
|
||||
'data-ex-id="' +
|
||||
esc(exchangeId) +
|
||||
@@ -706,18 +843,8 @@
|
||||
return `<table class="data-table data-table-sub"><thead><tr><th>类型</th><th>数量</th><th>触发/价格</th><th>操作</th></tr></thead><tbody>${rows}</tbody></table>`;
|
||||
}
|
||||
|
||||
function guessTpslFromCondOrders(side, cond) {
|
||||
const triggers = (cond || [])
|
||||
.map((o) => o.trigger_price)
|
||||
.filter((v) => v != null && !Number.isNaN(Number(v)))
|
||||
.map(Number);
|
||||
if (!triggers.length) return { sl: "", tp: "" };
|
||||
triggers.sort((a, b) => a - b);
|
||||
const s = (side || "long").toLowerCase();
|
||||
if (s === "short") {
|
||||
return { sl: triggers[triggers.length - 1], tp: triggers[0] };
|
||||
}
|
||||
return { sl: triggers[0], tp: triggers[triggers.length - 1] };
|
||||
function guessTpslFromCondOrders(side, cond, entry) {
|
||||
return inferTpslFromCondOrders(side, cond, entry);
|
||||
}
|
||||
|
||||
function renderOrdersCollapse(exchangeId, symbol, cond, reg) {
|
||||
@@ -786,7 +913,7 @@
|
||||
return row("止损", sl) + row("止盈", tp);
|
||||
}
|
||||
|
||||
function renderLivePositionCard(exchangeId, exchangeKey, pos, monitorOrder) {
|
||||
function renderLivePositionCard(exchangeId, exchangeKey, pos, monitorOrder, trendPlan) {
|
||||
const symbol = pos.symbol || "";
|
||||
const exKeyAttr = esc(exchangeKey || exchangeId || "").replace(/"/g, """);
|
||||
const side = (pos.side || "long").toLowerCase();
|
||||
@@ -795,16 +922,17 @@
|
||||
const mo = monitorOrder || {};
|
||||
const cond = condOrdersFromPosition(pos);
|
||||
const reg = Array.isArray(pos.regular_orders) ? pos.regular_orders : [];
|
||||
const guess = guessTpslFromCondOrders(side, cond);
|
||||
const tpsl = resolvePositionTpsl(pos, mo, trendPlan);
|
||||
const symAttr = esc(symbol).replace(/"/g, """);
|
||||
const sideAttr = esc(side).replace(/"/g, """);
|
||||
const contractsAttr = esc(String(pos.contracts != null ? pos.contracts : "")).replace(/"/g, """);
|
||||
const slAttr = esc(String(mo.stop_loss != null ? mo.stop_loss : guess.sl)).replace(/"/g, """);
|
||||
const tpAttr = esc(String(mo.take_profit != null ? mo.take_profit : guess.tp)).replace(/"/g, """);
|
||||
const entry = pos.entry_price != null ? pos.entry_price : mo.trigger_price;
|
||||
const sl = mo.stop_loss != null ? mo.stop_loss : guess.sl;
|
||||
const tp = mo.take_profit != null ? mo.take_profit : guess.tp;
|
||||
const rr = calcRrRatio(side, entry, sl, tp);
|
||||
const slAttr = esc(String(tpsl.sl)).replace(/"/g, """);
|
||||
const tpAttr = esc(String(tpsl.tp)).replace(/"/g, """);
|
||||
const entry = tpsl.entry;
|
||||
const sl = tpsl.sl;
|
||||
const tp = tpsl.tp;
|
||||
const tpMonitored = tpsl.tp_monitored;
|
||||
const rr = tpMonitored ? null : calcRrRatio(side, entry, sl, tp);
|
||||
const upnl = pos.unrealized_pnl;
|
||||
let pnlText = fmt(upnl, 2) + "U";
|
||||
if (pos.notional_usdt && upnl != null && Math.abs(Number(pos.notional_usdt)) > 1e-8) {
|
||||
@@ -828,7 +956,7 @@
|
||||
meta.push(
|
||||
`<span class="${beOn ? "pos-meta-on" : "pos-meta-off"}">移动保本:${beOn ? "开" : "关"}</span>`
|
||||
);
|
||||
const mktAttrs = marketOpenBtnAttrs(exchangeId, exchangeKey, symbol, pos, monitorOrder);
|
||||
const mktAttrs = marketOpenBtnAttrs(exchangeId, exchangeKey, symbol, pos, monitorOrder, trendPlan);
|
||||
return `<div class="pos-card hub-pos-card">
|
||||
<div class="pos-card-head">
|
||||
<div class="pos-card-symbol">
|
||||
@@ -844,8 +972,8 @@
|
||||
<div class="pos-grid">
|
||||
<div class="pos-cell"><span class="pos-label">成交价</span><span class="pos-value">${entry != null ? fmt(entry, 4) : "—"}</span></div>
|
||||
<div class="pos-cell"><span class="pos-label">止损</span><span class="pos-value">${sl != null && sl !== "" ? fmt(sl, 4) : "—"}</span></div>
|
||||
<div class="pos-cell"><span class="pos-label">止盈</span><span class="pos-value">${tp != null && tp !== "" ? fmt(tp, 4) : "—"}</span></div>
|
||||
<div class="pos-cell"><span class="pos-label">盈亏比</span><span class="pos-value">${rr != null ? fmt(rr, 2) + ":1" : "-:1"}</span></div>
|
||||
<div class="pos-cell"><span class="pos-label">止盈</span><span class="pos-value">${tpMonitored ? "程序监控" : tp != null && tp !== "" ? fmt(tp, 4) : "—"}</span></div>
|
||||
<div class="pos-cell"><span class="pos-label">盈亏比</span><span class="pos-value">${tpMonitored ? "—" : rr != null ? fmt(rr, 2) + ":1" : "-:1"}</span></div>
|
||||
<div class="pos-cell"><span class="pos-label">张数</span><span class="pos-value">${fmt(pos.contracts, 4)}</span></div>
|
||||
<div class="pos-cell"><span class="pos-label">浮盈亏</span><span class="pos-value ${pnlCls(upnl)}">${pnlText}</span></div>
|
||||
</div>
|
||||
@@ -933,17 +1061,17 @@
|
||||
.join("");
|
||||
}
|
||||
|
||||
function renderPositionBlock(exchangeId, exchangeKey, x, monitorOrder) {
|
||||
function renderPositionBlock(exchangeId, exchangeKey, x, monitorOrder, trendPlan) {
|
||||
const symAttr = esc(x.symbol || "").replace(/"/g, """);
|
||||
const exKeyAttr = esc(exchangeKey || exchangeId || "").replace(/"/g, """);
|
||||
const sideAttr = esc((x.side || "").toLowerCase()).replace(/"/g, """);
|
||||
const contractsAttr = esc(String(x.contracts != null ? x.contracts : "")).replace(/"/g, """);
|
||||
const cond = condOrdersFromPosition(x);
|
||||
const reg = Array.isArray(x.regular_orders) ? x.regular_orders : [];
|
||||
const guess = guessTpslFromCondOrders(x.side, cond);
|
||||
const slAttr = esc(String(guess.sl)).replace(/"/g, """);
|
||||
const tpAttr = esc(String(guess.tp)).replace(/"/g, """);
|
||||
const mktAttrs = marketOpenBtnAttrs(exchangeId, exchangeKey, x.symbol, x, monitorOrder);
|
||||
const tpsl = resolvePositionTpsl(x, monitorOrder, trendPlan);
|
||||
const slAttr = esc(String(tpsl.sl)).replace(/"/g, """);
|
||||
const tpAttr = esc(String(tpsl.tp)).replace(/"/g, """);
|
||||
const mktAttrs = marketOpenBtnAttrs(exchangeId, exchangeKey, x.symbol, x, monitorOrder, trendPlan);
|
||||
return `<div class="pos-block">
|
||||
<div class="table-scroll">
|
||||
<table class="data-table"><thead><tr><th>合约</th><th>方向</th><th>张数</th><th>浮盈</th><th>操作</th></tr></thead><tbody>
|
||||
@@ -972,7 +1100,17 @@
|
||||
</div>`;
|
||||
inner += `<div class="section-title">交易所持仓 · ${pos.length} 仓</div>`;
|
||||
if (pos.length) {
|
||||
inner += pos.map((p) => renderPositionBlock(row.id, row.key || row.id, p, findMonitorOrder(orders, p.symbol, p.side))).join("");
|
||||
inner += pos
|
||||
.map((p) =>
|
||||
renderPositionBlock(
|
||||
row.id,
|
||||
row.key || row.id,
|
||||
p,
|
||||
findMonitorOrder(orders, p.symbol, p.side),
|
||||
findTrendPlan(trends, p.symbol, p.side)
|
||||
)
|
||||
)
|
||||
.join("");
|
||||
} else {
|
||||
inner += '<div class="empty-hint">无持仓</div>';
|
||||
}
|
||||
@@ -1065,7 +1203,13 @@
|
||||
html += `<div class="hub-pos-list ${posListCls}" data-pos-count="${posCount}">`;
|
||||
if (posCount) {
|
||||
pos.forEach((p) => {
|
||||
html += renderLivePositionCard(row.id, row.key || row.id, p, findMonitorOrder(orders, p.symbol, p.side));
|
||||
html += renderLivePositionCard(
|
||||
row.id,
|
||||
row.key || row.id,
|
||||
p,
|
||||
findMonitorOrder(orders, p.symbol, p.side),
|
||||
findTrendPlan(trends, p.symbol, p.side)
|
||||
);
|
||||
});
|
||||
} else {
|
||||
html += '<div class="pos-empty">暂无持仓</div>';
|
||||
|
||||
@@ -5,6 +5,9 @@
|
||||
const AUTO_REFRESH_MS = 5000;
|
||||
const DEFAULT_VISIBLE_BARS = 200;
|
||||
const RIGHT_OFFSET_BARS = 10;
|
||||
const CANDLE_SCALE_BOTTOM = 0.26;
|
||||
const VOLUME_SCALE_TOP = 0.73;
|
||||
const VOLUME_SCALE_BOTTOM = 0.06;
|
||||
const TF_MS = {
|
||||
"1m": 60_000,
|
||||
"5m": 5 * 60_000,
|
||||
@@ -111,6 +114,30 @@
|
||||
if (el) el.textContent = "—";
|
||||
});
|
||||
if (elPosOrders) elPosOrders.innerHTML = "";
|
||||
syncChartWrapLayout();
|
||||
}
|
||||
|
||||
function resizeChart() {
|
||||
if (!chart || !chartHost) return;
|
||||
chart.applyOptions({ width: chartHost.clientWidth, height: chartHost.clientHeight });
|
||||
updatePriceTag();
|
||||
}
|
||||
|
||||
let resizeChartRaf = 0;
|
||||
function scheduleChartResize() {
|
||||
if (resizeChartRaf) cancelAnimationFrame(resizeChartRaf);
|
||||
resizeChartRaf = requestAnimationFrame(function () {
|
||||
resizeChartRaf = 0;
|
||||
syncChartWrapLayout();
|
||||
});
|
||||
}
|
||||
|
||||
function syncChartWrapLayout() {
|
||||
const wrap = chartHost && chartHost.closest(".market-chart-wrap");
|
||||
if (wrap && elPosPanel) {
|
||||
wrap.classList.toggle("has-pos-panel", !elPosPanel.classList.contains("hidden"));
|
||||
}
|
||||
resizeChart();
|
||||
}
|
||||
|
||||
function renderPosPanel(ctx) {
|
||||
@@ -126,7 +153,15 @@
|
||||
}
|
||||
if (elPosEntry) elPosEntry.textContent = ctx.entry != null ? fmtPrice(ctx.entry) : "—";
|
||||
if (elPosSl) elPosSl.textContent = ctx.stop_loss != null ? fmtPrice(ctx.stop_loss) : "—";
|
||||
if (elPosTp) elPosTp.textContent = ctx.take_profit != null ? fmtPrice(ctx.take_profit) : "—";
|
||||
if (elPosTp) {
|
||||
if (ctx.tp_monitored) {
|
||||
elPosTp.textContent = "程序监控";
|
||||
elPosTp.classList.add("market-pos-tp-monitored");
|
||||
} else {
|
||||
elPosTp.textContent = ctx.take_profit != null ? fmtPrice(ctx.take_profit) : "—";
|
||||
elPosTp.classList.remove("market-pos-tp-monitored");
|
||||
}
|
||||
}
|
||||
if (elPosSize) elPosSize.textContent = ctx.contracts != null ? String(ctx.contracts) : "—";
|
||||
if (elPosOrders) {
|
||||
const orders = Array.isArray(ctx.orders) ? ctx.orders : [];
|
||||
@@ -155,6 +190,7 @@
|
||||
.join("");
|
||||
}
|
||||
}
|
||||
scheduleChartResize();
|
||||
}
|
||||
|
||||
function clearPositionLines() {
|
||||
@@ -172,8 +208,10 @@
|
||||
const specs = [
|
||||
{ price: posContext.entry, color: "#5b9cf5", title: "入场" },
|
||||
{ price: posContext.stop_loss, color: "#ff4d6d", title: "止损" },
|
||||
{ price: posContext.take_profit, color: "#00ff9d", title: "止盈" },
|
||||
];
|
||||
if (!posContext.tp_monitored && posContext.take_profit != null) {
|
||||
specs.push({ price: posContext.take_profit, color: "#00ff9d", title: "止盈" });
|
||||
}
|
||||
specs.forEach(function (s) {
|
||||
if (s.price == null || !Number.isFinite(Number(s.price))) return;
|
||||
positionLines.push(
|
||||
@@ -496,10 +534,10 @@
|
||||
if (!volumeSeries) return false;
|
||||
|
||||
chart.priceScale("right").applyOptions({
|
||||
scaleMargins: { top: 0.06, bottom: 0.28 },
|
||||
scaleMargins: { top: 0.06, bottom: CANDLE_SCALE_BOTTOM },
|
||||
});
|
||||
chart.priceScale("volume").applyOptions({
|
||||
scaleMargins: { top: 0.78, bottom: 0 },
|
||||
scaleMargins: { top: VOLUME_SCALE_TOP, bottom: VOLUME_SCALE_BOTTOM },
|
||||
});
|
||||
applyPriceAutoScale();
|
||||
|
||||
@@ -522,11 +560,9 @@
|
||||
});
|
||||
|
||||
window.addEventListener("resize", function () {
|
||||
if (!chart) return;
|
||||
chart.applyOptions({ width: chartHost.clientWidth, height: chartHost.clientHeight });
|
||||
updatePriceTag();
|
||||
scheduleChartResize();
|
||||
});
|
||||
chart.applyOptions({ width: chartHost.clientWidth, height: chartHost.clientHeight });
|
||||
scheduleChartResize();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -712,6 +748,7 @@
|
||||
updateVisibleRangeMarkers();
|
||||
syncPosContextForView(exKey, sym);
|
||||
showLatestOhlcv();
|
||||
scheduleChartResize();
|
||||
|
||||
const limit = data.limit || lastCandles.length;
|
||||
let hint =
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600&family=Orbitron:wght@500;600;700&display=swap" rel="stylesheet" media="print" onload="this.media='all'" />
|
||||
<noscript><link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600&family=Orbitron:wght@500;600;700&display=swap" rel="stylesheet" /></noscript>
|
||||
<link rel="stylesheet" href="/assets/app.css?v=20260528-hub-pos-market2" />
|
||||
<link rel="stylesheet" href="/assets/app.css?v=20260528-hub-vol-fix" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="app-bg" aria-hidden="true"></div>
|
||||
@@ -204,7 +204,7 @@
|
||||
|
||||
<div id="toast"></div>
|
||||
<script src="https://unpkg.com/lightweight-charts@4.2.0/dist/lightweight-charts.standalone.production.js"></script>
|
||||
<script src="/assets/chart.js?v=20260528-hub-pos-market2"></script>
|
||||
<script src="/assets/app.js?v=20260528-hub-pos-market2"></script>
|
||||
<script src="/assets/chart.js?v=20260528-hub-vol-fix"></script>
|
||||
<script src="/assets/app.js?v=20260528-hub-tpsl-fix"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user