修改币种精度
This commit is contained in:
@@ -130,14 +130,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">{{ s.net_pnl_u }}</div></div>
|
||||
<div class="stat-item"><div class="label">亏损额合计(U)</div><div class="value">{{ 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 %}{{ 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 %}{{ s.max_single_profit }}{% else %}-{% endif %}</div></div>
|
||||
<div class="stat-item"><div class="label">最大回撤(U)</div><div class="value">{{ s.max_drawdown_u }}</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">当前连续亏损笔数</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 }}({{ 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 }}({{ signed_usdt_fmt(s.worst_day_pnl) }}U){% else %}-{% endif %}</div></div>
|
||||
</div>
|
||||
</div>
|
||||
{% endmacro %}
|
||||
@@ -165,9 +165,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 %}{{ 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 %}{{ usdt_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">{{ current_capital }}U</div></div>
|
||||
<div class="stat-item"><div class="label">当日资金(交易账户)</div><div class="value" id="current-capital">{{ usdt_fmt(current_capital) }}U</div></div>
|
||||
</div>
|
||||
<div class="rule-tip">实时价格更新时间:<span id="price-last-updated">--</span>(北京时间 UTC+8)</div>
|
||||
|
||||
@@ -202,7 +202,7 @@
|
||||
<div class="list-item" id="key-row-{{ k.id }}">
|
||||
<div><strong>{{ k.symbol }}</strong> | {{ k.monitor_type }} | <span class="badge direction">{{ '做多' if k.direction == 'long' else '做空' }}</span></div>
|
||||
<div>
|
||||
上:{{ k.upper }} 下:{{ k.lower }}
|
||||
上:{{ price_fmt(k.symbol, k.upper) }} 下:{{ price_fmt(k.symbol, k.lower) }}
|
||||
| 已提醒:{{ k.notification_count or 0 }}/{{ k.max_notify or 3 }}
|
||||
| 现价:<span id="key-price-{{ k.id }}">-</span>
|
||||
| 距上沿:<span id="key-up-diff-{{ k.id }}">-</span>
|
||||
@@ -224,7 +224,7 @@
|
||||
<strong>{{ h.symbol }}</strong> | {{ h.monitor_type }} | {{ '做多' if h.direction == 'long' else '做空' }} | {{ h.close_reason }}
|
||||
<button type="button" class="table-del" style="margin-left:8px" onclick="deleteKeyHistory({{ h.id }})">删除</button>
|
||||
</div>
|
||||
<div>上:{{ h.upper }} 下:{{ h.lower }} | 提醒次数:{{ h.notification_count }} | {{ (h.closed_at or '-')[:16] }}</div>
|
||||
<div>上:{{ price_fmt(h.symbol, h.upper) }} 下:{{ price_fmt(h.symbol, h.lower) }} | 提醒次数:{{ h.notification_count }} | {{ (h.closed_at or '-')[:16] }}</div>
|
||||
{% if h.last_alert_message %}<div style="font-size:.78rem;color:#aab;margin-top:4px;white-space:pre-wrap">{{ h.last_alert_message[:200] }}{% if h.last_alert_message|length > 200 %}…{% endif %}</div>{% endif %}
|
||||
</div>
|
||||
{% else %}
|
||||
@@ -252,7 +252,7 @@
|
||||
以损定仓:风险 {{ risk_percent }}% |移动保本:下单可勾选关闭;开启时 {{ breakeven_rr_trigger }}R 触发(每 1R 阶梯上移),偏移 {{ breakeven_offset_pct }}%
|
||||
</div>
|
||||
<div class="rule-tip">
|
||||
划转:自动划转 {{ '开启' if auto_transfer_enabled else '关闭' }}(每天<strong>北京时间 {{ auto_transfer_bj_hour }}:00</strong>起该整点小时内尝试;账簿按 <strong>UTC 自然日</strong>去重;界面时间为北京;将 {{ auto_transfer_to }} 补足到 {{ auto_transfer_amount }}U,来自 {{ auto_transfer_from }})
|
||||
划转:自动划转 {{ '开启' if auto_transfer_enabled else '关闭' }}(每天<strong>北京时间 {{ auto_transfer_bj_hour }}:00</strong>起该整点小时内尝试;账簿按 <strong>UTC 自然日</strong>去重;界面时间为北京;将 {{ auto_transfer_to }} 补足到 {{ usdt_fmt(auto_transfer_amount) }}U,来自 {{ auto_transfer_from }})
|
||||
</div>
|
||||
<form action="/manual_transfer" method="post" class="form-row">
|
||||
<input name="amount" type="number" min="0.01" step="0.01" placeholder="手动划转金额U" required>
|
||||
@@ -300,14 +300,14 @@
|
||||
<div class="list-item">
|
||||
<div><strong>{{ o.symbol }}</strong> | <span class="badge direction">{{ '做多' if o.direction == 'long' else '做空' }}</span></div>
|
||||
<div>
|
||||
风格:{{ o.trade_style or 'trend' }} | 风险:{{ o.risk_percent or '-' }}%≈{{ o.risk_amount or '-' }}U
|
||||
| {% if o.breakeven_enabled %}移动保本:开 {{ o.breakeven_rr_trigger or '-' }}R→{{ o.breakeven_price or '-' }}{% else %}移动保本:关{% endif %}
|
||||
风格:{{ o.trade_style or 'trend' }} | 风险:{{ o.risk_percent or '-' }}%≈{% if o.risk_amount is not none %}{{ usdt_fmt(o.risk_amount) }}{% else %}-{% endif %}U
|
||||
| {% if o.breakeven_enabled %}移动保本:开 {{ o.breakeven_rr_trigger or '-' }}R→{{ price_fmt(o.symbol, o.breakeven_price) }}{% else %}移动保本:关{% endif %}
|
||||
<br>
|
||||
成交:{{ o.trigger_price }} 止损:{{ o.stop_loss }} 止盈:{{ o.take_profit }}
|
||||
成交:{{ price_fmt(o.symbol, o.trigger_price) }} 止损:{{ price_fmt(o.symbol, o.stop_loss) }} 止盈:{{ price_fmt(o.symbol, o.take_profit) }}
|
||||
| 盈亏比:<span id="order-rr-{{ o.id }}">{% if o.rr_ratio is not none %}1:{{ '%.2f'|format(o.rr_ratio) }}{% else %}-{% endif %}</span>
|
||||
| 现价:<span id="order-price-{{ o.id }}">-</span>
|
||||
| 浮盈亏:<span id="order-pnl-{{ o.id }}">-</span>
|
||||
| 计划基数:{{ o.margin_capital }}U | 所保证金:<span id="order-ex-margin-{{ o.id }}">-</span>
|
||||
| 计划基数:{% if o.margin_capital is not none %}{{ usdt_fmt(o.margin_capital) }}{% else %}-{% endif %}U | 所保证金:<span id="order-ex-margin-{{ o.id }}">-</span>
|
||||
| 杠杆:{{ o.leverage }}x | 仓位占比:{{ o.position_ratio }}%
|
||||
</div>
|
||||
<a href="/del_order/{{ o.id }}" class="btn-del" onclick="return confirm('删除会触发手动平仓,继续?')">平仓</a>
|
||||
@@ -335,18 +335,18 @@
|
||||
<td>{{ r.symbol }}</td>
|
||||
<td>{{ r.monitor_type }}</td>
|
||||
<td><span class="badge {{ 'direction-long' if r.direction == 'long' else 'direction-short' }}">{{ '做多' if r.direction == 'long' else '做空' }}</span></td>
|
||||
<td>{{ r.trigger_price }}</td>
|
||||
<td>{{ price_fmt(r.symbol, r.trigger_price) }}</td>
|
||||
{% set stop_show = r.effective_stop_loss or r.initial_stop_loss or r.stop_loss %}
|
||||
{% 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>{{ r.margin_capital or '-' }}</td>
|
||||
<td>{% if r.margin_capital is not none %}{{ usdt_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 '') }}">{{ r.effective_pnl_amount or 0 }}</span></td>
|
||||
<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></td>
|
||||
<td>
|
||||
{% set effective_result = r.effective_result %}
|
||||
{% if effective_result in ["止盈","保本止盈","移动止盈"] %}<span class="badge profit">{{ effective_result }}</span>
|
||||
@@ -602,7 +602,7 @@ function openJournalDetail(id){
|
||||
`开仓时间:${o.open_datetime || "-"}`,
|
||||
`平仓时间:${o.close_datetime || "-"}`,
|
||||
`持仓时长:${o.hold_duration || "-"}`,
|
||||
`盈亏:${o.pnl || "-"}U`,
|
||||
`盈亏:${formatJournalPnlUi(o.pnl)}U`,
|
||||
`开仓类型:${o.entry_reason || "无"}`,
|
||||
`平仓/离场:${formatJournalExitOneLine(o)}`,
|
||||
`预期RR:${o.expect_rr || "-"}`,
|
||||
@@ -685,7 +685,7 @@ function editTradeRecordReview(t){
|
||||
if(stopLoss === null) return;
|
||||
const takeProfit = prompt("止盈价格(核对后用于统计)", String(t.take_profit ?? ""));
|
||||
if(takeProfit === null) return;
|
||||
const pnl = prompt("最终盈亏(可手工核对后填写)", String(t.pnl_amount ?? ""));
|
||||
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)));
|
||||
if(pnl === null) return;
|
||||
const result = prompt("结果(止盈/止损/保本止盈/移动止盈/手动平仓)", String(t.result || ""));
|
||||
if(result === null) return;
|
||||
@@ -751,7 +751,7 @@ function loadJournals(){
|
||||
journalCache[o.id] = o;
|
||||
const moodTags = (o.mood_issues || []).join(",") || "无";
|
||||
html += `<div class="entry">
|
||||
<div><strong>${o.coin||"-"} ${o.tf||"-"}</strong> | 盈亏:${o.pnl||"-"}U</div>
|
||||
<div><strong>${o.coin||"-"} ${o.tf||"-"}</strong> | 盈亏:${formatJournalPnlUi(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">
|
||||
@@ -908,7 +908,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") ? "" : String(t.pnl_amount));
|
||||
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)));
|
||||
const rr = calcExpectedRrFromTrade(t);
|
||||
setJournalField("expect_rr", rr);
|
||||
let realRr = rr;
|
||||
@@ -919,7 +919,7 @@ function fillJournalFromTrade(t){
|
||||
}
|
||||
setJournalField("real_rr", realRr);
|
||||
const riskHint = document.getElementById("risk-amount-hint");
|
||||
if(riskHint){ riskHint.value = (Number.isFinite(riskAmount) && riskAmount > 0) ? String(riskAmount) : ""; }
|
||||
if(riskHint){ riskHint.value = (Number.isFinite(riskAmount) && riskAmount > 0) ? riskAmount.toFixed(2) : ""; }
|
||||
const entryHint = document.getElementById("entry-price-hint");
|
||||
if(entryHint){ entryHint.value = t.trigger_price || ""; }
|
||||
const stopHint = document.getElementById("stop-loss-hint");
|
||||
@@ -1098,6 +1098,30 @@ function formatSigned(v, digits=4){
|
||||
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 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];
|
||||
@@ -1121,7 +1145,7 @@ function refreshPriceSnapshot(){
|
||||
(data.key_prices || []).forEach(k=>{
|
||||
const pEl = document.getElementById(`key-price-${k.id}`);
|
||||
if(pEl){
|
||||
pEl.innerText = Number(k.price).toFixed(6);
|
||||
pEl.innerText = (k.price_display && k.price_display !== "-") ? k.price_display : Number(k.price).toFixed(6);
|
||||
paintPriceTrend(pEl, `k-${k.id}`, Number(k.price));
|
||||
}
|
||||
const upEl = document.getElementById(`key-up-diff-${k.id}`);
|
||||
@@ -1145,18 +1169,19 @@ 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 = px.toFixed(decimals);
|
||||
paintPriceTrend(pEl, `o-${o.id}`, px);
|
||||
pEl.innerText = pxd !== null ? pxd : px.toFixed(decimals);
|
||||
paintPriceTrend(pEl, `o-${o.id}`, pxd !== null ? Number(pxd) : 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 = `${mn.toFixed(4)}U`;
|
||||
exM.innerText = `${formatUsdt2(mn)}U`;
|
||||
} else {
|
||||
const prc = (typeof data.positions_raw_count === "number") ? data.positions_raw_count : null;
|
||||
exM.innerText = (prc === 0) ? "无仓数据" : "-";
|
||||
@@ -1164,7 +1189,7 @@ function refreshPriceSnapshot(){
|
||||
}
|
||||
const pnlEl = document.getElementById(`order-pnl-${o.id}`);
|
||||
if(pnlEl){
|
||||
pnlEl.innerText = `${formatSigned(o.float_pnl, 4)}U (${formatSigned(o.float_pct, 2)}%)`;
|
||||
pnlEl.innerText = `${formatSignedUsdt2(o.float_pnl)}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");
|
||||
@@ -1198,7 +1223,7 @@ function refreshOrderDefaults(){
|
||||
const fullEl = document.getElementById("use-full-margin");
|
||||
const marginEl = document.getElementById("order-margin");
|
||||
if(fullEl && marginEl && fullEl.checked){
|
||||
const m = Math.max(latestAvailableUsdt * {{ full_margin_buffer_ratio }}, 0).toFixed(4);
|
||||
const m = Math.max(latestAvailableUsdt * {{ full_margin_buffer_ratio }}, 0).toFixed(2);
|
||||
marginEl.value = m;
|
||||
}
|
||||
}
|
||||
@@ -1209,18 +1234,18 @@ 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) ? "—" : `${data.funding_usdt}U`;
|
||||
if(el) el.innerText = (data.funding_usdt === null || data.funding_usdt === undefined) ? "—" : `${formatUsdt2(data.funding_usdt)}U`;
|
||||
}
|
||||
if (typeof data.current_capital !== "undefined") {
|
||||
const el = document.getElementById("current-capital");
|
||||
if(el) el.innerText = `${data.current_capital}U`;
|
||||
if(el) el.innerText = `${formatUsdt2(data.current_capital)}U`;
|
||||
}
|
||||
if (typeof data.available_trading_usdt !== "undefined" && data.available_trading_usdt !== null) {
|
||||
latestAvailableUsdt = Number(data.available_trading_usdt);
|
||||
}
|
||||
const canTradeText = data.can_trade ? "可开仓" : "不可开仓(有持仓或未到北京时间 {{ reset_hour }}:00)";
|
||||
const tip = document.getElementById("order-rule-tip");
|
||||
const avail = (latestAvailableUsdt !== null && !Number.isNaN(latestAvailableUsdt)) ? `;交易账户可用约${latestAvailableUsdt}U` : "";
|
||||
const avail = (latestAvailableUsdt !== null && !Number.isNaN(latestAvailableUsdt)) ? `;交易账户可用约 ${formatUsdt2(latestAvailableUsdt)}U` : "";
|
||||
if(tip){
|
||||
tip.innerText = `规则:单仓;BTC {{ btc_leverage }}x / 山寨 {{ alt_leverage }}x;${canTradeText}${avail}`;
|
||||
}
|
||||
@@ -1236,7 +1261,7 @@ if(fullMarginEl){
|
||||
fullMarginEl.addEventListener("change", function(){
|
||||
const marginEl = document.getElementById("order-margin");
|
||||
if(marginEl && this.checked && latestAvailableUsdt !== null && !Number.isNaN(latestAvailableUsdt)){
|
||||
marginEl.value = Math.max(latestAvailableUsdt * {{ full_margin_buffer_ratio }}, 0).toFixed(4);
|
||||
marginEl.value = Math.max(latestAvailableUsdt * {{ full_margin_buffer_ratio }}, 0).toFixed(2);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user