diff --git a/lib/common/static/instance_page.css b/lib/common/static/instance_page.css index 01e3131..adee9a2 100644 --- a/lib/common/static/instance_page.css +++ b/lib/common/static/instance_page.css @@ -166,6 +166,37 @@ .list-window-bar label{color:#9aa;display:flex;align-items:center;gap:6px} .stats-segment-block{margin-top:20px;padding-top:14px;border-top:1px solid #3a4468} .stats-segment-block h2{font-size:1.05rem;color:#dbe4ff;margin-bottom:8px} + .stats-period-tabs{display:flex;flex-wrap:wrap;gap:8px;margin-bottom:12px} + .stats-period-tab{background:#151a2a;color:#9aa3bf;border:1px solid #304164;border-radius:8px;padding:7px 14px;font-size:.84rem;cursor:pointer;transition:background .15s,border-color .15s,color .15s} + .stats-period-tab:hover{background:#1c2438;color:#cfd3ef} + .stats-period-tab.active{background:#1f3a5a;color:#8fc8ff;border-color:#3d5f8a;font-weight:600} + .stats-period-pane[hidden]{display:none!important} + .stats-period-range{font-size:.78rem;color:#8892b0;margin-bottom:12px;line-height:1.45} + .inst-stats-viz{display:flex;flex-direction:column;gap:14px;margin-bottom:14px} + .inst-stats-kpis{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:10px} + .inst-stats-kpi{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:6px;padding:12px 10px;background:#151a2a;border:1px solid #2a3152;border-radius:10px;text-align:center;min-height:88px} + .inst-stats-kpi-val{font-size:1.15rem;font-weight:700;font-variant-numeric:tabular-nums;line-height:1.2} + .inst-stats-kpi-lbl{font-size:.72rem;color:#8892b0;line-height:1.3} + .inst-stats-ring{--win-pct:0;width:56px;height:56px;border-radius:50%;background:conic-gradient(#4cd97f 0 calc(var(--win-pct) * 1%),#ff6b6b calc(var(--win-pct) * 1%) 100%);display:flex;align-items:center;justify-content:center;position:relative} + .inst-stats-ring::before{content:"";position:absolute;inset:7px;border-radius:50%;background:#151a2a} + .inst-stats-ring-label{position:relative;z-index:1;font-size:.78rem;font-weight:700;font-variant-numeric:tabular-nums} + .inst-stats-block{padding:12px;background:#141923;border:1px solid #2a3150;border-radius:10px} + .inst-stats-block-title{font-size:.72rem;color:#8892b0;margin-bottom:8px} + .inst-stats-stacked-bar{display:flex;height:10px;border-radius:6px;overflow:hidden;background:#1e2438} + .inst-stats-stacked-fill{height:100%;min-width:0;transition:width .2s ease} + .inst-stats-stacked-fill--profit{background:#4cd97f} + .inst-stats-stacked-fill--loss{background:#ff6b6b} + .inst-stats-bar-labels{display:flex;justify-content:space-between;gap:10px;margin-top:8px;font-size:.76rem;font-variant-numeric:tabular-nums} + .inst-stats-risk-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:8px 12px} + .inst-stats-risk-item{display:flex;flex-direction:column;gap:3px;min-width:0} + .inst-stats-risk-item .k{font-size:.7rem;color:#8892b0} + .inst-stats-risk-item .v{font-size:.84rem;font-weight:600;font-variant-numeric:tabular-nums;color:#e8ecf4;word-break:break-word} + .inst-stats-empty{margin:0;padding:18px;text-align:center;color:#8892b0;font-size:.85rem;background:#141923;border:1px dashed #2a3348;border-radius:10px} + .inst-stats-details{margin-top:4px} + .inst-stats-details>summary{cursor:pointer;font-size:.84rem;color:#9aa3bf;padding:8px 0;user-select:none;list-style-position:inside} + .inst-stats-details>summary::-webkit-details-marker{color:#6d7689} + .inst-stats-details[open]>summary{margin-bottom:6px;color:#cfd3ef} + @media (max-width:640px){.inst-stats-kpis{grid-template-columns:1fr}.inst-stats-risk-grid{grid-template-columns:1fr}} .key-history{margin-top:12px;padding-top:10px;border-top:1px solid #2a3150} .key-history h3{font-size:.88rem;color:#b8c4ff;margin-bottom:6px} .key-history .sub{font-size:.72rem;color:#8892b0;margin-bottom:6px} diff --git a/lib/common/static/instance_stats.js b/lib/common/static/instance_stats.js new file mode 100644 index 0000000..67dabcb --- /dev/null +++ b/lib/common/static/instance_stats.js @@ -0,0 +1,96 @@ +(function (global) { + "use strict"; + + var PERIODS = ["day", "week", "month"]; + + function statsSegmentSelect() { + return document.getElementById("stats-segment-select"); + } + + function activeSegmentPanel() { + var sel = statsSegmentSelect(); + if (!sel) return null; + var key = sel.value; + return document.querySelector( + '.stats-segment-panel[data-stats-segment="' + key + '"]' + ); + } + + function replaceStatsUrl(params) { + var q = new URLSearchParams(global.location.search); + Object.keys(params).forEach(function (k) { + if (params[k] == null || params[k] === "") q.delete(k); + else q.set(k, params[k]); + }); + var qs = q.toString(); + global.history.replaceState( + null, + "", + qs ? global.location.pathname + "?" + qs : global.location.pathname + ); + } + + function switchStatsPeriod(periodKey) { + var panel = activeSegmentPanel(); + if (!panel) return; + var key = PERIODS.indexOf(periodKey) >= 0 ? periodKey : "day"; + panel.querySelectorAll(".stats-period-pane").forEach(function (pane) { + var match = pane.getAttribute("data-stats-period") === key; + if (match) pane.removeAttribute("hidden"); + else pane.setAttribute("hidden", ""); + }); + panel.querySelectorAll(".stats-period-tab").forEach(function (btn) { + var on = btn.getAttribute("data-stats-period") === key; + btn.classList.toggle("active", on); + btn.setAttribute("aria-selected", on ? "true" : "false"); + }); + replaceStatsUrl({ stats_period: key }); + } + + function switchStatsSegment() { + var sel = statsSegmentSelect(); + if (!sel) return; + var key = sel.value; + document.querySelectorAll(".stats-segment-panel").forEach(function (p) { + p.style.display = + p.getAttribute("data-stats-segment") === key ? "block" : "none"; + }); + replaceStatsUrl({ stats_segment: key }); + var period = + new URLSearchParams(global.location.search).get("stats_period") || "day"; + switchStatsPeriod(period); + } + + function bindPeriodTabs() { + document.querySelectorAll(".stats-period-tab").forEach(function (btn) { + if (btn.getAttribute("data-stats-bound") === "1") return; + btn.setAttribute("data-stats-bound", "1"); + btn.addEventListener("click", function () { + switchStatsPeriod(btn.getAttribute("data-stats-period") || "day"); + }); + }); + } + + function initStatsFromUrl() { + var sel = statsSegmentSelect(); + if (!sel) return; + bindPeriodTabs(); + var url = new URLSearchParams(global.location.search); + var segKey = url.get("stats_segment"); + if ( + segKey && + sel.querySelector('option[value="' + segKey.replace(/"/g, "") + '"]') + ) { + sel.value = segKey; + } + switchStatsSegment(); + var period = url.get("stats_period") || "day"; + if (PERIODS.indexOf(period) < 0) period = "day"; + switchStatsPeriod(period); + } + + global.switchStatsSegment = switchStatsSegment; + global.switchStatsPeriod = switchStatsPeriod; + global.initStatsFromUrl = initStatsFromUrl; + global.initStatsSegmentFromUrl = initStatsFromUrl; +})(window); diff --git a/lib/common/static/instance_theme.css b/lib/common/static/instance_theme.css index aa74a1e..8787d71 100644 --- a/lib/common/static/instance_theme.css +++ b/lib/common/static/instance_theme.css @@ -819,6 +819,46 @@ html[data-theme="light"] .stats-period-block { border-bottom-color: #d0dae4 !important; } +html[data-theme="light"] .stats-period-tab { + background: #f4f7fb !important; + color: #4a6078 !important; + border-color: #c8d4e0 !important; +} +html[data-theme="light"] .stats-period-tab:hover { + background: #e8eef5 !important; + color: #142232 !important; +} +html[data-theme="light"] .stats-period-tab.active { + background: #dce8f5 !important; + color: #0d4a7a !important; + border-color: #7eb0d8 !important; +} +html[data-theme="light"] .stats-period-range, +html[data-theme="light"] .inst-stats-kpi-lbl, +html[data-theme="light"] .inst-stats-block-title, +html[data-theme="light"] .inst-stats-risk-item .k, +html[data-theme="light"] .inst-stats-empty { + color: #4a6078 !important; +} +html[data-theme="light"] .inst-stats-kpi, +html[data-theme="light"] .inst-stats-block { + background: #f8fafc !important; + border-color: #c8d4e0 !important; +} +html[data-theme="light"] .inst-stats-ring::before { + background: #f8fafc !important; +} +html[data-theme="light"] .inst-stats-stacked-bar { + background: #e2e8f0 !important; +} +html[data-theme="light"] .inst-stats-risk-item .v, +html[data-theme="light"] .inst-stats-details > summary { + color: #142232 !important; +} +html[data-theme="light"] .inst-stats-details[open] > summary { + color: #0d4a7a !important; +} + html[data-theme="light"] .key-history { border-top-color: #d0dae4 !important; } diff --git a/lib/instance/templates/embed_boot_scripts.html b/lib/instance/templates/embed_boot_scripts.html index 6068b74..79a6b55 100644 --- a/lib/instance/templates/embed_boot_scripts.html +++ b/lib/instance/templates/embed_boot_scripts.html @@ -597,29 +597,6 @@ function recomputeJournalRealRr(){ } -function switchStatsSegment(){ - const sel = document.getElementById("stats-segment-select"); - if(!sel) return; - const key = sel.value; - document.querySelectorAll(".stats-segment-panel").forEach(p=>{ - p.style.display = p.getAttribute("data-stats-segment") === key ? "block" : "none"; - }); - const q = new URLSearchParams(window.location.search); - q.set("stats_segment", key); - const qs = q.toString(); - history.replaceState(null, "", qs ? (window.location.pathname + "?" + qs) : window.location.pathname); -} - -function initStatsSegmentFromUrl(){ - const sel = document.getElementById("stats-segment-select"); - if(!sel) return; - const key = new URLSearchParams(window.location.search).get("stats_segment"); - if(key && sel.querySelector('option[value="' + key.replace(/"/g, "") + '"]')){ - sel.value = key; - } - switchStatsSegment(); -} - function toggleStatsCard(){ const card = document.getElementById("stats-card"); const btn = document.getElementById("stats-toggle-btn"); diff --git a/lib/instance/templates/embed_page_fragment.html b/lib/instance/templates/embed_page_fragment.html index 2dad742..41397f0 100644 --- a/lib/instance/templates/embed_page_fragment.html +++ b/lib/instance/templates/embed_page_fragment.html @@ -1,442 +1,541 @@ -{# Hub iframe tab fragment — shared via embed_templates #} -{% macro period_stats(title, s) %} -
-

{{ title }}

-
{{ s.range_label }}
-
-
开单次数
{{ s.opens_count }}
-
平仓笔数
{{ s.closed_count }}
-
胜率
{% if s.win_rate_pct is not none %}{{ s.win_rate_pct }}%{% else %}-{% endif %}
-
净盈亏(U)
{{ funds_fmt(s.net_pnl_u) }}
-
亏损额合计(U)
{{ funds_fmt(s.loss_sum_u) }}
-
单笔最大亏损(U)
{% if s.max_single_loss is not none %}{{ funds_fmt(s.max_single_loss) }}{% else %}-{% endif %}
-
单笔最大盈利(U)
{% if s.max_single_profit is not none %}{{ funds_fmt(s.max_single_profit) }}{% else %}-{% endif %}
-
最大回撤(U)
{{ funds_fmt(s.max_drawdown_u) }}
-
当前连续亏损笔数
{{ s.consecutive_losses }}
-
最长连续亏损(交易日)
{{ s.max_loss_streak_days }} 天
-
期内最大亏损日
{% if s.worst_day %}{{ s.worst_day }}({{ funds_fmt(s.worst_day_pnl) }}U){% else %}-{% endif %}
-
-
-{% endmacro %} -
- {% if page == 'key_monitor' %} - {% include 'key_monitor_panel.html' %} - {% elif page == 'trade' %} -
-
-
-

实盘下单监控

- {% if focus_order_id %} - 放大查看K线(100根) - {% else %} - 暂无持仓可放大 - {% endif %} -
- {% include order_rule_tips_tpl %} -
- {% from 'trade_policy_fields.html' import trade_policy_symbol, trade_policy_direction with context %} - {{ trade_policy_symbol('symbol', 'order-symbol') }} - {{ trade_policy_direction('direction', 'order-direction') }} - - {% from 'order_entry_model_fields.html' import order_entry_type_fields with context %} - {{ order_entry_type_fields() }} - {% from 'order_leverage_fields.html' import order_leverage_fields with context %} - {{ order_leverage_fields() }} - {% if not intraday_discipline %} - - - - - - {% else %} - - {% endif %} - - {% from 'symbol_live_price_snippet.html' import symbol_live_price_hint %} - {{ symbol_live_price_hint('order-symbol-live-price', 'order-symbol', 'order-direction') }} - 下单成交价以交易所成交回报为准 - - - - - - -
- {% include 'order_plan_preview_bar.html' %} -
-
-

实时持仓

-
- {% for o in order %} -
-
-
- {{ o.exchange_symbol or o.symbol }} - {% if o.time_close_enabled %} - - 时间平仓 {{ o.time_close_hours or '' }}h - · --:--:-- - - {% endif %} - {% include 'force_close_order_badge.html' %} - {{ '做多' if o.direction == 'long' else '做空' }} -
-
- {% if not intraday_discipline %} - - 平仓 - {% endif %} -
-
-
- 来源: {{ o.monitor_type|default('下单监控', true) }}{% if o.key_signal_type %} · {{ o.key_signal_type }}{% endif %} - {% if o.entry_model_label %}开仓: {{ o.entry_model_label }}{% elif intraday_discipline %}开仓: —{% else %}风格: {{ '波段单' if o.trade_style == 'swing' else '趋势单' }}{% endif %} - 风险: {% if position_sizing_mode == 'full_margin' %}{{ funds_fmt(o.risk_amount) if o.risk_amount is not none else '-' }}U{% else %}{{ o.risk_percent or '-' }}%≈{{ funds_fmt(o.risk_amount) if o.risk_amount is not none else '-' }}U{% endif %} - - - {% if intraday_discipline %} - {% elif o.breakeven_enabled %}移动保本:开 {{ o.breakeven_rr_trigger or '-' }}R→{{ price_fmt(o.symbol, o.breakeven_price) }}{% else %}移动保本:关{% endif %} - - -
-
-
- 成交价 - {{ price_fmt(o.symbol, o.trigger_price) }} -
-
- 止损 - {{ price_fmt(o.symbol, o.stop_loss) if o.stop_loss else '—' }} -
-
- 止盈 - {{ price_fmt(o.symbol, o.take_profit) if o.take_profit else '—' }} -
-
- 盈亏比 - {% if o.rr_ratio is not none %}{{ '%g'|format(o.rr_ratio) }}:1{% else %}-:1{% endif %} -
-
- 张数 - {% if o.order_amount is not none %}{{ '%.2f'|format(o.order_amount) }}{% else %}—{% endif %} -
-
- 盈利金额 - -
-
- 标记价 - - -
-
- 浮盈亏 - - -
-
- -
-
交易所止盈止损
-
- 止损:加载中… - {% if not intraday_discipline %} - - {% endif %} -
-
- 止盈:加载中… - {% if not intraday_discipline %} - - {% endif %} -
-
-
- {% else %} -
暂无持仓
- {% endfor %} -
-
- -
-
-

挂止盈止损

-

将先撤销该合约已有 TP/SL,再按下列价格重挂.

-
- -
-
- - -
-
- - -
-
- - -
-
-
- -
- {% elif page in ('strategy', 'strategy_trend', 'strategy_roll') %} - {% include 'strategy_trading_page.html' %} - {% elif page == 'strategy_records' %} - {% include 'strategy_records_page.html' %} - {% elif page == 'options' %} - {% include 'options_panel.html' %} - {% endif %} - - - - {% if page == 'records' %} -
-

交易记录

-
- -
-
- - - {% for r in record %} - - {% set pnl_val = (r.pnl_amount or 0)|float %} - - - - - - {% set stop_show = r.display_open_stop_loss or r.initial_stop_loss or r.stop_loss %} - {% set tp_show = r.effective_take_profit or r.take_profit %} - - - - - - - - {% set pnl_val = (r.effective_pnl_amount or 0)|float %} - - - - - {% endfor %} -
品种下单类型开仓类型方向成交止损(开仓)止盈基数杠杆持仓分钟开仓时间(北京)平仓时间(北京)盈亏U结果操作
{{ r.symbol }}{{ r.monitor_type }}{% if r.key_signal_type %} · {{ r.key_signal_type }}{% endif %}{{ r.effective_entry_reason or '-' }}{{ '做多' if r.direction == 'long' else '做空' }}{{ price_fmt(r.symbol, r.trigger_price) }}{{ price_fmt(r.symbol, stop_show) }}{{ price_fmt(r.symbol, tp_show) }}{% if r.margin_capital is not none and r.margin_capital != '' %}{{ funds_fmt(r.margin_capital) }}{% else %}-{% endif %}{{ r.leverage or '-' }}{{ r.effective_hold_minutes or 0 }}{{ (r.effective_opened_at or '-')[:16] }}{{ (r.effective_closed_at or r.created_at or '-')[:16] }}{{ funds_fmt(r.effective_pnl_amount or 0) }}{% if r.display_pnl_source == 'exchange' %}{% elif r.display_pnl_source != 'reviewed' %}{% endif %} - {% set effective_result = r.effective_result %} - {% if effective_result in ["止盈","保本止盈","移动止盈"] %}{{ effective_result }} - {% elif effective_result in ["止损","强制清仓","手动平仓"] %}{{ effective_result }} - {% elif effective_result == "时间平仓" %}{{ effective_result }} - {% else %}{{ effective_result or '-' }}{% endif %} - - - - -
-
-
- -
-

交易复盘记录上传(含截图)

-
- - - - - - {% from 'journal_form_fields.html' import journal_form_fields %} - {{ journal_form_fields(entry_reason_options, order_type_options) }} - {% from 'journal_upload_slots.html' import journal_upload_slots %} - {{ journal_upload_slots() }} -
- - - - - - - - - -
-
双周期上下排列;截止=平仓时间:开仓前背景至平仓;截止=当前时间:最近 N 根至此刻(可看平仓后走势);标注开仓,平仓与止损位
-
- - - - - - -
- - -
-
- -
-
-

AI复盘(按交易记录)

- -
-
- - - - - - - -
- - -
-
- 交易复盘记录 -
-
-
- AI历史复盘 -
-
-
-
-
- - {% endif %} - - {% if page == 'env_config' %} - {% include 'env_config_panel.html' %} - {% endif %} - {% if page == 'risk_policy' %} - {% include 'risk_policy_panel.html' %} - {% endif %} - {% if page == 'settings' %} - {% include 'settings_panel.html' %} - {% endif %} - {% if page == 'stats' %} -
-
-

数据统计

- -
-
-
- 统计分析按北京时间 {{ stats_bundle.stats_reset_hour }}:00切日计入(与顶栏 UTC 列表窗无关).历史总开仓(累计): - {{ stats_bundle.total_opens_all }} 次 -
-
- -
- {% for seg in stats_bundle.segments %} - - {% endfor %} -
-
- {% endif %} +{# Hub iframe tab fragment — shared via embed_templates #} +{% macro period_stats_pane(period_key, s) %} +{% set win_pct = s.win_rate_pct if s.win_rate_pct is not none else 0 %} +{% set profit_sum = (s.net_pnl_u + s.loss_sum_u) if s.closed_count else 0 %} +{% set loss_sum = s.loss_sum_u %} +{% set pnl_total = profit_sum + loss_sum %} +{% set profit_bar_w = (profit_sum / pnl_total * 100) if pnl_total > 0 else 0 %} +{% set loss_bar_w = (loss_sum / pnl_total * 100) if pnl_total > 0 else 0 %} +{% set net_cls = 'pos-pnl-profit' if s.net_pnl_u > 0 else ('pos-pnl-loss' if s.net_pnl_u < 0 else '') %} +
+
{{ s.range_label }}
+
+ {% if s.closed_count %} +
+
+ {% if s.net_pnl_u > 0 %}+{% endif %}{{ funds_fmt(s.net_pnl_u) }}U + 净盈亏 +
+
+
+ {% if s.win_rate_pct is not none %}{{ win_pct|round(0)|int }}%{% else %}—{% endif %} +
+ {{ s.win_count }}胜 {{ s.loss_count }}负 +
+
+ {{ s.opens_count }} / {{ s.closed_count }} + 开单 / 平仓 +
+
+
+
盈亏构成
+
+
+
+
+
+ 盈利 {{ funds_fmt(profit_sum) }}U + 亏损 {{ funds_fmt(loss_sum) }}U +
+
+
+
+
+ 最大回撤 + {{ funds_fmt(s.max_drawdown_u) }}U +
+
+ 连续亏损 + {{ s.consecutive_losses }} 笔 +
+
+ 最长连亏日 + {{ s.max_loss_streak_days }} 天 +
+
+ 最大亏损日 + {% if s.worst_day %}{{ s.worst_day }} ({{ funds_fmt(s.worst_day_pnl) }}U){% else %}—{% endif %} +
+
+
+ {% else %} +

当前区间暂无平仓数据

+ {% endif %} +
+
+ 详细指标 +
+
开单次数
{{ s.opens_count }}
+
平仓笔数
{{ s.closed_count }}
+
胜率
{% if s.win_rate_pct is not none %}{{ s.win_rate_pct }}%{% else %}-{% endif %}
+
净盈亏(U)
{{ funds_fmt(s.net_pnl_u) }}
+
亏损额合计(U)
{{ funds_fmt(s.loss_sum_u) }}
+
单笔最大亏损(U)
{% if s.max_single_loss is not none %}{{ funds_fmt(s.max_single_loss) }}{% else %}-{% endif %}
+
单笔最大盈利(U)
{% if s.max_single_profit is not none %}{{ funds_fmt(s.max_single_profit) }}{% else %}-{% endif %}
+
最大回撤(U)
{{ funds_fmt(s.max_drawdown_u) }}
+
当前连续亏损笔数
{{ s.consecutive_losses }}
+
最长连续亏损(交易日)
{{ s.max_loss_streak_days }} 天
+
期内最大亏损日
{% if s.worst_day %}{{ s.worst_day }}({{ funds_fmt(s.worst_day_pnl) }}U){% else %}-{% endif %}
+
+
+
+{% endmacro %} +
+
+ env配置 + {% endif %} + 系统设置 + + {% with msg=get_flashed_messages() %}{% if msg %}
{{ msg[0] }}
{% endif %}{% endwith %} + + {% include 'instance_header_panel.html' %} + {% if page not in ('settings', 'risk_policy', 'env_config', 'options') %} + {% include 'instance_top_bar.html' %} + {% endif %} + +
+ {% if page == 'key_monitor' %} + {% include 'key_monitor_panel.html' %} + {% elif page == 'trade' %} +
+
+
+

实盘下单监控

+ {% if focus_order_id %} + 放大查看K线(100根) + {% else %} + 暂无持仓可放大 + {% endif %} +
+ {% include order_rule_tips_tpl %} +
+ {% from 'trade_policy_fields.html' import trade_policy_symbol, trade_policy_direction with context %} + {{ trade_policy_symbol('symbol', 'order-symbol') }} + {{ trade_policy_direction('direction', 'order-direction') }} + + {% from 'order_entry_model_fields.html' import order_entry_type_fields with context %} + {{ order_entry_type_fields() }} + {% from 'order_leverage_fields.html' import order_leverage_fields with context %} + {{ order_leverage_fields() }} + {% if not intraday_discipline %} + + + + + + {% else %} + + {% endif %} + + {% from 'symbol_live_price_snippet.html' import symbol_live_price_hint %} + {{ symbol_live_price_hint('order-symbol-live-price', 'order-symbol', 'order-direction') }} + 下单成交价以交易所成交回报为准 + + + + + + +
+ {% include 'order_plan_preview_bar.html' %} +
+
+

实时持仓

+ {% if ui_orphan_recovery_enabled %} + {% if not order and orphan_live_positions %} + {% set o = orphan_live_positions[0] %} +
+ 检测到交易所仍有 {{ o.symbol }} {{ '空' if o.direction == 'short' else '多' }}仓,但本地监控已中断(误同步时可能无交易记录). + {% if o.recoverable_monitor_id %} + + {% else %} + 未找到可恢复的监控记录,需在服务器数据库处理. + {% endif %} +
+ {% else %} + + {% endif %} + {% endif %} +
+ {% for o in order %} +
+
+
+ {{ o.exchange_symbol or o.symbol }} + {% if o.time_close_enabled %} + + 时间平仓 {{ o.time_close_hours or '' }}h + · --:--:-- + + {% endif %} + {% include 'force_close_order_badge.html' %} + {{ '做多' if o.direction == 'long' else '做空' }} +
+
+ {% if not intraday_discipline %} + + 平仓 + {% endif %} +
+
+
+ 来源: {{ o.monitor_type|default('下单监控', true) }}{% if o.key_signal_type %} · {{ o.key_signal_type }}{% endif %} + {% if o.entry_model_label %}开仓: {{ o.entry_model_label }}{% elif intraday_discipline %}开仓: —{% else %}风格: {{ '波段单' if o.trade_style == 'swing' else '趋势单' }}{% endif %} + 风险: {% if position_sizing_mode == 'full_margin' %}{{ funds_fmt(o.risk_amount) if o.risk_amount is not none else '-' }}U{% else %}{{ o.risk_percent or '-' }}%≈{{ funds_fmt(o.risk_amount) if o.risk_amount is not none else '-' }}U{% endif %} + + + {% if intraday_discipline %} + {% elif o.breakeven_enabled %}移动保本:开 {{ o.breakeven_rr_trigger or '-' }}R→{{ price_fmt(o.symbol, o.breakeven_price) }}{% else %}移动保本:关{% endif %} + + +
+
+
+ 成交价 + {{ price_fmt(o.symbol, o.trigger_price) }} +
+
+ 止损 + {{ price_fmt(o.symbol, o.stop_loss) if o.stop_loss else '—' }} +
+
+ 止盈 + {{ price_fmt(o.symbol, o.take_profit) if o.take_profit else '—' }} +
+
+ 盈亏比 + {% if o.rr_ratio is not none %}{{ '%g'|format(o.rr_ratio) }}:1{% else %}-:1{% endif %} +
+
+ 张数 + {% if o.order_amount is not none %}{{ '%.2f'|format(o.order_amount) }}{% else %}—{% endif %} +
+
+ 盈利金额 + +
+
+ 标记价 + - +
+
+ 浮盈亏 + - +
+
+ +
+
交易所止盈止损
+
+ 止损:加载中… + {% if not intraday_discipline %} + + {% endif %} +
+
+ 止盈:加载中… + {% if not intraday_discipline %} + + {% endif %} +
+
+
+ {% else %} +
暂无持仓
+ {% endfor %} +
+
+ +
+
+

挂止盈止损

+

将先撤销该合约已有 TP/SL,再按下列价格重挂.

+
+ +
+
+ + +
+
+ + +
+
+ + +
+
+
+ +
+ {% elif page in ('strategy', 'strategy_trend', 'strategy_roll') %} + {% include 'strategy_trading_page.html' %} + {% elif page == 'strategy_records' %} + {% include 'strategy_records_page.html' %} + {% elif page == 'options' %} + {% include 'options_panel.html' %} + {% endif %} + + + + {% if page == 'records' %} +
+

交易记录

+
+ +
+
+ + + {% for r in record %} + + {% set pnl_val = (r.pnl_amount or 0)|float %} + + + + + + {% set stop_show = r.display_open_stop_loss or r.initial_stop_loss or r.stop_loss %} + {% set tp_show = r.effective_take_profit or r.take_profit %} + + + + + + + + {% set pnl_val = (r.effective_pnl_amount or 0)|float %} + + + + + {% endfor %} +
品种下单类型开仓类型方向成交止损(开仓)止盈基数杠杆持仓分钟开仓时间(北京)平仓时间(北京)盈亏U结果操作
{{ r.symbol }}{{ r.monitor_type }}{% if r.key_signal_type %} · {{ r.key_signal_type }}{% endif %}{{ r.effective_entry_reason or '-' }}{{ '做多' if r.direction == 'long' else '做空' }}{{ price_fmt(r.symbol, r.trigger_price) }}{{ price_fmt(r.symbol, stop_show) }}{{ price_fmt(r.symbol, tp_show) }}{% if r.margin_capital is not none and r.margin_capital != '' %}{{ funds_fmt(r.margin_capital) }}{% else %}-{% endif %}{{ r.leverage or '-' }}{{ r.effective_hold_minutes or 0 }}{{ (r.effective_opened_at or '-')[:16] }}{{ (r.effective_closed_at or r.created_at or '-')[:16] }}{{ funds_fmt(r.effective_pnl_amount or 0) }}{% if r.display_pnl_source == 'exchange' %}{% elif r.display_pnl_source != 'reviewed' %}{% endif %} + {% set effective_result = r.effective_result %} + {% if effective_result in ["止盈","保本止盈","移动止盈"] %}{{ effective_result }} + {% elif effective_result in ["止损","强制清仓","手动平仓"] %}{{ effective_result }} + {% elif effective_result == "时间平仓" %}{{ effective_result }} + {% else %}{{ effective_result or '-' }}{% endif %} + + + + +
+
+
+ +
+

交易复盘记录上传(含截图)

+
+ + + + + + {% from 'journal_form_fields.html' import journal_form_fields %} + {{ journal_form_fields(entry_reason_options, order_type_options) }} + {% from 'journal_upload_slots.html' import journal_upload_slots %} + {{ journal_upload_slots() }} +
+ + + + + + + + + +
+
双周期上下排列;截止=平仓时间:开仓前背景至平仓;截止=当前时间:最近 N 根至此刻(可看平仓后走势);标注开仓,平仓与止损位
+
+ + + + + + +
+ + +
+
+ +
+
+

AI复盘(按交易记录)

+ +
+
+ + + + + + + +
+ + +
+
+ 交易复盘记录 +
+
+
+ AI历史复盘 +
+
+
+
+
+ + {% endif %} + + + {% if page == 'env_config' %} + {% include 'env_config_panel.html' %} + {% endif %} + + {% if page == 'risk_policy' %} + {% include 'risk_policy_panel.html' %} + {% endif %} + + {% if page == 'settings' %} + {% include 'settings_panel.html' %} + {% endif %} + + {% if page == 'stats' %} +
+
+

数据统计

+ +
+
+
+ 统计分析按北京时间 {{ stats_bundle.stats_reset_hour }}:00切日计入(与顶栏 UTC 列表窗无关).历史总开仓(累计): + {{ stats_bundle.total_opens_all }} 次 +
+
+ +
+ {% for seg in stats_bundle.segments %} + + {% endfor %} +
+
+ {% endif %} diff --git a/lib/instance/templates/embed_shell.html b/lib/instance/templates/embed_shell.html index 0331806..21ff920 100644 --- a/lib/instance/templates/embed_shell.html +++ b/lib/instance/templates/embed_shell.html @@ -6,8 +6,8 @@ - - + + {{ exchange_display }} · 加密货币 | 交易监控复盘系统 @@ -100,6 +100,7 @@ const ORDER_ENTRY_MODEL_CODE_TO_CATEGORY = {{ entry_model_code_to_category | toj + {% include 'embed_boot_scripts.html' %} +