From e9e291e063da11d583e31152092743f6caff0318 Mon Sep 17 00:00:00 2001 From: Lxy Date: Mon, 22 Jun 2026 23:51:59 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E9=87=8D=E6=9E=84=E4=BA=A4=E6=98=93?= =?UTF-8?q?=E5=A4=8D=E7=9B=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/main.py | 6 - app/static/futures_analysis.html | 327 +++---- app/static/futures_analysis.js | 1479 +++++++++++++----------------- data/trade_review.html | 409 +++++++++ 4 files changed, 1222 insertions(+), 999 deletions(-) create mode 100644 data/trade_review.html diff --git a/app/main.py b/app/main.py index ab7787b..a34bd37 100644 --- a/app/main.py +++ b/app/main.py @@ -142,12 +142,6 @@ def review_plan_page(): return FileResponse(str(STATIC_DIR / "review_plan.html")) -@app.get("/trade-review") -def trade_review_page(): - """交易复盘页面""" - return FileResponse(str(STATIC_DIR / "trade_review.html")) - - @app.get("/api/v1/health") def health(): return {"status": "ok", "service": "market-data-buffer"} diff --git a/app/static/futures_analysis.html b/app/static/futures_analysis.html index 6fff8e0..b36717c 100644 --- a/app/static/futures_analysis.html +++ b/app/static/futures_analysis.html @@ -503,85 +503,73 @@ .tr-btn-danger:hover { background: rgba(255,59,48,0.2); } .tr-date-input { background: #fff; border: 1px solid rgba(0,0,0,0.05); border-radius: 12px; padding: 0 14px; height: 40px; font-size: 13px; color: var(--text-primary); box-shadow: var(--shadow-sm); outline: none; font-family: inherit; } .tr-date-input:focus { border-color: var(--color-brand); box-shadow: 0 0 0 3px rgba(0,122,255,0.15); } - .tr-select { background: #fff; border: 1px solid rgba(0,0,0,0.05); border-radius: 12px; padding: 0 14px; height: 40px; font-size: 13px; color: var(--text-primary); box-shadow: var(--shadow-sm); outline: none; font-family: inherit; cursor: pointer; } - .tr-kline-tab { padding: 8px 16px; border-radius: 8px; font-size: 13px; font-weight: 500; background: #fff; color: var(--text-secondary); border: 1px solid rgba(0,0,0,0.05); cursor: pointer; transition: all 0.2s; box-shadow: var(--shadow-sm); } - .tr-kline-tab:hover { background: var(--color-brand); color: #fff; border-color: var(--color-brand); } - .tr-kline-tab.active { background: var(--color-brand); color: #fff; border-color: var(--color-brand); box-shadow: 0 4px 10px rgba(0,122,255,0.2); } - .tr-sub-nav { display: flex; gap: 8px; margin-bottom: 20px; overflow-x: auto; padding-bottom: 4px; } - .tr-sub-nav-item { padding: 8px 18px; border-radius: 9999px; font-size: 13px; background: #fff; color: var(--text-secondary); cursor: pointer; white-space: nowrap; transition: all 0.2s; text-decoration: none; box-shadow: var(--shadow-sm); font-weight: 500; } - .tr-sub-nav-item:hover { background: var(--color-brand); color: #fff; } - .tr-sub-nav-item.active { background: var(--color-brand); color: #fff; box-shadow: 0 4px 10px rgba(0,122,255,0.2); } - - .tr-stats-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 14px; margin-bottom: 20px; } - .tr-stat-card { background: var(--bg-card); border-radius: 16px; padding: 18px; text-align: center; box-shadow: var(--shadow-sm); transition: transform 0.2s; } + /* 6列统计卡片 */ + .tr-stats-grid { display: grid; grid-template-columns: repeat(6, 1fr); gap: 14px; margin-bottom: 24px; } + .tr-stat-card { background: var(--bg-card); border-radius: var(--radius-card); padding: 18px; text-align: center; box-shadow: var(--shadow-sm); transition: transform 0.2s; } .tr-stat-card:hover { transform: translateY(-2px); box-shadow: var(--shadow-md); } - .tr-stat-label { font-size: 11px; color: var(--text-tertiary); margin-bottom: 6px; text-transform: uppercase; font-weight: 600; } - .tr-stat-value { font-size: 22px; font-weight: 700; } + .tr-stat-label { font-size: 11px; color: var(--text-tertiary); margin-bottom: 6px; font-weight: 600; } + .tr-stat-value { font-size: 24px; font-weight: 700; margin-bottom: 4px; } .tr-stat-value.profit { color: var(--color-down); } .tr-stat-value.loss { color: var(--color-up); } .tr-stat-sub { font-size: 12px; color: var(--text-tertiary); margin-top: 4px; } - .tr-sub-page { display: none; } - .tr-sub-page.active { display: block; } + /* 图表容器 */ + .tr-chart-box { background: var(--bg-card); border-radius: var(--radius-card); padding: 20px; margin-bottom: 24px; box-shadow: var(--shadow-sm); } + .tr-chart-title { font-size: 16px; font-weight: 600; color: var(--text-primary); margin-bottom: 16px; } + .tr-chart-container { width: 100%; height: 350px; } + .tr-bubble-container { width: 100%; height: 400px; } + /* 表格 */ + .tr-tbl-box { background: var(--bg-card); border-radius: var(--radius-card); padding: 20px; margin-bottom: 24px; box-shadow: var(--shadow-sm); overflow-x: auto; } + .tr-tbl-title { font-size: 16px; font-weight: 600; color: var(--text-primary); margin-bottom: 16px; } .tr-table { width: 100%; border-collapse: collapse; font-size: 13px; } - .tr-table th { background: #F5F5F7; padding: 10px 12px; text-align: left; font-weight: 600; color: var(--text-tertiary); font-size: 12px; white-space: nowrap; } - .tr-table td { padding: 9px 12px; border-bottom: 1px solid rgba(0,0,0,0.04); color: var(--text-primary); white-space: nowrap; } + .tr-table th { background: #F5F5F7; padding: 12px 8px; text-align: left; font-weight: 600; color: var(--text-tertiary); font-size: 12px; white-space: nowrap; border-bottom: 1px solid rgba(0,0,0,0.06); } + .tr-table td { padding: 12px 8px; border-bottom: 1px solid rgba(0,0,0,0.04); color: var(--text-primary); white-space: nowrap; } .tr-table tbody tr { transition: background 0.15s; } .tr-table tbody tr:hover { background: rgba(0,122,255,0.03); } .tr-pnl-positive { color: var(--color-down); font-weight: 600; } .tr-pnl-negative { color: var(--color-up); font-weight: 600; } - .tr-dir-buy { color: var(--color-down); font-weight: 500; } - .tr-dir-sell { color: var(--color-up); font-weight: 500; } - - .tr-pagination { display: flex; justify-content: center; align-items: center; gap: 8px; margin-top: 16px; } - .tr-pagination button { padding: 6px 14px; border-radius: 8px; border: 1px solid rgba(0,0,0,0.08); background: #fff; font-size: 12px; cursor: pointer; transition: all 0.2s; } - .tr-pagination button:hover { background: var(--color-brand); color: #fff; border-color: var(--color-brand); } - .tr-pagination button:disabled { opacity: 0.4; cursor: default; } - .tr-pagination span { font-size: 12px; color: var(--text-tertiary); } - - .tr-empty { display: flex; flex-direction: column; align-items: center; justify-content: center; min-height: 300px; gap: 12px; } - .tr-empty-icon { font-size: 56px; opacity: 0.3; } - .tr-empty-text { font-size: 15px; color: var(--text-tertiary); } + .tr-link { color: var(--color-brand); cursor: pointer; text-decoration: none; font-weight: 500; } + .tr-link:hover { text-decoration: underline; } - .tr-kline-controls { display: flex; gap: 10px; margin-bottom: 16px; align-items: center; } - .tr-kline-chart { width: 100%; height: 500px; background: var(--bg-card); border-radius: 16px; box-shadow: var(--shadow-sm); } - .tr-chart-container { width: 100%; height: 300px; margin-bottom: 16px; background: var(--bg-card); border-radius: 16px; box-shadow: var(--shadow-sm); } - - /* 交易详情弹窗样式 */ - .tr-detail-info { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 12px; margin-bottom: 20px; padding: 16px; background: #F5F5F7; border-radius: 12px; } - .tr-detail-info-item { display: flex; flex-direction: column; gap: 4px; } - .tr-detail-info-label { font-size: 12px; color: var(--text-tertiary); font-weight: 500; } - .tr-detail-info-value { font-size: 14px; font-weight: 600; color: var(--text-primary); } - .tr-detail-info-value.profit { color: var(--color-down); } - .tr-detail-info-value.loss { color: var(--color-up); } - .tr-detail-section { margin-top: 20px; } - .tr-detail-section-title { font-size: 15px; font-weight: 700; color: var(--text-primary); margin-bottom: 12px; padding-left: 8px; border-left: 3px solid var(--accent-gold); } - .tr-detail-ai-content { padding: 16px; background: #F5F5F7; border-radius: 12px; min-height: 100px; font-size: 14px; line-height: 1.8; color: var(--text-primary); white-space: pre-wrap; } - .tr-pair-symbol-link { cursor: pointer; color: var(--accent-gold); text-decoration: none; font-weight: 700; } - .tr-pair-symbol-link:hover { text-decoration: underline; } - - .tr-pairs-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(340px, 1fr)); gap: 16px; } - .tr-pair-card { background: var(--bg-card); border-radius: 16px; padding: 18px; box-shadow: var(--shadow-sm); transition: all 0.2s; position: relative; overflow: hidden; } - .tr-pair-card:hover { box-shadow: var(--shadow-md); transform: translateY(-2px); } - .tr-pair-card::before { content: ""; position: absolute; top: 0; left: 0; right: 0; height: 3px; } - .tr-pair-card.profit::before { background: var(--color-down); } - .tr-pair-card.loss::before { background: var(--color-up); } - .tr-pair-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 12px; } - .tr-pair-symbol { font-size: 15px; font-weight: 700; color: var(--text-primary); } - .tr-pair-pnl { font-size: 16px; font-weight: 700; padding: 4px 12px; border-radius: 8px; } - .tr-pair-pnl.profit { color: var(--color-down); background: rgba(52,199,89,0.1); } - .tr-pair-pnl.loss { color: var(--color-up); background: rgba(255,59,48,0.1); } - .tr-pair-info { display: grid; grid-template-columns: 1fr 1fr; gap: 6px; font-size: 12px; } - .tr-pair-info-item { display: flex; justify-content: space-between; padding: 4px 8px; background: #F5F5F7; border-radius: 6px; } - .tr-pair-info-label { color: var(--text-tertiary); } - .tr-pair-info-value { font-weight: 600; color: var(--text-primary); } - .tr-pair-actions { margin-top: 12px; display: flex; gap: 8px; } - .tr-pair-actions button { flex: 1; padding: 8px; border-radius: 8px; border: none; font-size: 12px; font-weight: 600; cursor: pointer; transition: all 0.2s; font-family: inherit; } - .tr-pair-btn-analyze { background: rgba(175,82,222,0.1); color: var(--color-ai); } - .tr-pair-btn-analyze:hover { background: rgba(175,82,222,0.2); } + /* K线周期按钮 */ + .tr-kline-tabs { display: flex; gap: 8px; margin-bottom: 16px; align-items: center; } + .tr-kline-tab { padding: 6px 14px; border: 1px solid rgba(0,0,0,0.08); background: #fff; border-radius: 6px; cursor: pointer; font-size: 13px; font-weight: 500; color: var(--text-secondary); transition: all 0.2s; font-family: inherit; } + .tr-kline-tab:hover { background: var(--color-brand); color: #fff; border-color: var(--color-brand); } + .tr-kline-tab.active { background: var(--color-brand); color: #fff; border-color: var(--color-brand); box-shadow: 0 4px 10px rgba(0,122,255,0.2); } + /* 弹窗通用样式(复用 rv-modal 体系) */ + .tr-modal-overlay { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.5); backdrop-filter: blur(8px); z-index: 2000; display: none; align-items: center; justify-content: center; } + .tr-modal-overlay.show { display: flex; } + .tr-modal { background: #fff; border-radius: 20px; width: 90%; max-width: 1000px; max-height: 90vh; overflow-y: auto; box-shadow: 0 25px 50px rgba(0,0,0,0.25); animation: rv-modal-in 0.25s ease; } + .tr-modal-header { display: flex; justify-content: space-between; align-items: center; padding: 20px 24px; border-bottom: 1px solid rgba(0,0,0,0.06); } + .tr-modal-title { font-size: 18px; font-weight: 700; color: var(--text-primary); } + .tr-modal-close { width: 32px; height: 32px; border-radius: 50%; border: none; background: #F5F5F7; font-size: 16px; cursor: pointer; display: flex; align-items: center; justify-content: center; color: var(--text-secondary); transition: all 0.2s; } + .tr-modal-close:hover { background: #E5E5E7; } + .tr-modal-body { padding: 24px; } + + /* 弹窗内概览网格 */ + .tr-overview-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; margin-bottom: 24px; } + .tr-overview-item { background: #F5F5F7; border-radius: 12px; padding: 16px; text-align: center; } + .tr-overview-label { font-size: 12px; color: var(--text-tertiary); margin-bottom: 4px; } + .tr-overview-value { font-size: 20px; font-weight: 700; color: var(--text-primary); } + .tr-overview-value.profit { color: var(--color-down); } + .tr-overview-value.loss { color: var(--color-up); } + + /* AI诊断框 */ + .tr-ai-box { background: linear-gradient(135deg, #f0f7ff 0%, #e6f4ff 100%); border: 1px solid #bae0ff; border-radius: 12px; padding: 20px; margin-bottom: 24px; } + .tr-ai-title { font-size: 16px; font-weight: 600; color: #0958d9; margin-bottom: 12px; display: flex; align-items: center; gap: 8px; } + .tr-ai-content { font-size: 14px; color: var(--text-primary); line-height: 1.8; white-space: pre-wrap; } + .tr-ai-tag { display: inline-block; background: #e6f4ff; color: #0958d9; padding: 2px 8px; border-radius: 4px; font-size: 12px; margin-right: 8px; margin-bottom: 8px; } + + /* 品种详情弹窗内K线 */ + .tr-kline-chart { width: 100%; height: 400px; } + + /* 每日详情 - 品种分区 */ + .tr-variety-section { margin-top: 24px; border-top: 1px solid rgba(0,0,0,0.06); padding-top: 20px; } + + /* 批次管理 */ .tr-batch-item { display: flex; justify-content: space-between; align-items: center; padding: 14px 16px; background: #F5F5F7; border-radius: 12px; margin-bottom: 10px; } .tr-batch-info { flex: 1; } .tr-batch-file { font-size: 14px; font-weight: 600; color: var(--text-primary); margin-bottom: 4px; } @@ -589,9 +577,17 @@ .tr-batch-delete { padding: 6px 14px; border-radius: 8px; border: none; background: rgba(255,59,48,0.1); color: var(--color-up); font-size: 12px; font-weight: 600; cursor: pointer; transition: all 0.2s; } .tr-batch-delete:hover { background: rgba(255,59,48,0.2); } + /* 空状态 */ + .tr-empty { display: flex; flex-direction: column; align-items: center; justify-content: center; min-height: 200px; gap: 12px; } + .tr-empty-icon { font-size: 56px; opacity: 0.3; } + .tr-empty-text { font-size: 15px; color: var(--text-tertiary); } + + @media (max-width: 1200px) { + .tr-stats-grid { grid-template-columns: repeat(3, 1fr); } + } @media (max-width: 768px) { .tr-stats-grid { grid-template-columns: repeat(2, 1fr); } - .tr-pairs-grid { grid-template-columns: 1fr; } + .tr-overview-grid { grid-template-columns: repeat(2, 1fr); } } @media (max-width: 768px) { @@ -1004,118 +1000,148 @@ - - - - +
- -
-
- - - - - - - - - -
日期时间类型合约品种买卖开平价格手数成交额平仓盈亏手续费文件
-
-
- + +
+
账户权益曲线(累计净盈亏 + 每日盈亏)
+
- -
-
-
- - - - - - - - - -
日期交易笔数净盈亏手续费盈利笔亏损笔胜率最大盈利最大亏损品种数
-
+ +
+
品种盈亏分布(气泡大小=手续费占比,颜色=净盈亏)
+
+
+ + +
+
每日交易详情(点击日期查看详情)
+ + + + + + + + + +
日期笔数平仓盈亏手续费净盈亏盈利笔亏损笔胜率最大盈利最大亏损品种数
- -
-
- - - - - - - - - -
品种名称交易笔数净盈亏平仓盈亏手续费总手数买入卖出胜率
-
+ +
+
品种盈亏排行(点击查看品种详情)
+ + + + + + + + + +
排名代码名称净盈亏平仓盈亏手续费胜率盈亏比笔数操作
+
- -
-
-