Add complete dashboard design doc: SQLite schema, REST API, SSE, frontend layout
This commit is contained in:
+371
@@ -0,0 +1,371 @@
|
|||||||
|
# Dashboard Design
|
||||||
|
|
||||||
|
## 1. 目录结构
|
||||||
|
|
||||||
|
```
|
||||||
|
exchange-monitor-go/
|
||||||
|
├── main.go # 入口:启动 engine + web server
|
||||||
|
├── config.go # 配置加载(不变)
|
||||||
|
├── types.go # 公共类型(不变)
|
||||||
|
│
|
||||||
|
├── engine/ # 核心交易引擎(从 main.go 拆分)
|
||||||
|
│ ├── engine.go # Engine 结构体:组合所有模块
|
||||||
|
│ ├── scanner.go # 价差扫描(从 scanner.go 移入)
|
||||||
|
│ ├── trader.go # 交易执行(从 trader.go 移入)
|
||||||
|
│ ├── notifier.go # Telegram 通知(从 notifier.go 移入)
|
||||||
|
│ └── portfolio.go # 资金管理 + PnL 聚合
|
||||||
|
│
|
||||||
|
├── exchange/ # 交易所连接(不变)
|
||||||
|
│ └── ...
|
||||||
|
│
|
||||||
|
├── db/ # SQLite 持久化层(新增)
|
||||||
|
│ ├── db.go # DB 初始化、迁移
|
||||||
|
│ ├── trade_repo.go # 交易记录 CRUD
|
||||||
|
│ ├── order_repo.go # 订单明细 CRUD
|
||||||
|
│ └── config_repo.go # 配置快照
|
||||||
|
│
|
||||||
|
├── web/ # Web 仪表盘(新增)
|
||||||
|
│ ├── server.go # HTTP 服务器 + 路由
|
||||||
|
│ ├── handler_dashboard.go # 页面渲染
|
||||||
|
│ ├── handler_api.go # REST API
|
||||||
|
│ ├── handler_sse.go # SSE 实时推送
|
||||||
|
│ ├── static/ # 前端静态资源(go:embed)
|
||||||
|
│ │ ├── index.html
|
||||||
|
│ │ ├── app.js
|
||||||
|
│ │ └── style.css
|
||||||
|
│ └── ws_monitor.go # WS 状态监控
|
||||||
|
│
|
||||||
|
├── risk/ # 风控层(新增)
|
||||||
|
│ └── risk.go # 风控规则引擎
|
||||||
|
│
|
||||||
|
├── persistence.md # 本设计文档
|
||||||
|
└── ...
|
||||||
|
```
|
||||||
|
|
||||||
|
## 2. 数据模型 (SQLite)
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────────────────────────────────────────────┐
|
||||||
|
│ trades │
|
||||||
|
├──────────────┬──────────┬───────────────────────────┤
|
||||||
|
│ id │ INTEGER │ PRIMARY KEY AUTOINCREMENT │
|
||||||
|
│ coin │ TEXT │ NOT NULL │
|
||||||
|
│ direction │ TEXT │ BG->HL / HL->BG │
|
||||||
|
│ status │ TEXT │ open / closed │
|
||||||
|
│ entry_spread │ REAL │ 进场价差 % │
|
||||||
|
│ exit_spread │ REAL │ 出场价差 % │
|
||||||
|
│ long_ex │ TEXT │ 多腿交易所 │
|
||||||
|
│ short_ex │ TEXT │ 空腿交易所 │
|
||||||
|
│ long_entry │ REAL │ 多腿进场价 │
|
||||||
|
│ long_exit │ REAL │ 多腿出场价 │
|
||||||
|
│ short_entry │ REAL │ 空腿进场价 │
|
||||||
|
│ short_exit │ REAL │ 空腿出场价 │
|
||||||
|
│ long_pnl │ REAL │ 多腿 PnL % │
|
||||||
|
│ short_pnl │ REAL │ 空腿 PnL % │
|
||||||
|
│ fee_entry │ REAL │ 开仓手续费 % │
|
||||||
|
│ fee_exit │ REAL │ 平仓手续费 % │
|
||||||
|
│ net_pnl │ REAL │ 净利 % │
|
||||||
|
│ amount_usd │ REAL │ 总金额 $ │
|
||||||
|
│ scale_count │ INTEGER │ 加仓次数 │
|
||||||
|
│ exit_reason │ TEXT │ 止盈/止损/超时 │
|
||||||
|
│ convergence │ TEXT │ 收敛/发散/持平 │
|
||||||
|
│ opened_at │ DATETIME │ │
|
||||||
|
│ closed_at │ DATETIME │ │
|
||||||
|
└──────────────┴──────────┴───────────────────────────┘
|
||||||
|
|
||||||
|
┌─────────────────────────────────────────────────────┐
|
||||||
|
│ orders (每腿一条) │
|
||||||
|
├──────────────┬──────────┬───────────────────────────┤
|
||||||
|
│ id │ INTEGER │ │
|
||||||
|
│ trade_id │ INTEGER │ FK → trades.id │
|
||||||
|
│ leg │ TEXT │ long / short │
|
||||||
|
│ type │ TEXT │ entry / exit / scale │
|
||||||
|
│ exchange │ TEXT │ │
|
||||||
|
│ side │ TEXT │ buy / sell │
|
||||||
|
│ price │ REAL │ 成交价 │
|
||||||
|
│ size │ REAL │ 数量 │
|
||||||
|
│ fee │ REAL │ 手续费 │
|
||||||
|
│ order_id │ TEXT │ 交易所订单 ID │
|
||||||
|
│ status │ TEXT │ filled / cancelled │
|
||||||
|
│ created_at │ DATETIME │ │
|
||||||
|
└──────────────┴──────────┴───────────────────────────┘
|
||||||
|
|
||||||
|
┌─────────────────────────────────────────────────────┐
|
||||||
|
│ price_snapshots │
|
||||||
|
├──────────────┬──────────┬───────────────────────────┤
|
||||||
|
│ id │ INTEGER │ │
|
||||||
|
│ coin │ TEXT │ │
|
||||||
|
│ exchange │ TEXT │ │
|
||||||
|
│ price │ REAL │ │
|
||||||
|
│ bid │ REAL │ │
|
||||||
|
│ ask │ REAL │ │
|
||||||
|
│ spread_basis │ REAL │ bid-ask spread % │
|
||||||
|
│ recorded_at │ DATETIME │ │
|
||||||
|
└──────────────┴──────────┴───────────────────────────┘
|
||||||
|
|
||||||
|
┌─────────────────────────────────────────────────────┐
|
||||||
|
│ config_snapshots │
|
||||||
|
├──────────────┬──────────┬───────────────────────────┤
|
||||||
|
│ id │ INTEGER │ │
|
||||||
|
│ key │ TEXT │ 参数名 │
|
||||||
|
│ value │ TEXT │ 参数值 │
|
||||||
|
│ changed_at │ DATETIME │ │
|
||||||
|
│ changed_by │ TEXT │ web / cli │
|
||||||
|
└──────────────┴──────────┴───────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
## 3. REST API
|
||||||
|
|
||||||
|
```
|
||||||
|
Base URL: http://localhost:8080/api/v1
|
||||||
|
|
||||||
|
┌────────┬────────────────────────┬────────────────────────────┐
|
||||||
|
│ Method │ Path │ 说明 │
|
||||||
|
├────────┼────────────────────────┼────────────────────────────┤
|
||||||
|
│ GET │ /api/v1/stats/summary │ 总览指标 │
|
||||||
|
│ GET │ /api/v1/stats/coins │ 各币种明细 │
|
||||||
|
│ GET │ /api/v1/stats/pnl │ PnL 曲线(按天/时) │
|
||||||
|
│ GET │ /api/v1/stats/daily │ 每日统计 │
|
||||||
|
├────────┼────────────────────────┼────────────────────────────┤
|
||||||
|
│ GET │ /api/v1/trades │ 交易列表(分页) │
|
||||||
|
│ GET │ /api/v1/trades/:id │ 单笔交易详情 + 订单明细 │
|
||||||
|
│ GET │ /api/v1/trades/active │ 当前持仓 │
|
||||||
|
├────────┼────────────────────────┼────────────────────────────┤
|
||||||
|
│ GET │ /api/v1/exchanges │ 交易所连接状态 │
|
||||||
|
│ GET │ /api/v1/prices │ 所有币种实时价差 │
|
||||||
|
├────────┼────────────────────────┼────────────────────────────┤
|
||||||
|
│ GET │ /api/v1/config │ 当前配置 │
|
||||||
|
│ PUT │ /api/v1/config │ 更新配置 │
|
||||||
|
├────────┼────────────────────────┼────────────────────────────┤
|
||||||
|
│ GET │ /api/v1/status │ 系统运行状态(uptime等) │
|
||||||
|
│ POST │ /api/v1/action/restart │ 重启扫描器 │
|
||||||
|
└────────┴────────────────────────┴────────────────────────────┘
|
||||||
|
|
||||||
|
GET /api/v1/stats/summary 响应:
|
||||||
|
{
|
||||||
|
"total_trades": 387,
|
||||||
|
"total_pnl_pct": 4.27,
|
||||||
|
"total_pnl_usd": 0.85,
|
||||||
|
"win_rate": 56.5,
|
||||||
|
"avg_pnl_pct": 0.011,
|
||||||
|
"max_drawdown": -2.1,
|
||||||
|
"active_positions": 3,
|
||||||
|
"running_time": "13h 22m",
|
||||||
|
"exchanges_connected": 4,
|
||||||
|
"mode": "simulation"
|
||||||
|
}
|
||||||
|
|
||||||
|
GET /api/v1/stats/coins 响应:
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"coin": "ONDO",
|
||||||
|
"trades": 115,
|
||||||
|
"pnl_pct": 3.11,
|
||||||
|
"win_rate": 56.5,
|
||||||
|
"avg_pnl": 0.027,
|
||||||
|
"best_trade": 0.18,
|
||||||
|
"worst_trade": -0.05,
|
||||||
|
"long_pct": 94,
|
||||||
|
"short_pct": 6,
|
||||||
|
"active": true
|
||||||
|
},
|
||||||
|
...
|
||||||
|
]
|
||||||
|
|
||||||
|
GET /api/v1/trades?page=1&limit=20&coin=ONDO 响应:
|
||||||
|
{
|
||||||
|
"trades": [
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"coin": "ONDO",
|
||||||
|
"direction": "BG->HL",
|
||||||
|
"entry_spread": 0.17,
|
||||||
|
"exit_spread": 0.01,
|
||||||
|
"net_pnl": 0.10,
|
||||||
|
"duration": "52s",
|
||||||
|
"opened_at": "2026-05-03T15:42:00+08:00",
|
||||||
|
"scale_count": 0
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"total": 115,
|
||||||
|
"page": 1
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 4. SSE (Server-Sent Events) 实时推送
|
||||||
|
|
||||||
|
```
|
||||||
|
Endpoint: GET /api/v1/stream
|
||||||
|
|
||||||
|
────────────── 连接建立 ──────────────→
|
||||||
|
|
||||||
|
←── event: snapshot ── 全量数据推送 ──
|
||||||
|
{ prices: {...}, positions: [...], summary: {...} }
|
||||||
|
|
||||||
|
←── event: price_update ── 价差变化 ── (每 500ms)
|
||||||
|
{ coin: "ONDO", spread: 0.15, bg: 0.28, hl: 0.2815 }
|
||||||
|
|
||||||
|
←── event: trade_opened ── 新开仓 ──
|
||||||
|
{ id: 42, coin: "ONDO", direction: "BG->HL", spread: 0.17, ... }
|
||||||
|
|
||||||
|
←── event: trade_closed ── 平仓 ──
|
||||||
|
{ id: 42, net_pnl: 0.10, exit_spread: 0.01, ... }
|
||||||
|
|
||||||
|
←── event: exchange_status ── WS 状态变化 ──
|
||||||
|
{ exchange: "Bitget", connected: true, latency_ms: 120 }
|
||||||
|
|
||||||
|
←── event: alert ── 系统告警 ──
|
||||||
|
{ level: "warn", message: "WS reconnected", ... }
|
||||||
|
```
|
||||||
|
|
||||||
|
## 5. 前端页面布局
|
||||||
|
|
||||||
|
```
|
||||||
|
┌──────────────────────────────────────────────────────┐
|
||||||
|
│ [logo] 套利机器人仪表盘 [模拟/实盘] [设置] │
|
||||||
|
├──────────────────────────────────────────────────────┤
|
||||||
|
│ ┌───────┐ ┌───────┐ ┌───────┐ ┌───────┐ ┌────────┐ │
|
||||||
|
│ │总交易 │ │总净利 │ │胜率 │ │当前持仓│ │运行时间 │ │
|
||||||
|
│ │ 387 │ │+4.27% │ │56.5% │ │ 3 │ │ 13h22m │ │
|
||||||
|
│ └───────┘ └───────┘ └───────┘ └───────┘ └────────┘ │
|
||||||
|
├──────────────────────────────────────────────────────┤
|
||||||
|
│ Tab: [📈 概览] [📋 交易记录] [⚙️ 配置] [🔌 连接] │
|
||||||
|
├──────────────────────────────────────────────────────┤
|
||||||
|
│ │
|
||||||
|
│ Tab: 概览 │
|
||||||
|
│ ┌──────────────────────────────────────────────────┐ │
|
||||||
|
│ │ 价差实时折线图(可切换币种) │ │
|
||||||
|
│ │ ╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲ │ │
|
||||||
|
│ │ ──── 0.1% 阈值线 ──── │ │
|
||||||
|
│ │ ╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱ │ │
|
||||||
|
│ │ [ONDO] [WIF] [OP] [DOGE] [ARB] [LINK] │ │
|
||||||
|
│ └──────────────────────────────────────────────────┘ │
|
||||||
|
│ │
|
||||||
|
│ ┌────┬──────┬──────┬──────┬──────┬──────┬───────┐ │
|
||||||
|
│ │币种 │方向 │持仓$ │价差% │已持 │浮动% │ P&L$ │ │
|
||||||
|
│ ├────┼──────┼──────┼──────┼──────┼──────┼───────┤ │
|
||||||
|
│ │ONDO│BG→HL │$5 │0.15 │12s │+0.10 │+0.005 │ │
|
||||||
|
│ │WIF │BG→HL │$10 │0.08 │2m30s │+0.22 │+0.022 │ │
|
||||||
|
│ │OP │HL→BG │$5 │0.22 │1m │+0.05 │+0.003 │ │
|
||||||
|
│ └────┴──────┴──────┴──────┴──────┴──────┴───────┘ │
|
||||||
|
│ │
|
||||||
|
│ 最近成交 │
|
||||||
|
│ 15:42:23 ONDO BG→HL 入场0.17% 出场0.01% +0.10% │
|
||||||
|
│ 15:41:55 WIF BG→HL 入场0.15% 出场0.02% +0.08% │
|
||||||
|
│ 15:41:30 OP HL→BG 入场0.22% 出场0.01% +0.15% │
|
||||||
|
│ │
|
||||||
|
│ Tab: 交易记录 │
|
||||||
|
│ ┌────┬──────┬──────┬──────┬──────┬──────┬──────┬───┐ │
|
||||||
|
│ │时间│币种 │方向 │入场 │出场 │净利% │持仓 │详情│ │
|
||||||
|
│ ├────┼──────┼──────┼──────┼──────┼──────┼──────┼───┤ │
|
||||||
|
│ │... │ │ │ │ │ │ │ >│ │
|
||||||
|
│ └────┴──────┴──────┴──────┴──────┴──────┴──────┴───┘ │
|
||||||
|
│ [上一页] [1/23] [下一页] │
|
||||||
|
│ │
|
||||||
|
│ Tab: 配置 │
|
||||||
|
│ 阈值: [0.1% ] 每腿金额: [$5 ] 模式: ○模拟 │
|
||||||
|
│ 冷却时间: [30000]ms 最大持仓: [3 ] ●实盘 │
|
||||||
|
│ [保存配置] │
|
||||||
|
│ │
|
||||||
|
│ Tab: 连接 │
|
||||||
|
│ ┌──────────┬──────────┬───────┬──────────┐ │
|
||||||
|
│ │交易所 │状态 │延迟 │最后更新 │ │
|
||||||
|
│ ├──────────┼──────────┼───────┼──────────┤ │
|
||||||
|
│ │Bitget │● 已连接 │120ms │15:42:23 │ │
|
||||||
|
│ │HL │● 已连接 │85ms │15:42:23 │ │
|
||||||
|
│ │Binance │● 已连接 │90ms │15:42:22 │ │
|
||||||
|
│ │dYdX │⚠ 重连中 │-- │15:41:48 │ │
|
||||||
|
│ └──────────┴──────────┴───────┴──────────┘ │
|
||||||
|
└──────────────────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
## 6. 前端技术选型
|
||||||
|
|
||||||
|
```
|
||||||
|
框架: 无框架,纯 HTML + CSS + vanilla JS
|
||||||
|
原因:零构建步骤,单文件嵌入
|
||||||
|
|
||||||
|
图表: Chart.js (CDN https://cdn.jsdelivr.net/npm/chart.js)
|
||||||
|
原因:轻量、灵活、CDN 无需 npm
|
||||||
|
|
||||||
|
实时通: EventSource (浏览器原生 SSE)
|
||||||
|
原因:比 WebSocket 简单,自动重连
|
||||||
|
|
||||||
|
UI: 纯 CSS Grid + Flexbox
|
||||||
|
深色主题(适合交易屏长时间看)
|
||||||
|
|
||||||
|
体积: < 300KB 总大小(含 Chart.js CDN)
|
||||||
|
```
|
||||||
|
|
||||||
|
## 7. Web Server 设计 (Go)
|
||||||
|
|
||||||
|
```
|
||||||
|
// web/server.go
|
||||||
|
|
||||||
|
package web
|
||||||
|
|
||||||
|
type Server struct {
|
||||||
|
engine *engine.Engine
|
||||||
|
db *db.DB
|
||||||
|
mux *http.ServeMux
|
||||||
|
sse *SSEHub // SSE 连接管理器
|
||||||
|
}
|
||||||
|
|
||||||
|
// SSEHub 管理所有 SSE 客户端连接
|
||||||
|
type SSEHub struct {
|
||||||
|
clients map[chan SSEEvent]struct{}
|
||||||
|
register chan chan SSEEvent
|
||||||
|
unregister chan chan SSEEvent
|
||||||
|
broadcast chan SSEEvent
|
||||||
|
}
|
||||||
|
|
||||||
|
// 从 Engine 接收事件并广播
|
||||||
|
func (h *SSEHub) Broadcast(eventType string, data interface{})
|
||||||
|
```
|
||||||
|
|
||||||
|
## 8. 数据流
|
||||||
|
|
||||||
|
```
|
||||||
|
WS 数据流 (500ms):
|
||||||
|
┌─────────┐ price ┌──────────┐ SSE push ┌─────────┐
|
||||||
|
│ Exchange│──────────►│ Engine │─────────────►│ Browser │
|
||||||
|
│ WS │ │(内存状态)│ │(实时更新)│
|
||||||
|
└─────────┘ └────┬─────┘ └─────────┘
|
||||||
|
│
|
||||||
|
│ 写入 SQLite
|
||||||
|
▼
|
||||||
|
┌──────────┐
|
||||||
|
│ SQLite │
|
||||||
|
│ (持久化) │
|
||||||
|
└──────────┘
|
||||||
|
|
||||||
|
API 请求:
|
||||||
|
┌─────────┐ GET /api/... ┌──────────┐ SQL ┌────────┐
|
||||||
|
│ Browser │────────────────►│ Server │──────────►│ SQLite │
|
||||||
|
│ (页面) │◄────────────────│(REST API)│◄──────────┘ │
|
||||||
|
└─────────┘ JSON └──────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
## 9. 实现顺序
|
||||||
|
|
||||||
|
```
|
||||||
|
Phase 1 — 基础设施
|
||||||
|
1. db/ 包:SQLite 初始化 + schema 迁移
|
||||||
|
2. 程序启动时保存交易记录到 SQLite
|
||||||
|
3. 重启时从 SQLite 恢复历史数据
|
||||||
|
|
||||||
|
Phase 2 — Web Server
|
||||||
|
1. web/server.go:路由 + SSE Hub
|
||||||
|
2. REST API:summary, trades, prices, config
|
||||||
|
3. 前端 index.html:概览页(指标卡片 + 当前持仓 + 最近成交)
|
||||||
|
|
||||||
|
Phase 3 — 实时
|
||||||
|
1. SSE stream:价格、持仓、交易实时推送
|
||||||
|
2. Chart.js 实时价差折线图
|
||||||
|
|
||||||
|
Phase 4 — 完善
|
||||||
|
1. 交易记录页(分页、筛选、详情弹窗)
|
||||||
|
2. 配置页(在线修改参数)
|
||||||
|
3. 连接状态页
|
||||||
|
4. PnL 曲线图
|
||||||
|
```
|
||||||
Reference in New Issue
Block a user