feat: compact instance toolbar, stats strip and settings two-column layout

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-07-07 01:37:19 +08:00
parent d87081205d
commit 6547029a89
11 changed files with 322 additions and 114 deletions
+10
View File
@@ -7400,10 +7400,20 @@ def api_account_snapshot():
extra_blocks=not risk_status.get("can_trade", True),
)
available_trading_usdt = get_available_trading_usdt()
unrealized_pnl = None
if exchange_private_api_configured():
from lib.instance.instance_live_pnl_lib import fetch_unrealized_pnl
def _binance_positions():
ensure_markets_loaded()
return exchange.fetch_positions() or []
unrealized_pnl = fetch_unrealized_pnl(_binance_positions)
return jsonify({
"funding_usdt": funding_usdt,
"current_capital": current_capital,
"available_trading_usdt": round(available_trading_usdt, FUNDS_DECIMALS) if available_trading_usdt is not None else None,
"unrealized_pnl": unrealized_pnl,
"recommended_capital": recommended_capital,
"active_count": position_limit_count,
"max_active_positions": MAX_ACTIVE_POSITIONS,
+13
View File
@@ -7215,10 +7215,23 @@ def api_account_snapshot():
extra_blocks=not risk_status.get("can_trade", True),
)
available_trading_usdt = get_available_trading_usdt()
unrealized_pnl = None
if exchange_private_api_configured():
from lib.instance.instance_live_pnl_lib import fetch_unrealized_pnl
def _gate_positions():
ensure_markets_loaded()
try:
return exchange.fetch_positions(None, {"settle": "usdt"}) or []
except Exception:
return exchange.fetch_positions() or []
unrealized_pnl = fetch_unrealized_pnl(_gate_positions)
return jsonify({
"funding_usdt": funding_usdt,
"current_capital": current_capital,
"available_trading_usdt": round(available_trading_usdt, 2) if available_trading_usdt is not None else None,
"unrealized_pnl": unrealized_pnl,
"recommended_capital": recommended_capital,
"active_count": position_limit_count,
"max_active_positions": MAX_ACTIVE_POSITIONS,
+13
View File
@@ -6761,10 +6761,23 @@ def api_account_snapshot():
extra_blocks=not risk_status.get("can_trade", True),
)
available_trading_usdt = get_available_trading_usdt()
unrealized_pnl = None
if exchange_private_api_configured():
from lib.instance.instance_live_pnl_lib import fetch_unrealized_pnl
def _okx_positions():
ensure_markets_loaded()
try:
return exchange.fetch_positions(None, {"instType": OKX_POSITION_INST_TYPE}) or []
except Exception:
return exchange.fetch_positions() or []
unrealized_pnl = fetch_unrealized_pnl(_okx_positions)
return jsonify({
"funding_usdt": funding_usdt,
"current_capital": current_capital,
"available_trading_usdt": round(available_trading_usdt, FUNDS_DECIMALS) if available_trading_usdt is not None else None,
"unrealized_pnl": unrealized_pnl,
"recommended_capital": recommended_capital,
"active_count": position_limit_count,
"max_active_positions": MAX_ACTIVE_POSITIONS,
+120 -1
View File
@@ -71,6 +71,20 @@
gap: 8px;
}
.instance-toolbar-row {
flex-direction: column;
align-items: stretch;
}
.instance-toolbar-filter.list-window-bar {
flex-basis: auto;
}
.stat-strip-inner {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
}
.grid {
gap: 10px;
}
@@ -497,6 +511,95 @@ html[data-theme="light"] .theme-toggle-btn.is-active {
margin-top: 6px;
}
/* ── 顶栏:状态 + 列表筛选 同一行 ── */
.instance-toolbar-row {
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: space-between;
gap: 10px 14px;
margin-bottom: 12px;
}
.instance-toolbar-status {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 8px;
flex: 0 1 auto;
}
.instance-toolbar-filter.list-window-bar {
flex: 1 1 320px;
margin-bottom: 0;
}
.list-window-label {
color: #cfd3ef;
}
.list-window-hint {
color: #8892b0;
font-size: 0.75rem;
}
.list-window-apply {
padding: 6px 12px;
}
/* ── 单行统计卡 ── */
.stat-strip {
margin-bottom: 12px;
padding: 10px 14px;
}
.stat-strip-inner {
display: flex;
flex-wrap: wrap;
gap: 8px 12px;
align-items: stretch;
justify-content: space-between;
}
.stat-strip-item {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
min-width: 72px;
flex: 1 1 0;
text-align: center;
}
.stat-strip-item .label {
font-size: 0.72rem;
color: #8892b0;
margin-bottom: 4px;
}
.stat-strip-item .value {
font-size: 0.95rem;
font-weight: 600;
color: #e8ecff;
line-height: 1.25;
}
.stat-strip-item--pnl .value.pnl-pos {
color: #3dd68c;
}
.stat-strip-item--pnl .value.pnl-neg {
color: #ff6b7a;
}
html[data-theme="light"] .stat-strip-item .value {
color: #142232;
}
html[data-theme="light"] .list-window-label {
color: #1a2838;
}
.login-theme-bar {
display: flex;
justify-content: flex-end;
@@ -1924,11 +2027,27 @@ html[data-theme="light"] .journal-detail-img-thumb {
.settings-cards-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
grid-template-columns: minmax(0, 1.45fr) minmax(280px, 1fr);
gap: 16px;
align-items: start;
}
.settings-side-col {
display: flex;
flex-direction: column;
gap: 16px;
}
.settings-card--risk {
min-width: 0;
}
@media (max-width: 900px) {
.settings-cards-grid {
grid-template-columns: minmax(0, 1fr);
}
}
.settings-card h2 {
margin: 0 0 10px;
font-size: 1.05rem;
+32
View File
@@ -0,0 +1,32 @@
"""实例页:持仓未实现盈亏(实时盈亏)汇总。"""
from __future__ import annotations
from collections.abc import Callable
from typing import Any
from lib.hub.hub_monitor_totals_lib import position_unrealized_pnl
def _position_contracts(pos: dict[str, Any]) -> float:
try:
return abs(float(pos.get("contracts") or 0))
except (TypeError, ValueError):
return 0.0
def sum_unrealized_pnl_from_positions(positions: list[dict[str, Any]] | None) -> float:
total = 0.0
for p in positions or []:
if not isinstance(p, dict):
continue
if _position_contracts(p) <= 1e-12:
continue
total += position_unrealized_pnl(p)
return round(total, 2)
def fetch_unrealized_pnl(fetch_positions_fn: Callable[[], list[dict[str, Any]] | None]) -> float | None:
try:
return sum_unrealized_pnl_from_positions(fetch_positions_fn() or [])
except Exception:
return None
@@ -1031,6 +1031,21 @@ function refreshAccountSnapshot(){
const el = document.getElementById("current-capital");
if(el) el.innerText = `${Number(data.current_capital).toFixed(2)}U`;
}
if (typeof data.unrealized_pnl !== "undefined") {
const pnlEl = document.getElementById("realtime-pnl");
if (pnlEl) {
if (data.unrealized_pnl === null || data.unrealized_pnl === undefined) {
pnlEl.innerText = "—";
pnlEl.classList.remove("pnl-pos", "pnl-neg");
} else {
const v = Number(data.unrealized_pnl);
const sign = v > 0 ? "+" : "";
pnlEl.innerText = `${sign}${v.toFixed(2)}U`;
pnlEl.classList.toggle("pnl-pos", v > 0);
pnlEl.classList.toggle("pnl-neg", v < 0);
}
}
}
if (typeof data.available_trading_usdt !== "undefined" && data.available_trading_usdt !== null) {
latestAvailableUsdt = Number(data.available_trading_usdt);
}
+5 -46
View File
@@ -7,7 +7,7 @@
<link rel="stylesheet" href="/static/instance_theme_early.css?v=4">
<link rel="stylesheet" href="/static/account_risk_badge.css?v=4">
<link rel="stylesheet" href="/static/instance_page.css?v=3">
<link rel="stylesheet" href="/static/instance_theme.css?v=54">
<link rel="stylesheet" href="/static/instance_theme.css?v=55">
<script src="/static/account_risk_badge.js?v=4"></script>
<meta name="theme-color" content="#0b0d14">
<title>{{ exchange_display }} · 加密货币 | 交易监控复盘系统</title>
@@ -26,26 +26,6 @@
<div class="container">
<div class="header">
<h1>加密货币|交易监控 + AI复盘一体化</h1>
<div class="header-row">
<div class="exchange-tag">{{ exchange_display }}</div>
{% if trade_policy.badge_text %}
<span class="trade-policy-badge" title="账户交易限制(.env">{{ trade_policy.badge_text }}</span>
{% endif %}
{% include 'force_close_header_badge.html' %}
<span class="risk-status-badge risk-status-{{ risk_status.status|default('normal') }}" id="account-risk-badge" role="status" title="{{ risk_status.reason|default('', true) }}" data-status-label="{{ risk_status.status_label|default('正常') }}"{% if risk_status.freeze_until_ms %} data-freeze-until-ms="{{ risk_status.freeze_until_ms }}"{% endif %}>{{ risk_status.status_label|default('正常') }}</span>
<div class="theme-toggle instance-theme-toggle" role="group" aria-label="界面主题">
<button type="button" class="theme-toggle-btn is-active" data-theme-value="dark" aria-pressed="true" title="暗色主题">
<svg class="theme-icon" viewBox="0 0 24 24" width="18" height="18" aria-hidden="true">
<path fill="currentColor" d="M12.1 3a9 9 0 1 0 8.9 11 6.5 6.5 0 1 1-8.9-11z"/>
</svg>
</button>
<button type="button" class="theme-toggle-btn" data-theme-value="light" aria-pressed="false" title="亮色主题">
<svg class="theme-icon" viewBox="0 0 24 24" width="18" height="18" aria-hidden="true" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round">
<circle cx="12" cy="12" r="4"/><path d="M12 2v2M12 20v2M4.93 4.93l1.41 1.41M17.66 17.66l1.41 1.41M2 12h2M20 12h2M4.93 19.07l1.41-1.41M17.66 6.34l1.41-1.41"/>
</svg>
</button>
</div>
</div>
</div>
<nav class="top-nav embed-top-nav" aria-label="实例导航">
<a href="/key_monitor" data-embed-tab="key_monitor" class="{% if initial_tab == 'key_monitor' %}active{% endif %}">关键位监控</a>
@@ -60,31 +40,10 @@
</nav>
<div id="embed-flash" class="flash" style="display:none" role="status"></div>
<div class="list-window-bar">
<span style="color:#cfd3ef">列表筛选(<strong>UTC</strong>,默认当日):{{ list_window.label }}</span>
<label>预设
<select id="win-preset-select" onchange="toggleListWindowCustom()">
<option value="utc_today" {% if list_window.preset == 'utc_today' %}selected{% endif %}>UTC 当日</option>
<option value="utc_last24h" {% if list_window.preset == 'utc_last24h' %}selected{% endif %}>近 24 小时</option>
<option value="utc_last7d" {% if list_window.preset == 'utc_last7d' %}selected{% endif %}>近 7 天</option>
<option value="custom" {% if list_window.preset == 'custom' %}selected{% endif %}>自定义</option>
</select>
</label>
<span id="win-custom-range" style="{% if list_window.preset != 'custom' %}display:none{% endif %}">
<label>起(UTC) <input type="datetime-local" id="win-from-utc" value="{{ list_window.start_utc.strftime('%Y-%m-%dT%H:%M') }}"></label>
<label>止(UTC) <input type="datetime-local" id="win-to-utc" value="{{ list_window.end_utc.strftime('%Y-%m-%dT%H:%M') }}"></label>
</span>
<button type="button" style="padding:6px 12px" onclick="applyListWindow()">应用</button>
<span style="color:#8892b0;font-size:.75rem">统计页仍按北京时间 {{ stats_bundle.stats_reset_hour|default(reset_hour) }}:00 切日</span>
</div>
<div class="stat-box instance-desktop-only">
<div class="stat-item"><div class="label">交易所</div><div class="value">{{ exchange_display }}</div></div>
<div class="stat-item"><div class="label">总交易</div><div class="value" id="stat-total">{{ total }}</div></div>
<div class="stat-item"><div class="label">胜率</div><div class="value" id="stat-rate">{{ rate }}%</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">{{ funds_fmt(current_capital) }}U</div></div>
</div>
{% if initial_tab != 'settings' %}
{% include 'instance_toolbar_row.html' %}
{% include 'instance_stats_strip.html' %}
{% endif %}
{% if initial_tab != 'settings' and include_transfer_block %}
{% include 'instance_top_bar.html' %}
{% endif %}
+18 -46
View File
@@ -17,7 +17,7 @@
<link rel="manifest" href="/static/icons/manifest.webmanifest">
<title>{{ exchange_display }} · 加密货币 | 交易监控复盘系统</title>
<link rel="stylesheet" href="/static/instance_page.css?v=1">
<link rel="stylesheet" href="/static/instance_theme.css?v=54">
<link rel="stylesheet" href="/static/instance_theme.css?v=55">
</head>
<body
@@ -51,26 +51,6 @@
<div class="container">
<div class="header">
<h1>加密货币|交易监控 + AI复盘一体化</h1>
<div class="header-row">
<div class="exchange-tag">{{ exchange_display }}</div>
{% if trade_policy.badge_text %}
<span class="trade-policy-badge" title="账户交易限制(.env">{{ trade_policy.badge_text }}</span>
{% endif %}
{% include 'force_close_header_badge.html' %}
<span class="risk-status-badge risk-status-{{ risk_status.status|default('normal') }}" id="account-risk-badge" role="status" title="{{ risk_status.reason|default('', true) }}" data-status-label="{{ risk_status.status_label|default('正常') }}"{% if risk_status.freeze_until_ms %} data-freeze-until-ms="{{ risk_status.freeze_until_ms }}"{% endif %}>{{ risk_status.status_label|default('正常') }}</span>
<div class="theme-toggle instance-theme-toggle" role="group" aria-label="界面主题">
<button type="button" class="theme-toggle-btn is-active" data-theme-value="dark" aria-pressed="true" title="暗色主题">
<svg class="theme-icon" viewBox="0 0 24 24" width="18" height="18" aria-hidden="true">
<path fill="currentColor" d="M12.1 3a9 9 0 1 0 8.9 11 6.5 6.5 0 1 1-8.9-11z"/>
</svg>
</button>
<button type="button" class="theme-toggle-btn" data-theme-value="light" aria-pressed="false" title="亮色主题">
<svg class="theme-icon" viewBox="0 0 24 24" width="18" height="18" aria-hidden="true" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round">
<circle cx="12" cy="12" r="4"/><path d="M12 2v2M12 20v2M4.93 4.93l1.41 1.41M17.66 17.66l1.41 1.41M2 12h2M20 12h2M4.93 19.07l1.41-1.41M17.66 6.34l1.41-1.41"/>
</svg>
</button>
</div>
</div>
</div>
<div class="top-nav">
<a href="/key_monitor" class="{% if page == 'key_monitor' %}active{% endif %}">关键位监控</a>
@@ -86,31 +66,8 @@
{% with msg=get_flashed_messages() %}{% if msg %}<div class="flash">{{ msg[0] }}</div>{% endif %}{% endwith %}
{% if page != 'settings' %}
<div class="list-window-bar">
<span style="color:#cfd3ef">列表筛选(<strong>UTC</strong>,默认当日):{{ list_window.label }}</span>
<label>预设
<select id="win-preset-select" onchange="toggleListWindowCustom()">
<option value="utc_today" {% if list_window.preset == 'utc_today' %}selected{% endif %}>UTC 当日</option>
<option value="utc_last24h" {% if list_window.preset == 'utc_last24h' %}selected{% endif %}>近 24 小时</option>
<option value="utc_last7d" {% if list_window.preset == 'utc_last7d' %}selected{% endif %}>近 7 天</option>
<option value="custom" {% if list_window.preset == 'custom' %}selected{% endif %}>自定义</option>
</select>
</label>
<span id="win-custom-range" style="{% if list_window.preset != 'custom' %}display:none{% endif %}">
<label>起(UTC) <input type="datetime-local" id="win-from-utc" value="{{ list_window.start_utc.strftime('%Y-%m-%dT%H:%M') }}"></label>
<label>止(UTC) <input type="datetime-local" id="win-to-utc" value="{{ list_window.end_utc.strftime('%Y-%m-%dT%H:%M') }}"></label>
</span>
<button type="button" style="padding:6px 12px" onclick="applyListWindow()">应用</button>
<span style="color:#8892b0;font-size:.75rem">统计页仍按北京时间 {{ stats_bundle.stats_reset_hour|default(reset_hour) }}:00 切日</span>
</div>
<div class="stat-box instance-desktop-only">
<div class="stat-item"><div class="label">交易所</div><div class="value">{{ exchange_display }}</div></div>
<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">{{ rate }}%</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">{{ funds_fmt(current_capital) }}U</div></div>
</div>
{% include 'instance_toolbar_row.html' %}
{% include 'instance_stats_strip.html' %}
{% endif %}
{% if page != 'settings' %}
{% include 'instance_top_bar.html' %}
@@ -1621,6 +1578,21 @@ function refreshAccountSnapshot(){
const el = document.getElementById("current-capital");
if(el) el.innerText = `${Number(data.current_capital).toFixed(2)}U`;
}
if (typeof data.unrealized_pnl !== "undefined") {
const pnlEl = document.getElementById("realtime-pnl");
if (pnlEl) {
if (data.unrealized_pnl === null || data.unrealized_pnl === undefined) {
pnlEl.innerText = "—";
pnlEl.classList.remove("pnl-pos", "pnl-neg");
} else {
const v = Number(data.unrealized_pnl);
const sign = v > 0 ? "+" : "";
pnlEl.innerText = `${sign}${v.toFixed(2)}U`;
pnlEl.classList.toggle("pnl-pos", v > 0);
pnlEl.classList.toggle("pnl-neg", v < 0);
}
}
}
if (typeof data.available_trading_usdt !== "undefined" && data.available_trading_usdt !== null) {
latestAvailableUsdt = Number(data.available_trading_usdt);
}
@@ -0,0 +1,33 @@
{# 单行统计卡:交易所 / 总交易 / 胜率 / 资金 / 交易日 / 当日资金 / 实时盈亏 #}
<div class="stat-strip card instance-desktop-only">
<div class="stat-strip-inner">
<div class="stat-strip-item">
<div class="label">交易所</div>
<div class="value">{{ exchange_display }}</div>
</div>
<div class="stat-strip-item">
<div class="label">总交易</div>
<div class="value" id="stat-total">{{ total }}</div>
</div>
<div class="stat-strip-item">
<div class="label">胜率</div>
<div class="value" id="stat-rate">{{ rate }}%</div>
</div>
<div class="stat-strip-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-strip-item">
<div class="label">交易日</div>
<div class="value">{{ trading_day }}</div>
</div>
<div class="stat-strip-item">
<div class="label">当日资金(交易账户)</div>
<div class="value" id="current-capital">{{ funds_fmt(current_capital) }}U</div>
</div>
<div class="stat-strip-item stat-strip-item--pnl">
<div class="label">实时盈亏</div>
<div class="value" id="realtime-pnl"></div>
</div>
</div>
</div>
@@ -0,0 +1,40 @@
{# 状态徽章 + 列表筛选 同一行 #}
<div class="instance-toolbar-row">
<div class="instance-toolbar-status">
<div class="exchange-tag">{{ exchange_display }}</div>
{% if trade_policy.badge_text %}
<span class="trade-policy-badge" title="账户交易限制(.env">{{ trade_policy.badge_text }}</span>
{% endif %}
{% include 'force_close_header_badge.html' %}
<span class="risk-status-badge risk-status-{{ risk_status.status|default('normal') }}" id="account-risk-badge" role="status" title="{{ risk_status.reason|default('', true) }}" data-status-label="{{ risk_status.status_label|default('正常') }}"{% if risk_status.freeze_until_ms %} data-freeze-until-ms="{{ risk_status.freeze_until_ms }}"{% endif %}>{{ risk_status.status_label|default('正常') }}</span>
<div class="theme-toggle instance-theme-toggle" role="group" aria-label="界面主题">
<button type="button" class="theme-toggle-btn is-active" data-theme-value="dark" aria-pressed="true" title="暗色主题">
<svg class="theme-icon" viewBox="0 0 24 24" width="18" height="18" aria-hidden="true">
<path fill="currentColor" d="M12.1 3a9 9 0 1 0 8.9 11 6.5 6.5 0 1 1-8.9-11z"/>
</svg>
</button>
<button type="button" class="theme-toggle-btn" data-theme-value="light" aria-pressed="false" title="亮色主题">
<svg class="theme-icon" viewBox="0 0 24 24" width="18" height="18" aria-hidden="true" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round">
<circle cx="12" cy="12" r="4"/><path d="M12 2v2M12 20v2M4.93 4.93l1.41 1.41M17.66 17.66l1.41 1.41M2 12h2M20 12h2M4.93 19.07l1.41-1.41M17.66 6.34l1.41-1.41"/>
</svg>
</button>
</div>
</div>
<div class="instance-toolbar-filter list-window-bar">
<span class="list-window-label">列表筛选(<strong>UTC</strong>,默认当日):{{ list_window.label }}</span>
<label>预设
<select id="win-preset-select" onchange="toggleListWindowCustom()">
<option value="utc_today" {% if list_window.preset == 'utc_today' %}selected{% endif %}>UTC 当日</option>
<option value="utc_last24h" {% if list_window.preset == 'utc_last24h' %}selected{% endif %}>近 24 小时</option>
<option value="utc_last7d" {% if list_window.preset == 'utc_last7d' %}selected{% endif %}>近 7 天</option>
<option value="custom" {% if list_window.preset == 'custom' %}selected{% endif %}>自定义</option>
</select>
</label>
<span id="win-custom-range" style="{% if list_window.preset != 'custom' %}display:none{% endif %}">
<label>起(UTC) <input type="datetime-local" id="win-from-utc" value="{{ list_window.start_utc.strftime('%Y-%m-%dT%H:%M') }}"></label>
<label>止(UTC) <input type="datetime-local" id="win-to-utc" value="{{ list_window.end_utc.strftime('%Y-%m-%dT%H:%M') }}"></label>
</span>
<button type="button" class="list-window-apply" onclick="applyListWindow()">应用</button>
<span class="list-window-hint">统计页仍按北京时间 {{ stats_bundle.stats_reset_hour|default(reset_hour) }}:00 切日</span>
</div>
</div>
+23 -21
View File
@@ -1,7 +1,7 @@
{# 系统设置:风控说明 · 数据导出 · 资金划转 #}
{# 系统设置:风控说明 · 右资金划转 + 数据导出 #}
<div class="settings-page">
<div class="settings-cards-grid">
<div class="card settings-card">
<div class="card settings-card settings-card--risk">
<h2>风控说明</h2>
<p class="settings-live-status">
当前账户状态:
@@ -36,26 +36,28 @@
{% endfor %}
</div>
<div class="card settings-card">
<h2>数据导出</h2>
<p class="settings-card-desc">
CSV · UTF-8 · v{{ instance_settings.data_export_version }}。
交易记录含开仓类型列;复盘单独导出。
</p>
<div class="settings-link-list">
<a class="settings-export-link" href="/export/trade_records">交易记录</a>
<a class="settings-export-link" href="/export/journal_entries">复盘记录</a>
<a class="settings-export-link" href="/export/key_monitors">关键位(当前)</a>
<a class="settings-export-link" href="/export/key_monitor_history">关键位历史</a>
<div class="settings-side-col">
{% if instance_settings.show_transfer %}
<div class="card settings-card">
<h2>资金划转</h2>
<p class="settings-card-desc">手动在资金账户与交易账户之间划转 USDT;自动划转规则见下方说明。</p>
{% include 'instance_transfer_panel.html' %}
</div>
{% endif %}
<div class="card settings-card">
<h2>数据导出</h2>
<p class="settings-card-desc">
CSV · UTF-8 · v{{ instance_settings.data_export_version }}。
交易记录含开仓类型列;复盘单独导出。
</p>
<div class="settings-link-list">
<a class="settings-export-link" href="/export/trade_records">交易记录</a>
<a class="settings-export-link" href="/export/journal_entries">复盘记录</a>
<a class="settings-export-link" href="/export/key_monitors">关键位(当前)</a>
<a class="settings-export-link" href="/export/key_monitor_history">关键位历史</a>
</div>
</div>
</div>
{% if instance_settings.show_transfer %}
<div class="card settings-card">
<h2>资金划转</h2>
<p class="settings-card-desc">手动在资金账户与交易账户之间划转 USDT;自动划转规则见下方说明。</p>
{% include 'instance_transfer_panel.html' %}
</div>
{% endif %}
</div>
</div>