关键位箱体突破调整
This commit is contained in:
@@ -150,11 +150,11 @@
|
||||
.pos-side-badge{padding:3px 8px;border-radius:6px;font-size:.72rem;font-weight:500;line-height:1.2}
|
||||
.pos-side-long{background:#253a6e;color:#6eb5ff}
|
||||
.pos-side-short{background:#4a2230;color:#ff8a8a}
|
||||
.pos-close-btn{padding:6px 14px;background:#c45454;color:#fff;border-radius:8px;text-decoration:none;font-size:.82rem;font-weight:500;flex-shrink:0;white-space:nowrap}
|
||||
.pos-close-btn:hover{background:#d66565;color:#fff}
|
||||
.pos-head-actions{display:flex;align-items:center;gap:6px;flex-shrink:0}
|
||||
.pos-entrust-btn{padding:6px 12px;background:#2a4a7a;color:#8fc8ff;border:none;border-radius:8px;font-size:.82rem;font-weight:500;cursor:pointer;white-space:nowrap}
|
||||
.pos-entrust-btn:hover{background:#355d96}
|
||||
.pos-close-btn{padding:6px 14px;background:#c45454;color:#fff;border-radius:8px;text-decoration:none;font-size:.82rem;font-weight:500;flex-shrink:0;white-space:nowrap;border:none;cursor:pointer;display:inline-block}
|
||||
.pos-close-btn:hover{background:#d66565;color:#fff}
|
||||
.pos-ex-orders{margin-top:10px;padding-top:10px;border-top:1px dashed #2a3348}
|
||||
.pos-ex-orders-title{font-size:.74rem;color:#7d8799;margin-bottom:6px}
|
||||
.pos-ex-order-row{display:flex;align-items:center;justify-content:space-between;gap:8px;font-size:.78rem;color:#c5cce0;margin-top:5px}
|
||||
@@ -199,14 +199,14 @@
|
||||
<div class="stat-item"><div class="label">开单次数</div><div class="value">{{ s.opens_count }}</div></div>
|
||||
<div class="stat-item"><div class="label">平仓笔数</div><div class="value">{{ s.closed_count }}</div></div>
|
||||
<div class="stat-item"><div class="label">胜率</div><div class="value">{% if s.win_rate_pct is not none %}{{ s.win_rate_pct }}%{% else %}-{% endif %}</div></div>
|
||||
<div class="stat-item"><div class="label">净盈亏(U)</div><div class="value">{{ signed_usdt_fmt(s.net_pnl_u) }}</div></div>
|
||||
<div class="stat-item"><div class="label">亏损额合计(U)</div><div class="value">{{ usdt_fmt(s.loss_sum_u) }}</div></div>
|
||||
<div class="stat-item"><div class="label">单笔最大亏损(U)</div><div class="value">{% if s.max_single_loss is not none %}{{ signed_usdt_fmt(s.max_single_loss) }}{% else %}-{% endif %}</div></div>
|
||||
<div class="stat-item"><div class="label">单笔最大盈利(U)</div><div class="value">{% if s.max_single_profit is not none %}{{ usdt_fmt(s.max_single_profit) }}{% else %}-{% endif %}</div></div>
|
||||
<div class="stat-item"><div class="label">最大回撤(U)</div><div class="value">{{ usdt_fmt(s.max_drawdown_u) }}</div></div>
|
||||
<div class="stat-item"><div class="label">净盈亏(U)</div><div class="value">{{ funds_fmt(s.net_pnl_u) }}</div></div>
|
||||
<div class="stat-item"><div class="label">亏损额合计(U)</div><div class="value">{{ funds_fmt(s.loss_sum_u) }}</div></div>
|
||||
<div class="stat-item"><div class="label">单笔最大亏损(U)</div><div class="value">{% if s.max_single_loss is not none %}{{ funds_fmt(s.max_single_loss) }}{% else %}-{% endif %}</div></div>
|
||||
<div class="stat-item"><div class="label">单笔最大盈利(U)</div><div class="value">{% if s.max_single_profit is not none %}{{ funds_fmt(s.max_single_profit) }}{% else %}-{% endif %}</div></div>
|
||||
<div class="stat-item"><div class="label">最大回撤(U)</div><div class="value">{{ funds_fmt(s.max_drawdown_u) }}</div></div>
|
||||
<div class="stat-item"><div class="label">当前连续亏损笔数</div><div class="value">{{ s.consecutive_losses }}</div></div>
|
||||
<div class="stat-item"><div class="label">最长连续亏损(交易日)</div><div class="value">{{ s.max_loss_streak_days }} 天</div></div>
|
||||
<div class="stat-item"><div class="label">期内最大亏损日</div><div class="value">{% if s.worst_day %}{{ s.worst_day }}({{ signed_usdt_fmt(s.worst_day_pnl) }}U){% else %}-{% endif %}</div></div>
|
||||
<div class="stat-item"><div class="label">期内最大亏损日</div><div class="value">{% if s.worst_day %}{{ s.worst_day }}({{ funds_fmt(s.worst_day_pnl) }}U){% else %}-{% endif %}</div></div>
|
||||
</div>
|
||||
</div>
|
||||
{% endmacro %}
|
||||
@@ -253,9 +253,9 @@
|
||||
<div class="stat-item"><div class="label">总交易</div><div class="value">{{ total }}</div></div>
|
||||
<div class="stat-item"><div class="label">错过次数</div><div class="value">{{ miss_count }}</div></div>
|
||||
<div class="stat-item"><div class="label">胜率</div><div class="value">{{ rate }}%</div></div>
|
||||
<div class="stat-item"><div class="label">资金账户(USDT)</div><div class="value" id="total-capital">{% if funding_usdt is not none %}{{ usdt_fmt(funding_usdt) }}U{% else %}—{% endif %}</div></div>
|
||||
<div class="stat-item"><div class="label">资金账户(USDT)</div><div class="value" id="total-capital">{% if funding_usdt is not none %}{{ funds_fmt(funding_usdt) }}U{% else %}—{% endif %}</div></div>
|
||||
<div class="stat-item"><div class="label">交易日</div><div class="value">{{ trading_day }}</div></div>
|
||||
<div class="stat-item"><div class="label">当日资金(交易账户)</div><div class="value" id="current-capital">{{ usdt_fmt(current_capital) }}U</div></div>
|
||||
<div class="stat-item"><div class="label">当日资金(交易账户)</div><div class="value" id="current-capital">{{ funds_fmt(current_capital) }}U</div></div>
|
||||
</div>
|
||||
<div class="rule-tip">实时价格更新时间:<span id="price-last-updated">--</span>(北京时间 UTC+8)</div>
|
||||
|
||||
@@ -281,7 +281,7 @@
|
||||
<option value="关键阻力位">关键阻力位</option>
|
||||
<option value="关键支撑位">关键支撑位</option>
|
||||
</select>
|
||||
<select name="direction" required>
|
||||
<select name="direction" id="key-direction" required>
|
||||
<option value="">方向</option><option value="long">做多</option><option value="short">做空</option>
|
||||
</select>
|
||||
<input name="upper" step="0.0001" placeholder="上沿/阻力" required>
|
||||
@@ -304,7 +304,11 @@
|
||||
<div class="pos-card-head">
|
||||
<div class="pos-card-symbol">
|
||||
<strong>{{ k.symbol }}</strong>
|
||||
{% if k.direction == 'watch' %}
|
||||
<span class="pos-side-badge" style="background:#2a3152;color:#9ab">双向</span>
|
||||
{% else %}
|
||||
<span class="pos-side-badge {{ 'pos-side-long' if k.direction == 'long' else 'pos-side-short' }}">{{ '做多' if k.direction == 'long' else '做空' }}</span>
|
||||
{% endif %}
|
||||
<span class="badge direction" style="margin-left:4px">{{ k.monitor_type }}</span>
|
||||
</div>
|
||||
<button type="button" class="pos-close-btn" style="border:none;cursor:pointer" onclick="deleteKeyMonitor({{ k.id }})">删</button>
|
||||
@@ -444,13 +448,13 @@
|
||||
</div>
|
||||
<div class="pos-head-actions">
|
||||
<button type="button" class="pos-entrust-btn" onclick="openTpslEntrustModal({{ o.id }})">委托</button>
|
||||
<a href="/del_order/{{ o.id }}" class="pos-close-btn" onclick="return confirm('删除会触发手动平仓,继续?')">平仓</a>
|
||||
<a href="/del_order/{{ o.id }}" class="pos-close-btn" onclick="return confirm('删除会触发手动平仓,继续?')">平仓</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pos-meta">
|
||||
<span class="pos-meta-item">来源: {{ o.monitor_type|default('下单监控', true) }}{% if o.key_signal_type %} · {{ o.key_signal_type }}{% endif %}</span>
|
||||
<span class="pos-meta-item">风格: {{ o.trade_style or 'trend' }}</span>
|
||||
<span class="pos-meta-item">风险: {{ o.risk_percent or '-' }}%≈{% if o.risk_amount is not none %}{{ usdt_fmt(o.risk_amount) }}{% else %}-{% endif %}U</span>
|
||||
<span class="pos-meta-item">风险: {{ o.risk_percent or '-' }}%≈{{ funds_fmt(o.risk_amount) if o.risk_amount is not none else '-' }}U</span>
|
||||
<span class="pos-meta-item {% if o.breakeven_enabled %}pos-meta-on{% else %}pos-meta-off{% endif %}">
|
||||
{% if o.breakeven_enabled %}移动保本:开 {{ o.breakeven_rr_trigger or '-' }}R→{{ price_fmt(o.symbol, o.breakeven_price) }}{% else %}移动保本:关{% endif %}
|
||||
</span>
|
||||
@@ -491,7 +495,7 @@
|
||||
</div>
|
||||
<div class="pos-footer">
|
||||
<span>保证金: <span id="order-ex-margin-{{ o.id }}">-</span></span>
|
||||
<span>计划基数: {% if o.margin_capital is not none %}{{ usdt_fmt(o.margin_capital) }}{% else %}-{% endif %}U</span>
|
||||
<span>计划基数: {{ funds_fmt(o.margin_capital) if o.margin_capital is not none else '-' }}U</span>
|
||||
<span>杠杆: {{ o.leverage or '-' }}x</span>
|
||||
<span>仓位占比: {{ o.position_ratio if o.position_ratio is not none else '-' }}%</span>
|
||||
</div>
|
||||
@@ -548,16 +552,6 @@
|
||||
{% if page == 'records' %}
|
||||
<div class="card full records-card">
|
||||
<h2>交易记录 & 错过机会</h2>
|
||||
<div class="rule-tip" style="margin-bottom:8px;font-size:.78rem">
|
||||
盈亏U:<span style="color:#6ab88a">所</span>=交易所平仓历史,
|
||||
<span style="color:#8892b0">估</span>=本地估算。
|
||||
{% if exchange_pnl_sync %}
|
||||
{% if exchange_pnl_sync.skipped %}(25秒内已同步,可点右侧按钮强制){% else %}
|
||||
本轮:平仓历史 {{ exchange_pnl_sync.hist_count or 0 }} 条,对齐 {{ exchange_pnl_sync.matched or 0 }} 笔{% if exchange_pnl_sync.reason %} — {{ exchange_pnl_sync.reason }}{% endif %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
<button type="button" id="sync-exchange-pnl-btn" style="margin-left:8px;padding:4px 10px;background:#1f3a5a;color:#8fc8ff;border:none;border-radius:6px;cursor:pointer">立即同步</button>
|
||||
</div>
|
||||
<div class="form-row" style="margin-bottom:10px;gap:8px">
|
||||
<label style="display:flex;align-items:center;gap:6px;font-size:.82rem;color:#cfd3ef">
|
||||
<input id="review-mode-toggle" type="checkbox">
|
||||
@@ -578,13 +572,13 @@
|
||||
{% set tp_show = r.effective_take_profit or r.take_profit %}
|
||||
<td>{{ price_fmt(r.symbol, stop_show) }}</td>
|
||||
<td>{{ price_fmt(r.symbol, tp_show) }}</td>
|
||||
<td>{% if r.margin_capital is not none %}{{ usdt_fmt(r.margin_capital) }}{% else %}-{% endif %}</td>
|
||||
<td>{% if r.margin_capital is not none and r.margin_capital != '' %}{{ funds_fmt(r.margin_capital) }}{% else %}-{% endif %}</td>
|
||||
<td>{{ r.leverage or '-' }}</td>
|
||||
<td>{{ r.effective_hold_minutes or 0 }}</td>
|
||||
<td>{{ (r.effective_opened_at or '-')[:16] }}</td>
|
||||
<td>{{ (r.effective_closed_at or r.created_at or '-')[:16] }}</td>
|
||||
{% set pnl_val = (r.effective_pnl_amount or 0)|float %}
|
||||
<td><span class="{{ 'pnl-profit' if pnl_val > 0 else ('pnl-loss' if pnl_val < 0 else '') }}">{{ signed_usdt_fmt(r.effective_pnl_amount or 0) }}</span>{% if r.display_pnl_source == 'exchange' %}<span style="font-size:.68rem;color:#6ab88a">所</span>{% elif r.display_pnl_source != 'reviewed' %}<span style="font-size:.68rem;color:#8892b0">估</span>{% endif %}</td>
|
||||
<td><span class="{{ 'pnl-profit' if pnl_val > 0 else ('pnl-loss' if pnl_val < 0 else '') }}">{{ funds_fmt(r.effective_pnl_amount or 0) }}</span>{% if r.display_pnl_source == 'exchange' %}<span style="font-size:.68rem;color:#6ab88a">所</span>{% elif r.display_pnl_source != 'reviewed' %}<span style="font-size:.68rem;color:#8892b0">估</span>{% endif %}</td>
|
||||
<td>
|
||||
{% set effective_result = r.effective_result %}
|
||||
{% if effective_result in ["止盈","保本止盈","移动止盈"] %}<span class="badge profit">{{ effective_result }}</span>
|
||||
@@ -858,7 +852,7 @@ function openJournalDetail(id){
|
||||
`开仓时间:${o.open_datetime || "-"}`,
|
||||
`平仓时间:${o.close_datetime || "-"}`,
|
||||
`持仓时长:${o.hold_duration || "-"}`,
|
||||
`盈亏:${formatJournalPnlUi(o.pnl)}U`,
|
||||
`盈亏:${o.pnl || "-"}U`,
|
||||
`开仓类型:${o.entry_reason || "无"}`,
|
||||
`平仓/离场:${formatJournalExitOneLine(o)}`,
|
||||
`预期RR:${o.expect_rr || "-"}`,
|
||||
@@ -941,7 +935,7 @@ function editTradeRecordReview(t){
|
||||
if(stopLoss === null) return;
|
||||
const takeProfit = prompt("止盈价格(核对后用于统计)", formatPriceForInput(t.take_profit));
|
||||
if(takeProfit === null) return;
|
||||
const pnl = prompt("最终盈亏(可手工核对后填写)", (t.pnl_amount === null || typeof t.pnl_amount === "undefined") ? "" : (Number.isFinite(Number(t.pnl_amount)) ? Number(t.pnl_amount).toFixed(2) : String(t.pnl_amount)));
|
||||
const pnl = prompt("最终盈亏(可手工核对后填写)", String(t.pnl_amount ?? ""));
|
||||
if(pnl === null) return;
|
||||
const result = prompt("结果(止盈/止损/保本止盈/移动止盈/手动平仓)", String(t.result || ""));
|
||||
if(result === null) return;
|
||||
@@ -1049,7 +1043,7 @@ function loadJournals(){
|
||||
journalCache[o.id] = o;
|
||||
const moodTags = (o.mood_issues || []).join(",") || "无";
|
||||
html += `<div class="entry">
|
||||
<div><strong>${o.coin||"-"} ${o.tf||"-"}</strong> | 盈亏:${formatJournalPnlUi(o.pnl)}U</div>
|
||||
<div><strong>${o.coin||"-"} ${o.tf||"-"}</strong> | 盈亏:${o.pnl||"-"}U</div>
|
||||
<div>开:${o.open_datetime||"-"} 平:${o.close_datetime||"-"} 持仓:${o.hold_duration||"-"}</div>
|
||||
<div>心态标签:${moodTags}</div>
|
||||
<div style="display:flex;gap:8px;flex-wrap:wrap;margin-top:6px">
|
||||
@@ -1231,7 +1225,7 @@ function fillJournalFromTrade(t){
|
||||
setJournalField("close_datetime", toDatetimeLocalFromBeijing(t.closed_at));
|
||||
setJournalField("coin", coinFromSymbol(t.symbol));
|
||||
setJournalField("tf", "5m");
|
||||
setJournalField("pnl", (t.pnl_amount === null || typeof t.pnl_amount === "undefined") ? "" : (Number.isFinite(Number(t.pnl_amount)) ? Number(t.pnl_amount).toFixed(2) : String(t.pnl_amount)));
|
||||
setJournalField("pnl", (t.pnl_amount === null || typeof t.pnl_amount === "undefined") ? "" : String(t.pnl_amount));
|
||||
const rr = calcExpectedRrFromTrade(t);
|
||||
setJournalField("expect_rr", rr);
|
||||
let realRr = rr;
|
||||
@@ -1242,7 +1236,7 @@ function fillJournalFromTrade(t){
|
||||
}
|
||||
setJournalField("real_rr", realRr);
|
||||
const riskHint = document.getElementById("risk-amount-hint");
|
||||
if(riskHint){ riskHint.value = (Number.isFinite(riskAmount) && riskAmount > 0) ? riskAmount.toFixed(2) : ""; }
|
||||
if(riskHint){ riskHint.value = (Number.isFinite(riskAmount) && riskAmount > 0) ? String(riskAmount) : ""; }
|
||||
const entryPx = formatPriceForInput(t.trigger_price);
|
||||
const slPx = formatPriceForInput(t.stop_loss);
|
||||
const tpPx = formatPriceForInput(t.take_profit);
|
||||
@@ -1416,6 +1410,7 @@ if(journalForm){
|
||||
|
||||
function syncKeyMonitorFormFields(){
|
||||
const typeEl = document.querySelector('#key-form [name="type"]');
|
||||
const dirEl = document.getElementById("key-direction");
|
||||
const modeEl = document.getElementById("key-sl-tp-mode");
|
||||
const manualTp = document.getElementById("key-manual-tp");
|
||||
const beWrap = document.getElementById("key-breakeven-wrap");
|
||||
@@ -1423,8 +1418,15 @@ function syncKeyMonitorFormFields(){
|
||||
const t = (typeEl.value || "").trim();
|
||||
const autoTypes = new Set(["箱体突破","收敛突破"]);
|
||||
const fibTypes = new Set(["斐波回调0.618","斐波回调0.786"]);
|
||||
const rsTypes = new Set(["关键阻力位","关键支撑位"]);
|
||||
const showAuto = autoTypes.has(t);
|
||||
const showBe = showAuto || fibTypes.has(t);
|
||||
const showDir = !rsTypes.has(t);
|
||||
if(dirEl){
|
||||
dirEl.style.display = showDir ? "" : "none";
|
||||
dirEl.required = showDir;
|
||||
if(!showDir) dirEl.value = "";
|
||||
}
|
||||
if(modeEl) modeEl.style.display = showAuto ? "" : "none";
|
||||
if(manualTp){
|
||||
const trend = showAuto && modeEl && modeEl.value === "trend_manual";
|
||||
@@ -1598,28 +1600,13 @@ function allowManualOrderSubmit(form){
|
||||
let latestAvailableUsdt = null;
|
||||
const lastPriceMap = {};
|
||||
|
||||
function formatSigned(v, digits=4){
|
||||
function formatSigned(v, digits=2){
|
||||
if(v === null || typeof v === "undefined" || Number.isNaN(Number(v))) return "-";
|
||||
const n = Number(v);
|
||||
const sign = n > 0 ? "+" : "";
|
||||
return `${sign}${n.toFixed(digits)}`;
|
||||
}
|
||||
|
||||
function formatUsdt2(v){
|
||||
if(v === null || typeof v === "undefined" || v === "") return "-";
|
||||
const n = Number(v);
|
||||
if(Number.isNaN(n)) return "-";
|
||||
return n.toFixed(2);
|
||||
}
|
||||
|
||||
function formatSignedUsdt2(v){
|
||||
if(v === null || typeof v === "undefined" || v === "" || Number.isNaN(Number(v))) return "-";
|
||||
const n = Number(v);
|
||||
if(n === 0) return "0.00";
|
||||
const sign = n > 0 ? "+" : "";
|
||||
return `${sign}${n.toFixed(2)}`;
|
||||
}
|
||||
|
||||
function formatRrRatio(rr){
|
||||
if(rr === null || typeof rr === "undefined") return "-:1";
|
||||
const n = Number(rr);
|
||||
@@ -1628,15 +1615,6 @@ function formatRrRatio(rr){
|
||||
return `${body}:1`;
|
||||
}
|
||||
|
||||
function formatJournalPnlUi(v){
|
||||
if(v === null || typeof v === "undefined" || v === "") return "-";
|
||||
const raw = String(v).trim();
|
||||
if(!raw) return "-";
|
||||
const n = Number(raw.replace(/,/g, ""));
|
||||
if(Number.isFinite(n)) return formatSignedUsdt2(n);
|
||||
return raw;
|
||||
}
|
||||
|
||||
function paintPriceTrend(el, key, value){
|
||||
if(!el) return;
|
||||
const prev = lastPriceMap[key];
|
||||
@@ -1660,7 +1638,7 @@ function refreshPriceSnapshot(){
|
||||
(data.key_prices || []).forEach(k=>{
|
||||
const pEl = document.getElementById(`key-price-${k.id}`);
|
||||
if(pEl){
|
||||
pEl.innerText = (k.price_display && k.price_display !== "-") ? k.price_display : Number(k.price).toFixed(6);
|
||||
pEl.innerText = k.price_display || (Number.isFinite(Number(k.price)) ? Number(k.price).toFixed(6) : "-");
|
||||
paintPriceTrend(pEl, `k-${k.id}`, Number(k.price));
|
||||
}
|
||||
const upEl = document.getElementById(`key-up-diff-${k.id}`);
|
||||
@@ -1684,19 +1662,26 @@ function refreshPriceSnapshot(){
|
||||
(data.order_prices || []).forEach(o=>{
|
||||
const pEl = document.getElementById(`order-price-${o.id}`);
|
||||
if(pEl){
|
||||
const pxd = (o.price_display && o.price_display !== "-") ? o.price_display : null;
|
||||
const hasMark = (()=>{ const x = o.exchange_mark_price; if(x===null||x===undefined||x==="")return false; const n=Number(x); return !Number.isNaN(n); })();
|
||||
const px = hasMark ? Number(o.exchange_mark_price) : Number(o.price);
|
||||
const decimals = hasMark ? 8 : 6;
|
||||
pEl.innerText = pxd !== null ? pxd : px.toFixed(decimals);
|
||||
paintPriceTrend(pEl, `o-${o.id}`, pxd !== null ? Number(pxd) : px);
|
||||
let disp = "";
|
||||
if(hasMark && o.exchange_mark_price_display){
|
||||
disp = o.exchange_mark_price_display;
|
||||
} else if(o.price_display){
|
||||
disp = o.price_display;
|
||||
} else {
|
||||
const px = hasMark ? Number(o.exchange_mark_price) : Number(o.price);
|
||||
disp = Number.isFinite(px) ? px.toFixed(6) : "-";
|
||||
}
|
||||
pEl.innerText = disp;
|
||||
const pxNum = hasMark ? Number(o.exchange_mark_price) : Number(o.price);
|
||||
paintPriceTrend(pEl, `o-${o.id}`, Number.isFinite(pxNum) ? pxNum : px);
|
||||
}
|
||||
const exM = document.getElementById(`order-ex-margin-${o.id}`);
|
||||
if(exM){
|
||||
const mv = o.exchange_initial_margin;
|
||||
const mn = (mv === null || mv === undefined || mv === "") ? NaN : Number(mv);
|
||||
if(!Number.isNaN(mn)){
|
||||
exM.innerText = `${formatUsdt2(mn)}U`;
|
||||
exM.innerText = `${mn.toFixed(2)}U`;
|
||||
} else {
|
||||
const prc = (typeof data.positions_raw_count === "number") ? data.positions_raw_count : null;
|
||||
exM.innerText = (prc === 0) ? "无仓数据" : "-";
|
||||
@@ -1704,7 +1689,7 @@ function refreshPriceSnapshot(){
|
||||
}
|
||||
const pnlEl = document.getElementById(`order-pnl-${o.id}`);
|
||||
if(pnlEl){
|
||||
pnlEl.innerText = `${formatSignedUsdt2(o.float_pnl)}U (${formatSigned(o.float_pct, 2)}%)`;
|
||||
pnlEl.innerText = `${formatSigned(o.float_pnl, 2)}U (${formatSigned(o.float_pct, 2)}%)`;
|
||||
pnlEl.classList.remove("price-up","price-down","price-flat");
|
||||
if(Number(o.float_pnl) > 0) pnlEl.classList.add("price-up");
|
||||
else if(Number(o.float_pnl) < 0) pnlEl.classList.add("price-down");
|
||||
@@ -1750,20 +1735,20 @@ function refreshAccountSnapshot(){
|
||||
fetch("/api/account_snapshot").then(r=>r.json()).then(data=>{
|
||||
if (typeof data.funding_usdt !== "undefined") {
|
||||
const el = document.getElementById("total-capital");
|
||||
if(el) el.innerText = (data.funding_usdt === null || data.funding_usdt === undefined) ? "—" : `${formatUsdt2(data.funding_usdt)}U`;
|
||||
if(el) el.innerText = (data.funding_usdt === null || data.funding_usdt === undefined) ? "—" : `${Number(data.funding_usdt).toFixed(2)}U`;
|
||||
}
|
||||
if (typeof data.current_capital !== "undefined") {
|
||||
const el = document.getElementById("current-capital");
|
||||
if(el) el.innerText = `${formatUsdt2(data.current_capital)}U`;
|
||||
if(el) el.innerText = `${Number(data.current_capital).toFixed(2)}U`;
|
||||
}
|
||||
if (typeof data.available_trading_usdt !== "undefined" && data.available_trading_usdt !== null) {
|
||||
latestAvailableUsdt = Number(data.available_trading_usdt);
|
||||
}
|
||||
const canTradeText = data.can_trade ? "可开仓" : `不可开仓(持仓 ${data.active_count||0}/${data.max_active_positions||{{ max_active_positions }}} 或未到北京时间 {{ reset_hour }}:00)`;
|
||||
const tip = document.getElementById("order-rule-tip");
|
||||
const avail = (latestAvailableUsdt !== null && !Number.isNaN(latestAvailableUsdt)) ? `;交易账户可用约 ${formatUsdt2(latestAvailableUsdt)}U` : "";
|
||||
const avail = (latestAvailableUsdt !== null && !Number.isNaN(latestAvailableUsdt)) ? `;交易账户可用约${latestAvailableUsdt.toFixed(2)}U` : "";
|
||||
if(tip){
|
||||
tip.innerText = `规则:最多 ${data.max_active_positions || {{ max_active_positions }}} 仓;BTC {{ btc_leverage }}x / 山寨 {{ alt_leverage }}x;${canTradeText}${avail};人工开仓盈亏比不得低于 ${data.manual_min_planned_rr || {{ manual_min_planned_rr }}}:1`;
|
||||
tip.innerText = `规则:最多 ${data.max_active_positions || {{ max_active_positions }}} 仓;BTC {{ btc_leverage }}x / 山寨 {{ alt_leverage }}x;${canTradeText}${avail}`;
|
||||
}
|
||||
}).catch(()=>{});
|
||||
}
|
||||
@@ -1882,23 +1867,25 @@ function refreshPriceSnapshotConditional(){
|
||||
(data.order_prices || []).forEach(o=>{
|
||||
const pEl = document.getElementById(`order-price-${o.id}`);
|
||||
if(pEl){
|
||||
const pxd = (o.price_display && o.price_display !== "-") ? o.price_display : null;
|
||||
const hasMark = (()=>{ const x = o.exchange_mark_price; if(x===null||x===undefined||x==="")return false; const n=Number(x); return !Number.isNaN(n); })();
|
||||
const px = hasMark ? Number(o.exchange_mark_price) : Number(o.price);
|
||||
const decimals = hasMark ? 8 : 6;
|
||||
pEl.innerText = pxd !== null ? pxd : px.toFixed(decimals);
|
||||
paintPriceTrend(pEl, `o-${o.id}`, pxd !== null ? Number(pxd) : px);
|
||||
let disp = "";
|
||||
if(hasMark && o.exchange_mark_price_display) disp = o.exchange_mark_price_display;
|
||||
else if(o.price_display) disp = o.price_display;
|
||||
else { const px = hasMark ? Number(o.exchange_mark_price) : Number(o.price); disp = Number.isFinite(px) ? px.toFixed(6) : "-"; }
|
||||
pEl.innerText = disp;
|
||||
const pxNum = hasMark ? Number(o.exchange_mark_price) : Number(o.price);
|
||||
paintPriceTrend(pEl, `o-${o.id}`, Number.isFinite(pxNum) ? pxNum : px);
|
||||
}
|
||||
const exM = document.getElementById(`order-ex-margin-${o.id}`);
|
||||
if(exM){
|
||||
const mv = o.exchange_initial_margin;
|
||||
const mn = (mv === null || mv === undefined || mv === "") ? NaN : Number(mv);
|
||||
if(!Number.isNaN(mn)) exM.innerText = `${formatUsdt2(mn)}U`;
|
||||
if(!Number.isNaN(mn)) exM.innerText = `${mn.toFixed(2)}U`;
|
||||
else { const prc = (typeof data.positions_raw_count === "number") ? data.positions_raw_count : null; exM.innerText = (prc === 0) ? "无仓数据" : "-"; }
|
||||
}
|
||||
const pnlEl = document.getElementById(`order-pnl-${o.id}`);
|
||||
if(pnlEl){
|
||||
pnlEl.innerText = `${formatSignedUsdt2(o.float_pnl)}U (${formatSigned(o.float_pct, 2)}%)`;
|
||||
pnlEl.innerText = `${formatSigned(o.float_pnl, 2)}U (${formatSigned(o.float_pct, 2)}%)`;
|
||||
pnlEl.classList.remove("price-up","price-down","price-flat");
|
||||
if(Number(o.float_pnl) > 0) pnlEl.classList.add("price-up");
|
||||
else if(Number(o.float_pnl) < 0) pnlEl.classList.add("price-down");
|
||||
@@ -1912,24 +1899,6 @@ function refreshPriceSnapshotConditional(){
|
||||
}).catch(()=>{});
|
||||
}
|
||||
setInterval(refreshPriceSnapshotConditional, {{ price_refresh_seconds * 1000 }});
|
||||
|
||||
const syncExchangePnlBtn = document.getElementById("sync-exchange-pnl-btn");
|
||||
if(syncExchangePnlBtn){
|
||||
syncExchangePnlBtn.addEventListener("click", ()=>{
|
||||
syncExchangePnlBtn.disabled = true;
|
||||
syncExchangePnlBtn.innerText = "同步中…";
|
||||
fetch("/api/sync_exchange_pnl").then(r=>r.json()).then(data=>{
|
||||
const msg = data.ok
|
||||
? `平仓历史 ${data.hist_count||0} 条,对齐 ${data.matched||0} 笔${data.reason?("\n"+data.reason):""}`
|
||||
: (data.reason || "同步失败");
|
||||
alert(msg);
|
||||
if((data.matched||0) > 0) location.reload();
|
||||
}).catch(()=>alert("同步请求失败")).finally(()=>{
|
||||
syncExchangePnlBtn.disabled = false;
|
||||
syncExchangePnlBtn.innerText = "立即同步";
|
||||
});
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user