diff --git a/persistence.md b/persistence.md new file mode 100644 index 0000000..7cd08e7 --- /dev/null +++ b/persistence.md @@ -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 曲线图 +```