From aeede956e69c97f15fece244bb555c291cf0bb7f Mon Sep 17 00:00:00 2001 From: tinkle-community Date: Mon, 15 Dec 2025 18:07:52 +0800 Subject: [PATCH] docs: add bilingual module documentation (EN/ZH) --- docs/architecture/BACKTEST_MODULE.md | 452 ++++++------- docs/architecture/BACKTEST_MODULE.zh-CN.md | 624 +++++++++++++++++ docs/architecture/DEBATE_MODULE.md | 2 + docs/architecture/DEBATE_MODULE.zh-CN.md | 606 +++++++++++++++++ docs/architecture/STRATEGY_MODULE.md | 536 +++++++-------- docs/architecture/STRATEGY_MODULE.zh-CN.md | 737 +++++++++++++++++++++ 6 files changed, 2465 insertions(+), 492 deletions(-) create mode 100644 docs/architecture/BACKTEST_MODULE.zh-CN.md create mode 100644 docs/architecture/DEBATE_MODULE.zh-CN.md create mode 100644 docs/architecture/STRATEGY_MODULE.zh-CN.md diff --git a/docs/architecture/BACKTEST_MODULE.md b/docs/architecture/BACKTEST_MODULE.md index f8f580c1..820c1e2b 100644 --- a/docs/architecture/BACKTEST_MODULE.md +++ b/docs/architecture/BACKTEST_MODULE.md @@ -1,87 +1,89 @@ -# NOFX 回测模块技术文档 +# NOFX Backtest Module - Technical Documentation -## 概述 +**Language:** [English](BACKTEST_MODULE.md) | [中文](BACKTEST_MODULE.zh-CN.md) -本文档详细描述 NOFX 回测模块的完整技术实现,包括配置、历史数据加载、模拟引擎、AI 决策、性能指标计算和结果存储。 +## Overview + +This document describes the complete technical implementation of the NOFX backtest module, including configuration, historical data loading, simulation engine, AI decision making, performance metrics calculation, and result storage. --- -## 完整回测流程图 +## Complete Backtest Flow ``` ┌─────────────────────────────────────────────────────────────────┐ -│ 回测执行流程 │ +│ Backtest Execution Flow │ └─────────────────────────────────────────────────────────────────┘ -1. API 请求: /backtest/start +1. API Request: /backtest/start ↓ 2. Manager.Start() - ├─ 验证配置 - ├─ 解析 AI 模型 - ├─ 创建 Runner 实例 - └─ 启动 runner.Start() (goroutine) + ├─ Validate config + ├─ Parse AI model + ├─ Create Runner instance + └─ Start runner.Start() (goroutine) ↓ 3. Runner.Start() → Runner.loop() - └─ 遍历每个决策时间点: - ├─ DataFeed.BuildMarketData() [构建市场数据] - ├─ 检查决策触发条件 [每 N 根 K 线] - ├─ buildDecisionContext() [构建决策上下文] - ├─ invokeAIWithRetry() [调用 AI + 缓存] - ├─ executeDecision() [执行交易] - ├─ checkLiquidation() [检查爆仓] - ├─ updateState() [更新状态] - ├─ appendEquityPoint() [记录权益] - ├─ appendTradeEvent() [记录交易] - ├─ maybeCheckpoint() [保存检查点] - └─ persistMetrics() [持久化指标] + └─ Iterate each decision time point: + ├─ DataFeed.BuildMarketData() [Build market data] + ├─ Check decision trigger [Every N bars] + ├─ buildDecisionContext() [Build decision context] + ├─ invokeAIWithRetry() [Call AI + cache] + ├─ executeDecision() [Execute trades] + ├─ checkLiquidation() [Check liquidation] + ├─ updateState() [Update state] + ├─ appendEquityPoint() [Record equity] + ├─ appendTradeEvent() [Record trades] + ├─ maybeCheckpoint() [Save checkpoint] + └─ persistMetrics() [Persist metrics] ↓ -4. 完成/失败 - ├─ 计算最终指标 - ├─ 持久化所有结果 - └─ 释放锁 +4. Complete/Failed + ├─ Calculate final metrics + ├─ Persist all results + └─ Release lock ↓ -5. API 查询: /backtest/metrics, /backtest/equity, /backtest/trades - └─ 加载并返回结果 +5. API Query: /backtest/metrics, /backtest/equity, /backtest/trades + └─ Load and return results ``` --- -## 1. 回测配置 (Configuration) +## 1. Configuration -**核心文件:** `backtest/config.go` +**Core File:** `backtest/config.go` -### 1.1 配置参数 +### 1.1 Config Parameters -| 参数 | 类型 | 默认值 | 说明 | -|------|------|--------|------| -| `RunID` | string | (必填) | 回测运行唯一标识 | -| `UserID` | string | "default" | 用户 ID | -| `Symbols` | []string | (必填) | 交易币种列表 | -| `Timeframes` | []string | ["3m", "15m", "4h"] | K 线周期 | -| `DecisionTimeframe` | string | Symbols[0] | 主决策周期 | -| `DecisionCadenceNBars` | int | 20 | 每 N 根 K 线触发一次决策 | -| `StartTS`, `EndTS` | int64 | (必填) | 回测时间范围 (Unix 时间戳) | -| `InitialBalance` | float64 | 1000 | 初始资金 (USD) | -| `FeeBps` | float64 | 5 | 手续费 (基点) | -| `SlippageBps` | float64 | 2 | 滑点 (基点) | -| `FillPolicy` | string | "next_open" | 成交策略 | -| `PromptVariant` | string | "baseline" | AI 提示词变体 | -| `CacheAI` | bool | false | 是否缓存 AI 决策 | -| `Leverage` | LeverageConfig | BTC/ETH:5, Altcoin:5 | 杠杆设置 | +| Parameter | Type | Default | Description | +|-----------|------|---------|-------------| +| `RunID` | string | (required) | Unique backtest run ID | +| `UserID` | string | "default" | User ID | +| `Symbols` | []string | (required) | Trading symbols list | +| `Timeframes` | []string | ["3m", "15m", "4h"] | K-line timeframes | +| `DecisionTimeframe` | string | Symbols[0] | Primary decision timeframe | +| `DecisionCadenceNBars` | int | 20 | Trigger decision every N bars | +| `StartTS`, `EndTS` | int64 | (required) | Backtest time range (Unix timestamp) | +| `InitialBalance` | float64 | 1000 | Initial balance (USD) | +| `FeeBps` | float64 | 5 | Trading fee (basis points) | +| `SlippageBps` | float64 | 2 | Slippage (basis points) | +| `FillPolicy` | string | "next_open" | Fill policy | +| `PromptVariant` | string | "baseline" | AI prompt variant | +| `CacheAI` | bool | false | Cache AI decisions | +| `Leverage` | LeverageConfig | BTC/ETH:5, Altcoin:5 | Leverage settings | -### 1.2 成交策略 (Fill Policy) +### 1.2 Fill Policy ```go // backtest/config.go:163-179 switch fillPolicy { -case "next_open": // 下一根 K 线开盘价 -case "bar_vwap": // 当前 K 线 VWAP -case "mid": // 当前 K 线 (High+Low)/2 +case "next_open": // Next bar open price +case "bar_vwap": // Current bar VWAP +case "mid": // Current bar (High+Low)/2 default: // Mark Price } ``` -### 1.3 配置示例 +### 1.3 Config Example ```go cfg := backtest.BacktestConfig{ @@ -101,61 +103,61 @@ cfg := backtest.BacktestConfig{ --- -## 2. 历史数据加载 (Data Loading) +## 2. Data Loading -**核心文件:** `backtest/datafeed.go` +**Core File:** `backtest/datafeed.go` -### 2.1 数据加载流程 +### 2.1 Data Loading Flow ``` -1. NewDataFeed() - 初始化 +1. NewDataFeed() - Initialize ↓ -2. loadAll() - 加载所有历史数据 - ├─ 计算缓冲区 (StartTS 前 200 根 K 线) - ├─ 调用 market.GetKlinesRange() 获取数据 - ├─ 存储到 symbolSeries map - └─ 从主周期构建决策时间线 +2. loadAll() - Load all historical data + ├─ Calculate buffer (200 bars before StartTS) + ├─ Call market.GetKlinesRange() to fetch data + ├─ Store in symbolSeries map + └─ Build decision timeline from primary timeframe ↓ -3. BuildMarketData() - 构建市场数据快照 - ├─ 切片 K 线数据到当前时间戳 - ├─ 计算技术指标 (EMA, MACD, RSI, ATR) - └─ 返回 market.Data 结构 +3. BuildMarketData() - Build market data snapshot + ├─ Slice K-line data to current timestamp + ├─ Calculate technical indicators (EMA, MACD, RSI, ATR) + └─ Return market.Data structure ``` -### 2.2 数据结构 +### 2.2 Data Structure ```go -// DataFeed 核心结构 +// DataFeed core structure type DataFeed struct { - decisionTimes []int64 // 决策时间点列表 - symbolSeries map[string]*symbolSeries // 按币种存储的数据 + decisionTimes []int64 // Decision time points list + symbolSeries map[string]*symbolSeries // Data stored by symbol } -// 单币种时间序列 +// Single symbol time series type symbolSeries struct { - timeframes map[string]*timeframeSeries // 按周期存储 + timeframes map[string]*timeframeSeries // Stored by timeframe } -// 单周期数据 +// Single timeframe data type timeframeSeries struct { - klines []market.Kline // K 线数据 - closeTimes []int64 // 收盘时间索引 + klines []market.Kline // K-line data + closeTimes []int64 // Close time index } ``` -### 2.3 关键代码引用 +### 2.3 Key Code References -- 数据获取: `backtest/datafeed.go:48-93` -- 时间线生成: `backtest/datafeed.go:96-115` -- 市场数据组装: `backtest/datafeed.go:141-171` +- Data fetching: `backtest/datafeed.go:48-93` +- Timeline generation: `backtest/datafeed.go:96-115` +- Market data assembly: `backtest/datafeed.go:141-171` --- -## 3. 模拟引擎 (Simulation Engine) +## 3. Simulation Engine -**核心文件:** `backtest/runner.go` +**Core File:** `backtest/runner.go` -### 3.1 主循环 +### 3.1 Main Loop ```go // backtest/runner.go:232-264 @@ -169,44 +171,44 @@ func (r *Runner) loop() { } ``` -### 3.2 单步执行 +### 3.2 Single Step Execution ```go // backtest/runner.go:266-471 func (r *Runner) stepOnce(ts int64) { - // 1. 获取当前 K 线时间戳 - // 2. 构建市场数据 - // 3. 检查决策触发条件 (每 N 根 K 线) - // 4. 执行决策周期 (如果触发) - // 5. 检查爆仓 - // 6. 更新状态并记录 + // 1. Get current bar timestamp + // 2. Build market data + // 3. Check decision trigger (every N bars) + // 4. Execute decision cycle (if triggered) + // 5. Check liquidation + // 6. Update state and record } ``` -### 3.3 状态管理 +### 3.3 State Management ```go // backtest/types.go:31-47 type BacktestState struct { - BarIndex int // 当前 K 线索引 - Cash float64 // 可用余额 - Equity float64 // 总权益 - UnrealizedPnL float64 // 未实现盈亏 - RealizedPnL float64 // 已实现盈亏 - MaxEquity float64 // 最高权益 - MinEquity float64 // 最低权益 - MaxDrawdownPct float64 // 最大回撤 - Positions map[string]*position // 持仓 + BarIndex int // Current bar index + Cash float64 // Available balance + Equity float64 // Total equity + UnrealizedPnL float64 // Unrealized PnL + RealizedPnL float64 // Realized PnL + MaxEquity float64 // Peak equity + MinEquity float64 // Trough equity + MaxDrawdownPct float64 // Max drawdown + Positions map[string]*position // Positions } ``` --- -## 4. AI 决策 (AI Decision Making) +## 4. AI Decision Making -**核心文件:** `backtest/runner.go` +**Core File:** `backtest/runner.go` -### 4.1 决策上下文构建 +### 4.1 Decision Context Building ```go // backtest/runner.go:473-532 @@ -226,29 +228,29 @@ func (r *Runner) buildDecisionContext() *decision.Context { } ``` -### 4.2 AI 调用 +### 4.2 AI Invocation ```go // backtest/runner.go:544-563 func (r *Runner) invokeAIWithRetry() (*decision.FullDecision, error) { - // 最多重试 3 次 - // 指数退避: 500ms, 1000ms, 1500ms - // 使用 decision.GetFullDecisionWithStrategy() 统一提示词生成 + // Max 3 retries + // Exponential backoff: 500ms, 1000ms, 1500ms + // Uses decision.GetFullDecisionWithStrategy() for unified prompt generation } ``` -### 4.3 AI 缓存 +### 4.3 AI Cache ```go // backtest/aicache.go:127-168 -// 缓存键: SHA256(context payload) -// 包含: variant, timestamp, account, positions, market data +// Cache key: SHA256(context payload) +// Contains: variant, timestamp, account, positions, market data ``` -### 4.4 支持的 AI 模型 +### 4.4 Supported AI Models -| 模型 | 客户端文件 | -|------|-----------| +| Model | Client File | +|-------|-------------| | DeepSeek | `mcp/deepseek_client.go` | | Qwen | `mcp/qwen_client.go` | | Claude | `mcp/claude_client.go` | @@ -259,21 +261,21 @@ func (r *Runner) invokeAIWithRetry() (*decision.FullDecision, error) { --- -## 5. 性能指标 (Performance Metrics) +## 5. Performance Metrics -**核心文件:** `backtest/metrics.go` +**Core File:** `backtest/metrics.go` -### 5.1 指标计算 +### 5.1 Metrics Calculation -| 指标 | 公式 | 代码位置 | -|------|------|----------| -| **总收益率** | (最终权益 - 初始资金) / 初始资金 × 100 | metrics.go:36-42 | -| **最大回撤** | max((峰值 - 当前) / 峰值 × 100) | metrics.go:64-91 | -| **夏普比率** | 平均收益 / 收益标准差 | metrics.go:94-138 | -| **胜率** | 盈利交易数 / 总交易数 × 100 | metrics.go:180-181 | -| **盈亏比** | 总盈利 / 总亏损 | metrics.go:189-193 | +| Metric | Formula | Code Location | +|--------|---------|---------------| +| **Total Return** | (Final Equity - Initial) / Initial × 100 | metrics.go:36-42 | +| **Max Drawdown** | max((Peak - Current) / Peak × 100) | metrics.go:64-91 | +| **Sharpe Ratio** | Avg Return / Return StdDev | metrics.go:94-138 | +| **Win Rate** | Winning Trades / Total Trades × 100 | metrics.go:180-181 | +| **Profit Factor** | Total Profit / Total Loss | metrics.go:189-193 | -### 5.2 交易统计 +### 5.2 Trade Statistics ```go // backtest/metrics.go:141-225 @@ -291,11 +293,11 @@ type TradeMetrics struct { --- -## 6. 权益曲线 (Equity Curve) +## 6. Equity Curve -**核心文件:** `backtest/equity.go` +**Core File:** `backtest/equity.go` -### 6.1 权益点结构 +### 6.1 Equity Point Structure ```json { @@ -309,56 +311,56 @@ type TradeMetrics struct { } ``` -### 6.2 权益更新 +### 6.2 Equity Update ```go // backtest/runner.go:829-872 func (r *Runner) updateState() { - // 1. 计算总权益: cash + margin + 未实现盈亏 - // 2. 追踪峰值 (MaxEquity) - // 3. 追踪谷值 (MinEquity) - // 4. 重新计算回撤: (MaxEquity - Equity) / MaxEquity × 100 + // 1. Calculate total equity: cash + margin + unrealized PnL + // 2. Track peak (MaxEquity) + // 3. Track trough (MinEquity) + // 4. Recalculate drawdown: (MaxEquity - Equity) / MaxEquity × 100 } ``` -### 6.3 数据重采样 +### 6.3 Data Resampling ```go // backtest/equity.go:10-50 func ResampleEquity(points []EquityPoint, timeframe string) []EquityPoint { - // 按时间周期分桶 - // 保留每个桶的最后一个点 + // Bucket by timeframe + // Keep last point in each bucket } ``` --- -## 7. 结果存储 (Result Storage) +## 7. Result Storage -**核心文件:** `backtest/storage.go`, `store/backtest.go` +**Core Files:** `backtest/storage.go`, `store/backtest.go` -### 7.1 文件存储结构 +### 7.1 File Storage Structure ``` backtests/ ├── / -│ ├── run.json # 运行元数据 -│ ├── checkpoint.json # 检查点 (用于恢复) -│ ├── equity.jsonl # 权益曲线 (逐行 JSON) -│ ├── trades.jsonl # 交易记录 (逐行 JSON) -│ ├── metrics.json # 性能指标 -│ ├── progress.json # 进度信息 -│ ├── ai_cache.json # AI 决策缓存 -│ └── decision_logs/ # 决策日志 +│ ├── run.json # Run metadata +│ ├── checkpoint.json # Checkpoint (for resume) +│ ├── equity.jsonl # Equity curve (line-delimited JSON) +│ ├── trades.jsonl # Trade records (line-delimited JSON) +│ ├── metrics.json # Performance metrics +│ ├── progress.json # Progress info +│ ├── ai_cache.json # AI decision cache +│ └── decision_logs/ # Decision logs │ ├── 0.json │ ├── 1.json │ └── ... ``` -### 7.2 数据库表结构 +### 7.2 Database Schema ```sql --- 回测运行元数据 +-- Backtest run metadata CREATE TABLE backtest_runs ( run_id TEXT PRIMARY KEY, user_id TEXT, @@ -375,7 +377,7 @@ CREATE TABLE backtest_runs ( updated_at DATETIME ); --- 权益曲线 +-- Equity curve CREATE TABLE backtest_equity ( id INTEGER PRIMARY KEY, run_id TEXT, @@ -388,7 +390,7 @@ CREATE TABLE backtest_equity ( cycle INTEGER ); --- 交易记录 +-- Trade records CREATE TABLE backtest_trades ( id INTEGER PRIMARY KEY, run_id TEXT, @@ -405,14 +407,14 @@ CREATE TABLE backtest_trades ( liquidation BOOLEAN ); --- 性能指标 +-- Performance metrics CREATE TABLE backtest_metrics ( run_id TEXT PRIMARY KEY, payload BLOB, updated_at DATETIME ); --- 检查点 (暂停/恢复) +-- Checkpoints (pause/resume) CREATE TABLE backtest_checkpoints ( run_id TEXT PRIMARY KEY, payload BLOB, @@ -422,31 +424,31 @@ CREATE TABLE backtest_checkpoints ( --- -## 8. API 接口 +## 8. API Endpoints -**核心文件:** `api/backtest.go` +**Core File:** `api/backtest.go` -### 8.1 接口列表 +### 8.1 Endpoint List -| 接口 | 方法 | 说明 | -|------|------|------| -| `/backtest/start` | POST | 开始回测 | -| `/backtest/pause` | POST | 暂停回测 | -| `/backtest/resume` | POST | 恢复回测 | -| `/backtest/stop` | POST | 停止回测 | -| `/backtest/status` | GET | 获取状态 | -| `/backtest/runs` | GET | 列出所有回测 | -| `/backtest/equity` | GET | 获取权益曲线 | -| `/backtest/trades` | GET | 获取交易记录 | -| `/backtest/metrics` | GET | 获取性能指标 | -| `/backtest/trace` | GET | 获取决策日志 | -| `/backtest/export` | GET | 导出 ZIP | -| `/backtest/delete` | POST | 删除回测 | +| Endpoint | Method | Description | +|----------|--------|-------------| +| `/backtest/start` | POST | Start backtest | +| `/backtest/pause` | POST | Pause backtest | +| `/backtest/resume` | POST | Resume backtest | +| `/backtest/stop` | POST | Stop backtest | +| `/backtest/status` | GET | Get status | +| `/backtest/runs` | GET | List all backtests | +| `/backtest/equity` | GET | Get equity curve | +| `/backtest/trades` | GET | Get trade records | +| `/backtest/metrics` | GET | Get performance metrics | +| `/backtest/trace` | GET | Get decision logs | +| `/backtest/export` | GET | Export ZIP | +| `/backtest/delete` | POST | Delete backtest | -### 8.2 请求示例 +### 8.2 Request Examples ```bash -# 开始回测 +# Start backtest POST /backtest/start { "config": { @@ -460,17 +462,17 @@ POST /backtest/start } } -# 获取权益曲线 +# Get equity curve GET /backtest/equity?run_id=bt_20231215&tf=1h&limit=1000 -# 获取指标 +# Get metrics GET /backtest/metrics?run_id=bt_20231215 ``` -### 8.3 响应示例 +### 8.3 Response Examples ```json -// 状态响应 +// Status response { "run_id": "bt_20231215", "state": "running", @@ -480,7 +482,7 @@ GET /backtest/metrics?run_id=bt_20231215 "unrealized_pnl": 234.50 } -// 指标响应 +// Metrics response { "total_return_pct": 12.34, "max_drawdown_pct": 5.67, @@ -493,74 +495,74 @@ GET /backtest/metrics?run_id=bt_20231215 --- -## 9. 账户与持仓管理 +## 9. Account & Position Management -**核心文件:** `backtest/account.go` +**Core File:** `backtest/account.go` -### 9.1 持仓结构 +### 9.1 Position Structure ```go type position struct { Symbol string - Side string // "long" 或 "short" + Side string // "long" or "short" Quantity float64 EntryPrice float64 Leverage int - Margin float64 // 保证金 - Notional float64 // 名义价值 - LiquidationPrice float64 // 爆仓价格 + Margin float64 // Margin + Notional float64 // Notional value + LiquidationPrice float64 // Liquidation price OpenTime int64 } ``` -### 9.2 开仓逻辑 +### 9.2 Open Position Logic ```go // backtest/account.go:61-104 func (a *BacktestAccount) Open(symbol, side string, qty, price float64, leverage int) { - // 1. 应用滑点 - // 2. 计算名义价值 (qty × price) - // 3. 计算保证金 (notional / leverage) - // 4. 扣除保证金 + 手续费 - // 5. 创建/加仓 - // 6. 计算爆仓价格 + // 1. Apply slippage + // 2. Calculate notional value (qty × price) + // 3. Calculate margin (notional / leverage) + // 4. Deduct margin + fees + // 5. Create/add to position + // 6. Calculate liquidation price } ``` -### 9.3 平仓逻辑 +### 9.3 Close Position Logic ```go // backtest/account.go:106-140 func (a *BacktestAccount) Close(symbol, side string, qty, price float64) { - // 1. 验证持仓存在 - // 2. 应用滑点 (反向) - // 3. 计算已实现盈亏 + // 1. Verify position exists + // 2. Apply slippage (reverse direction) + // 3. Calculate realized PnL // long: (exit - entry) × qty // short: (entry - exit) × qty - // 4. 返还保证金 + 盈亏 - 手续费 - // 5. 更新/删除持仓 + // 4. Return margin + PnL - fees + // 5. Update/delete position } ``` -### 9.4 爆仓价格计算 +### 9.4 Liquidation Price Calculation ```go // backtest/account.go:177-186 func computeLiquidation(entry float64, leverage int, side string) float64 { if side == "long" { - return entry * (1 - 1.0/float64(leverage)) // 做多: 下跌爆仓 + return entry * (1 - 1.0/float64(leverage)) // Long: liquidate on drop } - return entry * (1 + 1.0/float64(leverage)) // 做空: 上涨爆仓 + return entry * (1 + 1.0/float64(leverage)) // Short: liquidate on rise } ``` --- -## 10. 检查点与恢复 +## 10. Checkpoint & Resume -**核心文件:** `backtest/runner.go` +**Core File:** `backtest/runner.go` -### 10.1 检查点结构 +### 10.1 Checkpoint Structure ```json { @@ -576,47 +578,47 @@ func computeLiquidation(entry float64, leverage int, side string) float64 { } ``` -### 10.2 检查点触发 +### 10.2 Checkpoint Trigger ```go // backtest/runner.go:874-898 func (r *Runner) maybeCheckpoint() { - // 每 N 根 K 线保存 - // 或每 N 秒保存 + // Save every N bars + // Or save every N seconds } ``` -### 10.3 恢复流程 +### 10.3 Resume Flow ```go func (r *Runner) RestoreFromCheckpoint() { - // 1. 加载检查点 - // 2. 恢复账户状态 - // 3. 恢复 K 线索引 (从下一根继续) - // 4. 恢复权益曲线、交易记录 + // 1. Load checkpoint + // 2. Restore account state + // 3. Restore bar index (continue from next bar) + // 4. Restore equity curve, trade records } ``` --- -## 核心文件索引 +## Core File Index -| 模块 | 文件 | 关键方法 | -|------|------|----------| -| **配置** | `backtest/config.go` | `BacktestConfig`, `Validate()` | -| **数据加载** | `backtest/datafeed.go` | `NewDataFeed()`, `loadAll()`, `BuildMarketData()` | -| **模拟引擎** | `backtest/runner.go` | `Start()`, `loop()`, `stepOnce()` | -| **决策** | `backtest/runner.go` | `buildDecisionContext()`, `invokeAIWithRetry()` | -| **执行** | `backtest/runner.go` | `executeDecision()` | -| **账户** | `backtest/account.go` | `Open()`, `Close()`, `TotalEquity()` | -| **指标** | `backtest/metrics.go` | `CalculateMetrics()` | -| **权益** | `backtest/equity.go` | `ResampleEquity()`, `LimitEquityPoints()` | -| **存储** | `backtest/storage.go` | `SaveCheckpoint()`, `appendEquityPoint()` | -| **数据库** | `store/backtest.go` | 表结构和 CRUD 操作 | -| **API** | `api/backtest.go` | HTTP 处理器 | -| **AI 缓存** | `backtest/aicache.go` | `Get()`, `Put()`, `save()` | +| Module | File | Key Methods | +|--------|------|-------------| +| **Config** | `backtest/config.go` | `BacktestConfig`, `Validate()` | +| **Data Loading** | `backtest/datafeed.go` | `NewDataFeed()`, `loadAll()`, `BuildMarketData()` | +| **Sim Engine** | `backtest/runner.go` | `Start()`, `loop()`, `stepOnce()` | +| **Decision** | `backtest/runner.go` | `buildDecisionContext()`, `invokeAIWithRetry()` | +| **Execution** | `backtest/runner.go` | `executeDecision()` | +| **Account** | `backtest/account.go` | `Open()`, `Close()`, `TotalEquity()` | +| **Metrics** | `backtest/metrics.go` | `CalculateMetrics()` | +| **Equity** | `backtest/equity.go` | `ResampleEquity()`, `LimitEquityPoints()` | +| **Storage** | `backtest/storage.go` | `SaveCheckpoint()`, `appendEquityPoint()` | +| **Database** | `store/backtest.go` | Schema and CRUD operations | +| **API** | `api/backtest.go` | HTTP handlers | +| **AI Cache** | `backtest/aicache.go` | `Get()`, `Put()`, `save()` | --- -**文档版本:** 1.0.0 -**最后更新:** 2025-01-15 +**Document Version:** 1.0.0 +**Last Updated:** 2025-01-15 diff --git a/docs/architecture/BACKTEST_MODULE.zh-CN.md b/docs/architecture/BACKTEST_MODULE.zh-CN.md new file mode 100644 index 00000000..8ec1938c --- /dev/null +++ b/docs/architecture/BACKTEST_MODULE.zh-CN.md @@ -0,0 +1,624 @@ +# NOFX 回测模块技术文档 + +**语言:** [English](BACKTEST_MODULE.md) | [中文](BACKTEST_MODULE.zh-CN.md) + +## 概述 + +本文档详细描述 NOFX 回测模块的完整技术实现,包括配置、历史数据加载、模拟引擎、AI 决策、性能指标计算和结果存储。 + +--- + +## 完整回测流程图 + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ 回测执行流程 │ +└─────────────────────────────────────────────────────────────────┘ + +1. API 请求: /backtest/start + ↓ +2. Manager.Start() + ├─ 验证配置 + ├─ 解析 AI 模型 + ├─ 创建 Runner 实例 + └─ 启动 runner.Start() (goroutine) + ↓ +3. Runner.Start() → Runner.loop() + └─ 遍历每个决策时间点: + ├─ DataFeed.BuildMarketData() [构建市场数据] + ├─ 检查决策触发条件 [每 N 根 K 线] + ├─ buildDecisionContext() [构建决策上下文] + ├─ invokeAIWithRetry() [调用 AI + 缓存] + ├─ executeDecision() [执行交易] + ├─ checkLiquidation() [检查爆仓] + ├─ updateState() [更新状态] + ├─ appendEquityPoint() [记录权益] + ├─ appendTradeEvent() [记录交易] + ├─ maybeCheckpoint() [保存检查点] + └─ persistMetrics() [持久化指标] + ↓ +4. 完成/失败 + ├─ 计算最终指标 + ├─ 持久化所有结果 + └─ 释放锁 + ↓ +5. API 查询: /backtest/metrics, /backtest/equity, /backtest/trades + └─ 加载并返回结果 +``` + +--- + +## 1. 回测配置 (Configuration) + +**核心文件:** `backtest/config.go` + +### 1.1 配置参数 + +| 参数 | 类型 | 默认值 | 说明 | +|------|------|--------|------| +| `RunID` | string | (必填) | 回测运行唯一标识 | +| `UserID` | string | "default" | 用户 ID | +| `Symbols` | []string | (必填) | 交易币种列表 | +| `Timeframes` | []string | ["3m", "15m", "4h"] | K 线周期 | +| `DecisionTimeframe` | string | Symbols[0] | 主决策周期 | +| `DecisionCadenceNBars` | int | 20 | 每 N 根 K 线触发一次决策 | +| `StartTS`, `EndTS` | int64 | (必填) | 回测时间范围 (Unix 时间戳) | +| `InitialBalance` | float64 | 1000 | 初始资金 (USD) | +| `FeeBps` | float64 | 5 | 手续费 (基点) | +| `SlippageBps` | float64 | 2 | 滑点 (基点) | +| `FillPolicy` | string | "next_open" | 成交策略 | +| `PromptVariant` | string | "baseline" | AI 提示词变体 | +| `CacheAI` | bool | false | 是否缓存 AI 决策 | +| `Leverage` | LeverageConfig | BTC/ETH:5, Altcoin:5 | 杠杆设置 | + +### 1.2 成交策略 (Fill Policy) + +```go +// backtest/config.go:163-179 +switch fillPolicy { +case "next_open": // 下一根 K 线开盘价 +case "bar_vwap": // 当前 K 线 VWAP +case "mid": // 当前 K 线 (High+Low)/2 +default: // Mark Price +} +``` + +### 1.3 配置示例 + +```go +cfg := backtest.BacktestConfig{ + RunID: "bt_20231215_150405", + Symbols: []string{"BTCUSDT", "ETHUSDT"}, + Timeframes: []string{"3m", "15m", "4h"}, + DecisionTimeframe: "3m", + DecisionCadenceNBars: 20, + StartTS: 1702566000, + EndTS: 1702652400, + InitialBalance: 10000, + FeeBps: 5, + SlippageBps: 2, + FillPolicy: "next_open", +} +``` + +--- + +## 2. 历史数据加载 (Data Loading) + +**核心文件:** `backtest/datafeed.go` + +### 2.1 数据加载流程 + +``` +1. NewDataFeed() - 初始化 + ↓ +2. loadAll() - 加载所有历史数据 + ├─ 计算缓冲区 (StartTS 前 200 根 K 线) + ├─ 调用 market.GetKlinesRange() 获取数据 + ├─ 存储到 symbolSeries map + └─ 从主周期构建决策时间线 + ↓ +3. BuildMarketData() - 构建市场数据快照 + ├─ 切片 K 线数据到当前时间戳 + ├─ 计算技术指标 (EMA, MACD, RSI, ATR) + └─ 返回 market.Data 结构 +``` + +### 2.2 数据结构 + +```go +// DataFeed 核心结构 +type DataFeed struct { + decisionTimes []int64 // 决策时间点列表 + symbolSeries map[string]*symbolSeries // 按币种存储的数据 +} + +// 单币种时间序列 +type symbolSeries struct { + timeframes map[string]*timeframeSeries // 按周期存储 +} + +// 单周期数据 +type timeframeSeries struct { + klines []market.Kline // K 线数据 + closeTimes []int64 // 收盘时间索引 +} +``` + +### 2.3 关键代码引用 + +- 数据获取: `backtest/datafeed.go:48-93` +- 时间线生成: `backtest/datafeed.go:96-115` +- 市场数据组装: `backtest/datafeed.go:141-171` + +--- + +## 3. 模拟引擎 (Simulation Engine) + +**核心文件:** `backtest/runner.go` + +### 3.1 主循环 + +```go +// backtest/runner.go:232-264 +func (r *Runner) loop() { + for _, ts := range r.feed.DecisionTimes() { + if r.isPaused() { + break + } + r.stepOnce(ts) + } +} +``` + +### 3.2 单步执行 + +```go +// backtest/runner.go:266-471 +func (r *Runner) stepOnce(ts int64) { + // 1. 获取当前 K 线时间戳 + // 2. 构建市场数据 + // 3. 检查决策触发条件 (每 N 根 K 线) + // 4. 执行决策周期 (如果触发) + // 5. 检查爆仓 + // 6. 更新状态并记录 +} +``` + +### 3.3 状态管理 + +```go +// backtest/types.go:31-47 +type BacktestState struct { + BarIndex int // 当前 K 线索引 + Cash float64 // 可用余额 + Equity float64 // 总权益 + UnrealizedPnL float64 // 未实现盈亏 + RealizedPnL float64 // 已实现盈亏 + MaxEquity float64 // 最高权益 + MinEquity float64 // 最低权益 + MaxDrawdownPct float64 // 最大回撤 + Positions map[string]*position // 持仓 +} +``` + +--- + +## 4. AI 决策 (AI Decision Making) + +**核心文件:** `backtest/runner.go` + +### 4.1 决策上下文构建 + +```go +// backtest/runner.go:473-532 +func (r *Runner) buildDecisionContext() *decision.Context { + return &decision.Context{ + CurrentTime: "2023-12-15 10:30:00 UTC", + RuntimeMinutes: elapsed, + CallCount: cycleNumber, + Account: { + TotalEquity, AvailableBalance, TotalPnL, MarginUsedPct + }, + Positions: []PositionInfo{...}, + CandidateCoins: []string{symbols...}, + MarketDataMap: map[symbol]*market.Data{...}, + MultiTFMarket: map[symbol]map[timeframe]*market.Data{...}, + } +} +``` + +### 4.2 AI 调用 + +```go +// backtest/runner.go:544-563 +func (r *Runner) invokeAIWithRetry() (*decision.FullDecision, error) { + // 最多重试 3 次 + // 指数退避: 500ms, 1000ms, 1500ms + // 使用 decision.GetFullDecisionWithStrategy() 统一提示词生成 +} +``` + +### 4.3 AI 缓存 + +```go +// backtest/aicache.go:127-168 +// 缓存键: SHA256(context payload) +// 包含: variant, timestamp, account, positions, market data +``` + +### 4.4 支持的 AI 模型 + +| 模型 | 客户端文件 | +|------|-----------| +| DeepSeek | `mcp/deepseek_client.go` | +| Qwen | `mcp/qwen_client.go` | +| Claude | `mcp/claude_client.go` | +| Gemini | `mcp/gemini_client.go` | +| Grok | `mcp/grok_client.go` | +| OpenAI | `mcp/openai_client.go` | +| Kimi | `mcp/kimi_client.go` | + +--- + +## 5. 性能指标 (Performance Metrics) + +**核心文件:** `backtest/metrics.go` + +### 5.1 指标计算 + +| 指标 | 公式 | 代码位置 | +|------|------|----------| +| **总收益率** | (最终权益 - 初始资金) / 初始资金 × 100 | metrics.go:36-42 | +| **最大回撤** | max((峰值 - 当前) / 峰值 × 100) | metrics.go:64-91 | +| **夏普比率** | 平均收益 / 收益标准差 | metrics.go:94-138 | +| **胜率** | 盈利交易数 / 总交易数 × 100 | metrics.go:180-181 | +| **盈亏比** | 总盈利 / 总亏损 | metrics.go:189-193 | + +### 5.2 交易统计 + +```go +// backtest/metrics.go:141-225 +type TradeMetrics struct { + TotalTrades int + WinningTrades int + LosingTrades int + AvgWin float64 + AvgLoss float64 + BestSymbol string + WorstSymbol string + SymbolStats map[string]*SymbolStat +} +``` + +--- + +## 6. 权益曲线 (Equity Curve) + +**核心文件:** `backtest/equity.go` + +### 6.1 权益点结构 + +```json +{ + "ts": 1702566000000, + "equity": 10500.50, + "available": 8000.00, + "pnl": 500.50, + "pnl_pct": 5.005, + "dd_pct": 2.34, + "cycle": 42 +} +``` + +### 6.2 权益更新 + +```go +// backtest/runner.go:829-872 +func (r *Runner) updateState() { + // 1. 计算总权益: cash + margin + 未实现盈亏 + // 2. 追踪峰值 (MaxEquity) + // 3. 追踪谷值 (MinEquity) + // 4. 重新计算回撤: (MaxEquity - Equity) / MaxEquity × 100 +} +``` + +### 6.3 数据重采样 + +```go +// backtest/equity.go:10-50 +func ResampleEquity(points []EquityPoint, timeframe string) []EquityPoint { + // 按时间周期分桶 + // 保留每个桶的最后一个点 +} +``` + +--- + +## 7. 结果存储 (Result Storage) + +**核心文件:** `backtest/storage.go`, `store/backtest.go` + +### 7.1 文件存储结构 + +``` +backtests/ +├── / +│ ├── run.json # 运行元数据 +│ ├── checkpoint.json # 检查点 (用于恢复) +│ ├── equity.jsonl # 权益曲线 (逐行 JSON) +│ ├── trades.jsonl # 交易记录 (逐行 JSON) +│ ├── metrics.json # 性能指标 +│ ├── progress.json # 进度信息 +│ ├── ai_cache.json # AI 决策缓存 +│ └── decision_logs/ # 决策日志 +│ ├── 0.json +│ ├── 1.json +│ └── ... +``` + +### 7.2 数据库表结构 + +```sql +-- 回测运行元数据 +CREATE TABLE backtest_runs ( + run_id TEXT PRIMARY KEY, + user_id TEXT, + config_json TEXT, + state TEXT, -- pending, running, completed, failed + processed_bars INTEGER, + progress_pct REAL, + equity_last REAL, + max_drawdown_pct REAL, + liquidated BOOLEAN, + ai_provider TEXT, + ai_model TEXT, + created_at DATETIME, + updated_at DATETIME +); + +-- 权益曲线 +CREATE TABLE backtest_equity ( + id INTEGER PRIMARY KEY, + run_id TEXT, + ts INTEGER, + equity REAL, + available REAL, + pnl REAL, + pnl_pct REAL, + dd_pct REAL, + cycle INTEGER +); + +-- 交易记录 +CREATE TABLE backtest_trades ( + id INTEGER PRIMARY KEY, + run_id TEXT, + ts INTEGER, + symbol TEXT, + action TEXT, + side TEXT, + qty REAL, + price REAL, + fee REAL, + slippage REAL, + realized_pnl REAL, + leverage INTEGER, + liquidation BOOLEAN +); + +-- 性能指标 +CREATE TABLE backtest_metrics ( + run_id TEXT PRIMARY KEY, + payload BLOB, + updated_at DATETIME +); + +-- 检查点 (暂停/恢复) +CREATE TABLE backtest_checkpoints ( + run_id TEXT PRIMARY KEY, + payload BLOB, + updated_at DATETIME +); +``` + +--- + +## 8. API 接口 + +**核心文件:** `api/backtest.go` + +### 8.1 接口列表 + +| 接口 | 方法 | 说明 | +|------|------|------| +| `/backtest/start` | POST | 开始回测 | +| `/backtest/pause` | POST | 暂停回测 | +| `/backtest/resume` | POST | 恢复回测 | +| `/backtest/stop` | POST | 停止回测 | +| `/backtest/status` | GET | 获取状态 | +| `/backtest/runs` | GET | 列出所有回测 | +| `/backtest/equity` | GET | 获取权益曲线 | +| `/backtest/trades` | GET | 获取交易记录 | +| `/backtest/metrics` | GET | 获取性能指标 | +| `/backtest/trace` | GET | 获取决策日志 | +| `/backtest/export` | GET | 导出 ZIP | +| `/backtest/delete` | POST | 删除回测 | + +### 8.2 请求示例 + +```bash +# 开始回测 +POST /backtest/start +{ + "config": { + "run_id": "bt_20231215", + "symbols": ["BTCUSDT", "ETHUSDT"], + "timeframes": ["3m", "15m", "4h"], + "start_ts": 1702566000, + "end_ts": 1702652400, + "initial_balance": 10000, + "ai_model_id": "model_001" + } +} + +# 获取权益曲线 +GET /backtest/equity?run_id=bt_20231215&tf=1h&limit=1000 + +# 获取指标 +GET /backtest/metrics?run_id=bt_20231215 +``` + +### 8.3 响应示例 + +```json +// 状态响应 +{ + "run_id": "bt_20231215", + "state": "running", + "progress_pct": 45.5, + "processed_bars": 1234, + "equity": 10234.50, + "unrealized_pnl": 234.50 +} + +// 指标响应 +{ + "total_return_pct": 12.34, + "max_drawdown_pct": 5.67, + "sharpe_ratio": 1.89, + "profit_factor": 2.34, + "win_rate": 65.5, + "trades": 123 +} +``` + +--- + +## 9. 账户与持仓管理 + +**核心文件:** `backtest/account.go` + +### 9.1 持仓结构 + +```go +type position struct { + Symbol string + Side string // "long" 或 "short" + Quantity float64 + EntryPrice float64 + Leverage int + Margin float64 // 保证金 + Notional float64 // 名义价值 + LiquidationPrice float64 // 爆仓价格 + OpenTime int64 +} +``` + +### 9.2 开仓逻辑 + +```go +// backtest/account.go:61-104 +func (a *BacktestAccount) Open(symbol, side string, qty, price float64, leverage int) { + // 1. 应用滑点 + // 2. 计算名义价值 (qty × price) + // 3. 计算保证金 (notional / leverage) + // 4. 扣除保证金 + 手续费 + // 5. 创建/加仓 + // 6. 计算爆仓价格 +} +``` + +### 9.3 平仓逻辑 + +```go +// backtest/account.go:106-140 +func (a *BacktestAccount) Close(symbol, side string, qty, price float64) { + // 1. 验证持仓存在 + // 2. 应用滑点 (反向) + // 3. 计算已实现盈亏 + // long: (exit - entry) × qty + // short: (entry - exit) × qty + // 4. 返还保证金 + 盈亏 - 手续费 + // 5. 更新/删除持仓 +} +``` + +### 9.4 爆仓价格计算 + +```go +// backtest/account.go:177-186 +func computeLiquidation(entry float64, leverage int, side string) float64 { + if side == "long" { + return entry * (1 - 1.0/float64(leverage)) // 做多: 下跌爆仓 + } + return entry * (1 + 1.0/float64(leverage)) // 做空: 上涨爆仓 +} +``` + +--- + +## 10. 检查点与恢复 + +**核心文件:** `backtest/runner.go` + +### 10.1 检查点结构 + +```json +{ + "bar_index": 1234, + "bar_ts": 1702609200000, + "cash": 8000.00, + "equity": 10234.50, + "max_equity": 10500.00, + "max_drawdown_pct": 5.67, + "positions": [...], + "decision_cycle": 62, + "liquidated": false +} +``` + +### 10.2 检查点触发 + +```go +// backtest/runner.go:874-898 +func (r *Runner) maybeCheckpoint() { + // 每 N 根 K 线保存 + // 或每 N 秒保存 +} +``` + +### 10.3 恢复流程 + +```go +func (r *Runner) RestoreFromCheckpoint() { + // 1. 加载检查点 + // 2. 恢复账户状态 + // 3. 恢复 K 线索引 (从下一根继续) + // 4. 恢复权益曲线、交易记录 +} +``` + +--- + +## 核心文件索引 + +| 模块 | 文件 | 关键方法 | +|------|------|----------| +| **配置** | `backtest/config.go` | `BacktestConfig`, `Validate()` | +| **数据加载** | `backtest/datafeed.go` | `NewDataFeed()`, `loadAll()`, `BuildMarketData()` | +| **模拟引擎** | `backtest/runner.go` | `Start()`, `loop()`, `stepOnce()` | +| **决策** | `backtest/runner.go` | `buildDecisionContext()`, `invokeAIWithRetry()` | +| **执行** | `backtest/runner.go` | `executeDecision()` | +| **账户** | `backtest/account.go` | `Open()`, `Close()`, `TotalEquity()` | +| **指标** | `backtest/metrics.go` | `CalculateMetrics()` | +| **权益** | `backtest/equity.go` | `ResampleEquity()`, `LimitEquityPoints()` | +| **存储** | `backtest/storage.go` | `SaveCheckpoint()`, `appendEquityPoint()` | +| **数据库** | `store/backtest.go` | 表结构和 CRUD 操作 | +| **API** | `api/backtest.go` | HTTP 处理器 | +| **AI 缓存** | `backtest/aicache.go` | `Get()`, `Put()`, `save()` | + +--- + +**文档版本:** 1.0.0 +**最后更新:** 2025-01-15 diff --git a/docs/architecture/DEBATE_MODULE.md b/docs/architecture/DEBATE_MODULE.md index 089fa56d..21f0cd1d 100644 --- a/docs/architecture/DEBATE_MODULE.md +++ b/docs/architecture/DEBATE_MODULE.md @@ -1,5 +1,7 @@ # Debate Arena Module - Technical Documentation +**Language:** [English](DEBATE_MODULE.md) | [中文](DEBATE_MODULE.zh-CN.md) + ## Overview The Debate Arena is a collaborative AI decision-making system where multiple AI models with different personalities debate market conditions and reach consensus on trading decisions. The system supports multi-round debates, real-time streaming, voting mechanisms, and automatic trade execution. diff --git a/docs/architecture/DEBATE_MODULE.zh-CN.md b/docs/architecture/DEBATE_MODULE.zh-CN.md new file mode 100644 index 00000000..21782e06 --- /dev/null +++ b/docs/architecture/DEBATE_MODULE.zh-CN.md @@ -0,0 +1,606 @@ +# NOFX 辩论竞技场模块 - 技术文档 + +**语言:** [English](DEBATE_MODULE.md) | [中文](DEBATE_MODULE.zh-CN.md) + +## 概述 + +辩论竞技场是一个多 AI 协作决策系统,多个具有不同性格的 AI 模型对市场状况进行辩论并达成交易决策共识。系统支持多轮辩论、实时流推送、投票机制和自动交易执行。 + +--- + +## 1. 架构概览 + +``` +┌─────────────────────────────────────────────────────────────────────────────┐ +│ 辩论竞技场系统 │ +├─────────────────────────────────────────────────────────────────────────────┤ +│ │ +│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ +│ │ 多头 AI │ │ 空头 AI │ │ 分析 AI │ │ 风控 AI │ │ +│ │ 🐂 │ │ 🐻 │ │ 📊 │ │ 🛡️ │ │ +│ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ │ +│ │ │ │ │ │ +│ └──────────────────┴──────────────────┴──────────────────┘ │ +│ │ │ +│ ┌─────────▼─────────┐ │ +│ │ 辩论引擎 │ │ +│ │ (debate/engine) │ │ +│ └─────────┬─────────┘ │ +│ │ │ +│ ┌──────────────────────────┼──────────────────────────┐ │ +│ │ │ │ │ +│ ┌──────▼──────┐ ┌─────────▼─────────┐ ┌────────▼────────┐ │ +│ │ 市场数据 │ │ 投票系统 │ │ 自动执行器 │ │ +│ │ 组装 │ │ 与共识机制 │ │ (可选) │ │ +│ └─────────────┘ └───────────────────┘ └─────────────────┘ │ +│ │ +└─────────────────────────────────────────────────────────────────────────────┘ +``` + +### 文件结构 + +``` +├── debate/ +│ └── engine.go # 核心辩论引擎逻辑 +├── api/ +│ └── debate.go # HTTP 处理器和 SSE 流 +├── store/ +│ └── debate.go # 数据库操作和模式 +└── web/src/pages/ + └── DebateArenaPage.tsx # 前端 UI +``` + +--- + +## 2. 性格系统 + +### 2.1 可用性格 + +| 性格 | 图标 | 名称 | 描述 | 交易偏向 | +|------|------|------|------|----------| +| Bull | 🐂 | 激进多头 | 寻找做多机会 | 乐观,趋势跟随 | +| Bear | 🐻 | 谨慎空头 | 关注风险 | 悲观,做空偏向 | +| Analyst | 📊 | 数据分析师 | 纯数据驱动 | 无偏见,客观分析 | +| Contrarian | 🔄 | 逆势者 | 挑战多数观点 | 另类视角 | +| Risk Manager | 🛡️ | 风控经理 | 关注风险控制 | 仓位管理,止损 | + +### 2.2 性格提示词增强 + +**文件位置:** `debate/engine.go:buildDebateSystemPrompt()` (365-426行) + +``` +## 辩论模式 - 第 {round}/{max_rounds} 轮 + +你作为 {emoji} {personality} 参与辩论。 + +### 你的辩论角色: +{personality_description} + +### 辩论规则: +1. 分析所有候选币种 +2. 用具体数据支持论点 +3. 回应其他参与者 (第2轮起) +4. 有说服力但基于数据 +5. 可以推荐多个不同操作的币种 + +### 输出格式 (严格 JSON): + + - 带数据引用的市场分析 + - 主要交易论点 + - 对他人的回应 (第2轮起) + + + +[ + {"symbol": "BTCUSDT", "action": "open_long", "confidence": 75, ...}, + {"symbol": "ETHUSDT", "action": "open_short", "confidence": 80, ...} +] + +``` + +--- + +## 3. 辩论执行流程 + +### 3.1 会话创建 + +``` +POST /api/debates + │ + ▼ +┌─────────────────────────────────────────────────────────────┐ +│ 1. 验证用户认证 │ +│ 2. 解析 CreateDebateRequest: │ +│ - name, strategy_id, symbol, max_rounds, participants │ +│ - interval_minutes, prompt_variant, auto_execute │ +│ 3. 验证策略所有权 │ +│ 4. 自动选择币种 (如未提供): │ +│ - 静态币种 → 使用策略第一个币种 │ +│ - CoinPool → 从 AI500 API 获取 │ +│ - OI Top → 从 OI 排行 API 获取 │ +│ - Mixed → 先尝试池,回退到 OI │ +│ 5. 设置默认值: │ +│ - max_rounds: 3 (范围 2-5) │ +│ - interval_minutes: 5 │ +│ - prompt_variant: "balanced" │ +│ 6. 在数据库创建 DebateSession │ +│ 7. 添加带 AI 模型和性格的参与者 │ +│ 8. 返回完整会话及参与者 │ +└─────────────────────────────────────────────────────────────┘ +``` + +### 3.2 辩论轮次执行 + +**文件位置:** `debate/engine.go:runDebate()` (157-289行) + +``` +┌─────────────────────────────────────────────────────────────┐ +│ 每轮 (1 到 max_rounds): │ +│ ┌─────────────────────────────────────────────────────────┐ │ +│ │ 1. 广播 "round_start" 事件 │ │ +│ │ 2. 每个参与者 (按 speak_order): │ │ +│ │ ┌─────────────────────────────────────────────────┐ │ │ +│ │ │ a. 构建性格增强的系统提示词 │ │ │ +│ │ │ b. 构建用户提示词: │ │ │ +│ │ │ - 市场数据 (来自策略引擎) │ │ │ +│ │ │ - 之前的辩论消息 (第2轮起) │ │ │ +│ │ │ c. 调用 AI 模型,60秒超时 │ │ │ +│ │ │ d. 从响应解析多币种决策 │ │ │ +│ │ │ e. 保存消息到数据库 │ │ │ +│ │ │ f. 广播 "message" 事件 │ │ │ +│ │ └─────────────────────────────────────────────────┘ │ │ +│ │ 3. 广播 "round_end" 事件 │ │ +│ └─────────────────────────────────────────────────────────┘ │ +│ │ +│ 所有轮次后: │ +│ ┌─────────────────────────────────────────────────────────┐ │ +│ │ 1. 进入投票阶段 (status = "voting") │ │ +│ │ 2. 收集所有参与者的最终投票 │ │ +│ │ 3. 确定多币种共识 │ │ +│ │ 4. 存储最终决策 │ │ +│ │ 5. 更新状态为 "completed" │ │ +│ │ 6. 广播 "consensus" 事件 │ │ +│ └─────────────────────────────────────────────────────────┘ │ +└─────────────────────────────────────────────────────────────┘ +``` + +--- + +## 4. 共识算法 + +### 4.1 投票收集 + +**文件位置:** `debate/engine.go:collectVotes()` (542-567行) + +``` +每个参与者: +┌─────────────────────────────────────────────────────────────┐ +│ 1. 构建投票系统提示词 │ +│ 2. 构建带辩论摘要的投票用户提示词 │ +│ 3. 调用 AI 模型获取最终投票 │ +│ 4. 解析多币种决策 │ +│ 5. 验证/修复币种与 session.Symbol 一致 │ +│ 6. 保存投票到数据库 │ +│ 7. 广播 "vote" 事件 │ +└─────────────────────────────────────────────────────────────┘ +``` + +### 4.2 多币种共识确定 + +**文件位置:** `debate/engine.go:determineMultiCoinConsensus()` (752-924行) + +**算法:** + +``` +1. 收集所有投票中的所有币种决策 +2. 按 symbol → action → 聚合数据 分组 + +3. 对每个投票决策: + weight = confidence / 100.0 + 累加: + ┌─────────────────────────────────────────────────────────┐ + │ score += weight │ + │ total_confidence += confidence │ + │ total_leverage += leverage │ + │ total_position_pct += position_pct │ + │ total_stop_loss += stop_loss │ + │ total_take_profit += take_profit │ + │ count++ │ + └─────────────────────────────────────────────────────────┘ + +4. 对每个币种: + 找到胜出操作 (最高 score) + 计算平均值: + ┌─────────────────────────────────────────────────────────┐ + │ avg_confidence = total_confidence / count │ + │ avg_leverage = clamp(total_leverage / count, 1, 20) │ + │ avg_position_pct = clamp(total_pct / count, 0.1, 1.0) │ + │ avg_stop_loss = 默认 3% (如未设置) │ + │ avg_take_profit = 默认 6% (如未设置) │ + └─────────────────────────────────────────────────────────┘ + +5. 返回共识决策数组 +``` + +### 4.3 共识示例 + +**输入投票:** +``` +AI1 (多头): BTC open_long (conf=80, lev=10, pos=0.3) +AI2 (空头): BTC open_short (conf=60, lev=5, pos=0.2) +AI3 (分析): BTC open_long (conf=70, lev=8, pos=0.25) +``` + +**计算:** +``` +open_long: + score = 0.80 + 0.70 = 1.50 + avg_conf = (80 + 70) / 2 = 75 + avg_lev = (10 + 8) / 2 = 9 + avg_pos = (0.3 + 0.25) / 2 = 0.275 + +open_short: + score = 0.60 + avg_conf = 60 + avg_lev = 5 + avg_pos = 0.2 + +胜出: open_long (score 1.50 > 0.60) +``` + +**输出:** +```json +{ + "symbol": "BTCUSDT", + "action": "open_long", + "confidence": 75, + "leverage": 9, + "position_pct": 0.275, + "stop_loss": 0.03, + "take_profit": 0.06 +} +``` + +--- + +## 5. 自动执行 + +### 5.1 执行流程 + +**文件位置:** `debate/engine.go:ExecuteConsensus()` (932-1052行) + +``` +POST /api/debates/:id/execute + │ + ▼ +┌─────────────────────────────────────────────────────────────┐ +│ 1. 验证会话状态 = completed │ +│ 2. 验证 final_decision 存在且未执行 │ +│ 3. 验证操作是 open_long 或 open_short │ +│ 4. 获取当前市场价格 │ +│ 5. 获取账户余额: │ +│ - 尝试 available_balance │ +│ - 回退到 total_equity 或 wallet_balance │ +│ 6. 计算仓位大小: │ +│ position_size_usd = available_balance × position_pct │ +│ (最小 $12 以满足交易所要求) │ +│ 7. 计算止损和止盈价格: │ +│ ┌───────────────────────────────────────────────────┐ │ +│ │ open_long: │ │ +│ │ SL = price × (1 - stop_loss_pct) │ │ +│ │ TP = price × (1 + take_profit_pct) │ │ +│ │ open_short: │ │ +│ │ SL = price × (1 + stop_loss_pct) │ │ +│ │ TP = price × (1 - take_profit_pct) │ │ +│ └───────────────────────────────────────────────────┘ │ +│ 8. 创建 Decision 对象 │ +│ 9. 调用 executor.ExecuteDecision() │ +│ 10. 更新 final_decision: │ +│ - executed = true/false │ +│ - executed_at = 时间戳 │ +│ - error 消息 (如失败) │ +└─────────────────────────────────────────────────────────────┘ +``` + +--- + +## 6. API 接口 + +### 6.1 接口列表 + +| 接口 | 方法 | 描述 | +|------|------|------| +| `/api/debates` | GET | 列出用户所有辩论 | +| `/api/debates/personalities` | GET | 获取 AI 性格配置 | +| `/api/debates/:id` | GET | 获取辩论详情 | +| `/api/debates` | POST | 创建新辩论 | +| `/api/debates/:id/start` | POST | 开始辩论执行 | +| `/api/debates/:id/cancel` | POST | 取消运行中的辩论 | +| `/api/debates/:id/execute` | POST | 执行共识交易 | +| `/api/debates/:id` | DELETE | 删除辩论 | +| `/api/debates/:id/messages` | GET | 获取所有消息 | +| `/api/debates/:id/votes` | GET | 获取所有投票 | +| `/api/debates/:id/stream` | GET | SSE 实时流 | + +### 6.2 创建辩论请求 + +```json +POST /api/debates +{ + "name": "BTC 市场辩论", + "strategy_id": "strategy-uuid", + "symbol": "BTCUSDT", + "max_rounds": 3, + "interval_minutes": 5, + "prompt_variant": "balanced", + "auto_execute": false, + "trader_id": "trader-uuid", + "enable_oi_ranking": true, + "oi_ranking_limit": 10, + "oi_duration": "1h", + "participants": [ + {"ai_model_id": "deepseek-v3", "personality": "bull"}, + {"ai_model_id": "qwen-max", "personality": "bear"}, + {"ai_model_id": "gpt-5.2", "personality": "analyst"} + ] +} +``` + +--- + +## 7. 实时更新 (SSE) + +### 7.1 SSE 接口 + +**文件位置:** `api/debate.go:HandleDebateStream()` (407-453行) + +``` +GET /api/debates/:id/stream + │ + ▼ +┌─────────────────────────────────────────────────────────────┐ +│ 1. 验证用户所有权 │ +│ 2. 设置 SSE 头: │ +│ Content-Type: text/event-stream │ +│ Cache-Control: no-cache │ +│ Connection: keep-alive │ +│ 3. 发送初始状态 │ +│ 4. 订阅事件 │ +│ 5. 流式推送更新直到客户端断开 │ +└─────────────────────────────────────────────────────────────┘ +``` + +### 7.2 事件类型 + +| 事件 | 触发时机 | 数据 | +|------|----------|------| +| `initial` | 连接开始 | 完整会话状态 | +| `round_start` | 轮次开始 | `{round, status}` | +| `message` | AI 发言 | DebateMessage 对象 | +| `round_end` | 轮次结束 | `{round, status}` | +| `vote` | AI 投票 | DebateVote 对象 | +| `consensus` | 辩论完成 | DebateDecision 对象 | +| `error` | 发生错误 | `{error: string}` | + +--- + +## 8. 数据库模式 + +### 8.1 表结构 + +**debate_sessions:** +```sql +CREATE TABLE debate_sessions ( + id TEXT PRIMARY KEY, + user_id TEXT NOT NULL, + name TEXT NOT NULL, + strategy_id TEXT NOT NULL, + status TEXT NOT NULL DEFAULT 'pending', + symbol TEXT NOT NULL, + max_rounds INTEGER DEFAULT 3, + current_round INTEGER DEFAULT 0, + interval_minutes INTEGER DEFAULT 5, + prompt_variant TEXT DEFAULT 'balanced', + final_decision TEXT, + final_decisions TEXT, + auto_execute BOOLEAN DEFAULT 0, + trader_id TEXT, + enable_oi_ranking BOOLEAN DEFAULT 0, + oi_ranking_limit INTEGER DEFAULT 10, + oi_duration TEXT DEFAULT '1h', + created_at DATETIME DEFAULT CURRENT_TIMESTAMP, + updated_at DATETIME DEFAULT CURRENT_TIMESTAMP +); +``` + +**debate_participants:** +```sql +CREATE TABLE debate_participants ( + id TEXT PRIMARY KEY, + session_id TEXT NOT NULL, + ai_model_id TEXT NOT NULL, + ai_model_name TEXT NOT NULL, + provider TEXT NOT NULL, + personality TEXT NOT NULL, + color TEXT NOT NULL, + speak_order INTEGER DEFAULT 0, + created_at DATETIME DEFAULT CURRENT_TIMESTAMP, + FOREIGN KEY (session_id) REFERENCES debate_sessions(id) ON DELETE CASCADE +); +``` + +**debate_messages:** +```sql +CREATE TABLE debate_messages ( + id TEXT PRIMARY KEY, + session_id TEXT NOT NULL, + round INTEGER NOT NULL, + ai_model_id TEXT NOT NULL, + ai_model_name TEXT NOT NULL, + provider TEXT NOT NULL, + personality TEXT NOT NULL, + message_type TEXT NOT NULL, + content TEXT NOT NULL, + decision TEXT, + decisions TEXT, + confidence INTEGER DEFAULT 0, + created_at DATETIME DEFAULT CURRENT_TIMESTAMP, + FOREIGN KEY (session_id) REFERENCES debate_sessions(id) ON DELETE CASCADE +); +``` + +**debate_votes:** +```sql +CREATE TABLE debate_votes ( + id TEXT PRIMARY KEY, + session_id TEXT NOT NULL, + ai_model_id TEXT NOT NULL, + ai_model_name TEXT NOT NULL, + action TEXT NOT NULL, + symbol TEXT NOT NULL, + confidence INTEGER DEFAULT 0, + leverage INTEGER DEFAULT 5, + position_pct REAL DEFAULT 0.2, + stop_loss_pct REAL DEFAULT 0.03, + take_profit_pct REAL DEFAULT 0.06, + reasoning TEXT, + created_at DATETIME DEFAULT CURRENT_TIMESTAMP, + FOREIGN KEY (session_id) REFERENCES debate_sessions(id) ON DELETE CASCADE +); +``` + +--- + +## 9. 前端组件 + +### 9.1 页面结构 + +**文件位置:** `web/src/pages/DebateArenaPage.tsx` + +``` +DebateArenaPage +├── 左侧边栏 (w-56) +│ ├── 新建辩论按钮 +│ ├── 辩论会话列表 +│ │ └── SessionItem (状态, 名称, 时间戳) +│ └── 在线交易员列表 +│ └── TraderItem (名称, 状态, AI 模型) +│ +├── 主内容区 +│ ├── 头部栏 +│ │ ├── 会话信息 (名称, 状态, 币种) +│ │ ├── 参与者头像 +│ │ └── 投票摘要 +│ │ +│ ├── 内容区 (双栏) +│ │ ├── 左: 讨论记录 +│ │ │ ├── 轮次标题 +│ │ │ └── MessageCards (可展开) +│ │ │ +│ │ └── 右: 最终投票 +│ │ └── VoteCards (操作, 置信度, 理由) +│ │ +│ └── 共识栏 +│ ├── 最终决策显示 +│ └── 执行按钮 (如果 auto_execute 禁用) +│ +└── 弹窗 + ├── CreateModal + │ ├── 名称输入 + │ ├── 策略选择器 + │ ├── 币种输入 (自动填充) + │ ├── 最大轮数选择器 + │ └── 参与者选择器 (AI 模型 + 性格) + │ + └── ExecuteModal + └── 交易员选择器 +``` + +### 9.2 状态颜色 + +```typescript +const STATUS_COLOR = { + pending: 'bg-gray-500', + running: 'bg-blue-500 animate-pulse', + voting: 'bg-yellow-500 animate-pulse', + completed: 'bg-green-500', + cancelled: 'bg-red-500', +} +``` + +### 9.3 操作样式 + +```typescript +const ACT = { + open_long: { + color: 'text-green-400', + bg: 'bg-green-500/20', + icon: , + label: 'LONG' + }, + open_short: { + color: 'text-red-400', + bg: 'bg-red-500/20', + icon: , + label: 'SHORT' + }, + hold: { + color: 'text-blue-400', + bg: 'bg-blue-500/20', + icon: , + label: 'HOLD' + }, + wait: { + color: 'text-gray-400', + bg: 'bg-gray-500/20', + icon: , + label: 'WAIT' + }, +} +``` + +--- + +## 10. 集成点 + +### 10.1 策略系统 + +辩论会话依赖保存的策略: +- **币种来源配置:** static/pool/OI top +- **市场数据指标:** K线、时间周期、技术指标 +- **风控参数:** 杠杆限制、仓位大小 +- **自定义提示词:** 角色定义、交易规则 + +### 10.2 AI 模型系统 + +每个参与者需要: +- AI 模型配置 (provider, API key, 自定义 URL) +- 支持的 providers: deepseek, qwen, openai, claude, gemini, grok, kimi +- 客户端初始化带超时处理 (每次调用 60s) + +### 10.3 交易员系统 + +自动执行需要: +- 运行中状态的活跃交易员 +- 交易员必须有有效的交易所连接 +- 执行器接口: `ExecuteDecision()`, `GetBalance()` + +--- + +## 总结 + +辩论竞技场模块提供了一个复杂的多 AI 协作决策系统: + +- **多性格辩论:** 5 种独特的 AI 性格 (多头、空头、分析师、逆势者、风控经理),具有独特的交易偏向 +- **共识机制:** 基于置信度的加权投票来确定最终决策 +- **实时更新:** SSE 流推送实时辩论进度 +- **自动执行:** 可选的基于共识的自动交易执行 +- **策略集成:** 与策略配置深度集成,用于市场数据和风控参数 +- **多币种支持:** 能够同时分析和决策多个币种 + +该系统使用户能够利用多个 AI 视角做出更稳健的交易决策,同时保持对执行的完全控制。 + +--- + +**文档版本:** 1.0.0 +**最后更新:** 2025-01-15 diff --git a/docs/architecture/STRATEGY_MODULE.md b/docs/architecture/STRATEGY_MODULE.md index eebb8832..664626fb 100644 --- a/docs/architecture/STRATEGY_MODULE.md +++ b/docs/architecture/STRATEGY_MODULE.md @@ -1,82 +1,84 @@ -# NOFX 策略模块技术文档 +# NOFX Strategy Module - Technical Documentation -## 概述 +**Language:** [English](STRATEGY_MODULE.md) | [中文](STRATEGY_MODULE.zh-CN.md) -本文档详细描述 NOFX 策略模块的完整数据流程,包括币种选择、数据组装、提示词构建、AI 请求、响应解析和决策执行。 +## Overview + +This document describes the complete data flow of the NOFX strategy module, including coin selection, data assembly, prompt construction, AI request, response parsing, and decision execution. --- -## 完整数据流程图 +## Complete Data Flow ``` ┌─────────────────────────────────────────────────────────────────┐ -│ 交易周期 (每 N 分钟) │ +│ Trading Cycle (Every N Minutes) │ └─────────────────────────────────────────────────────────────────┘ -1. 币种选择 (GetCandidateCoins) - ├─ Static (静态列表) - ├─ AI500 Pool (AI评分池) - ├─ OI Top (持仓增长榜) - └─ Mixed (混合模式) +1. Coin Selection (GetCandidateCoins) + ├─ Static (Static list) + ├─ AI500 Pool (AI rating pool) + ├─ OI Top (Position growth ranking) + └─ Mixed (Mixed mode) ↓ -2. 数据组装 (buildTradingContext) - ├─ 账户余额 → equity, available, unrealizedPnL - ├─ 当前持仓 → symbol, side, entry, mark, qty, leverage - ├─ K线数据 → OHLCV (5m, 15m, 1h, 4h) - ├─ 技术指标 → EMA, MACD, RSI, ATR, Volume - ├─ 链上数据 → OI, Funding Rate - ├─ 量化数据 → 资金流向, OI变化 (可选) - └─ 最近交易 → 最近10笔已平仓 +2. Data Assembly (buildTradingContext) + ├─ Account balance → equity, available, unrealizedPnL + ├─ Current positions → symbol, side, entry, mark, qty, leverage + ├─ K-line data → OHLCV (5m, 15m, 1h, 4h) + ├─ Technical indicators → EMA, MACD, RSI, ATR, Volume + ├─ On-chain data → OI, Funding Rate + ├─ Quant data → Capital flow, OI changes (optional) + └─ Recent trades → Last 10 closed trades ↓ -3. 系统提示词 (BuildSystemPrompt) - ├─ 角色定义 - ├─ 交易模式 (aggressive/conservative/scalping) - ├─ 硬性约束 (代码强制执行) - ├─ AI引导 (建议值) - ├─ 交易频率 - ├─ 入场标准 - ├─ 决策流程 - └─ 输出格式 (XML + JSON) +3. System Prompt (BuildSystemPrompt) + ├─ Role definition + ├─ Trading mode (aggressive/conservative/scalping) + ├─ Hard constraints (code enforced) + ├─ AI guidance (suggested values) + ├─ Trading frequency + ├─ Entry standards + ├─ Decision process + └─ Output format (XML + JSON) ↓ -4. 用户提示词 (BuildUserPrompt) - ├─ 系统状态 (时间, 周期号) - ├─ BTC市场概览 - ├─ 账户信息 - ├─ 当前持仓 (含技术指标) - ├─ 候选币种 (完整市场数据) - └─ "请分析并输出决策..." +4. User Prompt (BuildUserPrompt) + ├─ System status (time, cycle number) + ├─ BTC market overview + ├─ Account information + ├─ Current positions (with indicators) + ├─ Candidate coins (full market data) + └─ "Please analyze and output decisions..." ↓ -5. AI请求 (CallWithMessages) - ├─ 选择AI模型 +5. AI Request (CallWithMessages) + ├─ Select AI model ├─ POST: system_prompt + user_prompt - ├─ 超时: 120秒, 重试: 3次 - └─ 返回原始响应 + ├─ Timeout: 120s, Retries: 3 + └─ Return raw response ↓ -6. AI解析 (parseFullDecisionResponse) - ├─ 提取思维链 - ├─ 提取JSON决策 - ├─ 修复字符编码 - ├─ 验证JSON格式 - ├─ 解析决策数组 - └─ 验证风控参数 +6. AI Parsing (parseFullDecisionResponse) + ├─ Extract Chain of Thought + ├─ Extract JSON decision + ├─ Fix character encoding + ├─ Validate JSON format + ├─ Parse decision array + └─ Validate risk parameters ↓ -7. 决策执行 - ├─ 排序: 平仓优先 → 开仓 → hold/wait - ├─ 风控强制执行 - ├─ 提交订单 - ├─ 确认成交 - └─ 记录到数据库 +7. Decision Execution + ├─ Sort: Close first → Open → hold/wait + ├─ Risk control enforcement + ├─ Submit orders + ├─ Confirm fills + └─ Record to database ``` --- -## 1. 币种选择 (Coin Selection) +## 1. Coin Selection -**核心文件:** `decision/engine.go:380-454` +**Core File:** `decision/engine.go:380-454` -**入口方法:** `StrategyEngine.GetCandidateCoins()` +**Entry Method:** `StrategyEngine.GetCandidateCoins()` -### 1.1 静态币种列表 (Static) +### 1.1 Static Coin List ```go // decision/engine.go:395-403 @@ -90,11 +92,11 @@ if config.CoinSource.SourceType == "static" { } ``` -- **配置:** `StrategyConfig.CoinSource.StaticCoins` -- **用途:** 手动指定交易币种 -- **标签:** `["static"]` +- **Config:** `StrategyConfig.CoinSource.StaticCoins` +- **Usage:** Manually specify trading coins +- **Tag:** `["static"]` -### 1.2 AI500 币种池 (CoinPool) +### 1.2 AI500 Coin Pool ```go // decision/engine.go:405-406, 456-474 @@ -110,11 +112,11 @@ func (e *StrategyEngine) getCoinPoolCoins(limit int) []CandidateCoin { } ``` -- **API:** `config.CoinSource.CoinPoolAPIURL` (默认: `http://nofxaios.com:30006/api/ai500/list`) -- **用途:** 获取 AI 评分最高的 N 个币种 -- **标签:** `["ai500"]` +- **API:** `config.CoinSource.CoinPoolAPIURL` +- **Usage:** Get top N coins by AI rating +- **Tag:** `["ai500"]` -### 1.3 OI Top 币种 (持仓增长榜) +### 1.3 OI Top Coins (Position Growth Ranking) ```go // decision/engine.go:408-409, 476-498 @@ -131,39 +133,39 @@ func (e *StrategyEngine) getOITopCoins() []CandidateCoin { ``` - **API:** `config.CoinSource.OITopAPIURL` -- **用途:** 获取持仓量增长最快的币种 -- **标签:** `["oi_top"]` +- **Usage:** Get coins with fastest OI growth +- **Tag:** `["oi_top"]` -### 1.4 混合模式 (Mixed) +### 1.4 Mixed Mode ```go // decision/engine.go:411-449 if config.CoinSource.SourceType == "mixed" { if config.CoinSource.UseCoinPool { - // 添加 AI500 币种 + // Add AI500 coins } if config.CoinSource.UseOITop { - // 添加 OI Top 币种 + // Add OI Top coins } if len(config.CoinSource.StaticCoins) > 0 { - // 添加静态币种 + // Add static coins } - // 去重合并,保留多来源标签 + // Deduplicate and merge, keep multi-source tags } ``` -- **特点:** 同时使用多个数据源 -- **标签示例:** `["ai500", "oi_top"]` (双信号币种) +- **Feature:** Use multiple data sources simultaneously +- **Tag Example:** `["ai500", "oi_top"]` (dual signal coin) --- -## 2. 数据组装 (Data Assembly) +## 2. Data Assembly -**核心文件:** `trader/auto_trader.go:562-791`, `decision/engine.go:299-374` +**Core File:** `trader/auto_trader.go:562-791`, `decision/engine.go:299-374` -**入口方法:** `AutoTrader.buildTradingContext()` +**Entry Method:** `AutoTrader.buildTradingContext()` -### 2.1 账户数据 +### 2.1 Account Data ```go // trader/auto_trader.go:565-583 @@ -173,12 +175,12 @@ available := balance["available_balance"].(float64) unrealizedPnL := balance["total_pnl"].(float64) ``` -**提取字段:** -- `total_equity` - 账户总权益 -- `available_balance` - 可用余额 -- `total_pnl` - 未实现盈亏 +**Extracted Fields:** +- `total_equity` - Total account equity +- `available_balance` - Available balance +- `total_pnl` - Unrealized PnL -### 2.2 持仓数据 +### 2.2 Position Data ```go // trader/auto_trader.go:588-682 @@ -197,7 +199,7 @@ for _, pos := range positions { } ``` -### 2.3 市场数据获取 +### 2.3 Market Data Fetching ```go // decision/engine.go:299-374 @@ -213,69 +215,69 @@ func (e *StrategyEngine) fetchMarketDataWithStrategy(symbols []string) map[strin } ``` -### 2.4 技术指标计算 +### 2.4 Technical Indicator Calculation -**文件:** `market/data.go:59-98` +**File:** `market/data.go:59-98` -| 指标 | 配置 | 计算方法 | -|------|------|----------| +| Indicator | Config | Calculation | +|-----------|--------|-------------| | **EMA** | `EnableEMA`, `EMAPeriods` | `calculateEMA(klines, period)` | | **MACD** | `EnableMACD` | `calculateMACD(klines)` - 12/26/9 | | **RSI** | `EnableRSI`, `RSIPeriods` | `calculateRSI(klines, period)` | | **ATR** | `EnableATR`, `ATRPeriods` | `calculateATR(klines, period)` | -| **Volume** | `EnableVolume` | 原始成交量数据 | -| **OI** | `EnableOI` | 持仓量数据 | -| **Funding Rate** | `EnableFundingRate` | 资金费率 | +| **Volume** | `EnableVolume` | Raw volume data | +| **OI** | `EnableOI` | Open interest data | +| **Funding Rate** | `EnableFundingRate` | Funding rate | -### 2.5 量化数据 (可选) +### 2.5 Quant Data (Optional) ```go // trader/auto_trader.go:759-778 if config.Indicators.EnableQuantData { quantData := provider.GetQuantData(symbol) - // 包含: 资金流向、OI变化、价格变化 + // Contains: Capital flow, OI changes, Price changes } ``` -**数据结构:** +**Data Structure:** ```go QuantData { Netflow { - Institution: {Future, Spot}, // 机构资金流 - Personal: {Future, Spot} // 散户资金流 + Institution: {Future, Spot}, // Institutional flow + Personal: {Future, Spot} // Retail flow }, OI { CurrentOI: float64, - Delta: {1h, 4h, 24h} // OI变化 + Delta: {1h, 4h, 24h} // OI changes }, PriceChange { - "1h", "4h", "24h": float64 // 价格变化百分比 + "1h", "4h", "24h": float64 // Price change % } } ``` --- -## 3. 系统提示词 (System Prompt) +## 3. System Prompt -**核心文件:** `decision/engine.go:700-818` +**Core File:** `decision/engine.go:700-818` -**入口方法:** `StrategyEngine.BuildSystemPrompt(accountEquity, variant)` +**Entry Method:** `StrategyEngine.BuildSystemPrompt(accountEquity, variant)` -### 3.1 提示词结构 (8个部分) +### 3.1 Prompt Structure (8 Sections) ``` -1. 角色定义 [可编辑] -2. 交易模式变体 [运行时确定] -3. 硬性约束 [代码强制 + AI引导] -4. 交易频率 [可编辑] -5. 入场标准 [可编辑] -6. 决策流程 [可编辑] -7. 输出格式 [固定XML + JSON结构] -8. 自定义提示词 [可选] +1. Role Definition [Editable] +2. Trading Mode Variant [Runtime determined] +3. Hard Constraints [Code enforced + AI guided] +4. Trading Frequency [Editable] +5. Entry Standards [Editable] +6. Decision Process [Editable] +7. Output Format [Fixed XML + JSON structure] +8. Custom Prompt [Optional] ``` -### 3.2 角色定义 +### 3.2 Role Definition ```go // decision/engine.go:706-713 @@ -285,41 +287,41 @@ if roleDefinition == "" { } ``` -### 3.3 交易模式变体 +### 3.3 Trading Mode Variants -| 模式 | 特点 | -|------|------| -| `aggressive` | 趋势突破,较高仓位容忍度 | -| `conservative` | 多信号确认,保守资金管理 | -| `scalping` | 短线动量,紧止盈 | +| Mode | Characteristics | +|------|-----------------| +| `aggressive` | Trend breakout, higher position tolerance | +| `conservative` | Multi-signal confirmation, conservative money management | +| `scalping` | Short-term momentum, tight take-profit | -### 3.4 硬性约束 +### 3.4 Hard Constraints -**代码强制执行 (CODE ENFORCED):** +**Code Enforced:** ```go // decision/engine.go:725-749 -maxPositions := config.RiskControl.MaxPositions // 默认: 3 -altcoinMaxRatio := config.RiskControl.AltcoinMaxPositionValueRatio // 默认: 1.0 -btcethMaxRatio := config.RiskControl.BTCETHMaxPositionValueRatio // 默认: 5.0 -maxMarginUsage := config.RiskControl.MaxMarginUsage // 默认: 90% -minPositionSize := config.RiskControl.MinPositionSize // 默认: 12 USDT +maxPositions := config.RiskControl.MaxPositions // Default: 3 +altcoinMaxRatio := config.RiskControl.AltcoinMaxPositionValueRatio // Default: 1.0 +btcethMaxRatio := config.RiskControl.BTCETHMaxPositionValueRatio // Default: 5.0 +maxMarginUsage := config.RiskControl.MaxMarginUsage // Default: 90% +minPositionSize := config.RiskControl.MinPositionSize // Default: 12 USDT ``` -**AI引导 (建议值):** +**AI Guided (Suggested Values):** ```go -altcoinMaxLeverage := config.RiskControl.AltcoinMaxLeverage // 默认: 5x -btcethMaxLeverage := config.RiskControl.BTCETHMaxLeverage // 默认: 5x -minRiskRewardRatio := config.RiskControl.MinRiskRewardRatio // 默认: 1:3 -minConfidence := config.RiskControl.MinConfidence // 默认: 75 +altcoinMaxLeverage := config.RiskControl.AltcoinMaxLeverage // Default: 5x +btcethMaxLeverage := config.RiskControl.BTCETHMaxLeverage // Default: 5x +minRiskRewardRatio := config.RiskControl.MinRiskRewardRatio // Default: 1:3 +minConfidence := config.RiskControl.MinConfidence // Default: 75 ``` -### 3.5 输出格式要求 +### 3.5 Output Format Requirements ```xml -[思维链分析过程] +[Chain of Thought analysis process] @@ -343,32 +345,32 @@ minConfidence := config.RiskControl.MinConfidence // 默认: 75 --- -## 4. 用户提示词 (User Prompt) +## 4. User Prompt -**核心文件:** `decision/engine.go:884-1007` +**Core File:** `decision/engine.go:884-1007` -**入口方法:** `StrategyEngine.BuildUserPrompt(ctx)` +**Entry Method:** `StrategyEngine.BuildUserPrompt(ctx)` -### 4.1 提示词内容结构 +### 4.1 Prompt Content Structure ``` -1. 系统状态 [时间, 周期号, 运行时长] -2. BTC市场概览 [价格, 涨跌幅, MACD, RSI] -3. 账户信息 [权益, 余额%, 盈亏%, 保证金%, 持仓数] -4. 最近成交 [最近10笔已平仓交易] -5. 当前持仓 [详细持仓数据 + 技术指标] -6. 候选币种 [完整市场数据] -7. 量化数据 [资金流向, OI数据] (可选) -8. OI排行数据 [市场OI变化排行] (可选) +1. System Status [Time, cycle number, runtime] +2. BTC Market Overview [Price, change%, MACD, RSI] +3. Account Info [Equity, balance%, PnL%, margin%, positions] +4. Recent Trades [Last 10 closed trades] +5. Current Positions [Detailed position data + indicators] +6. Candidate Coins [Full market data] +7. Quant Data [Capital flow, OI data] (optional) +8. OI Ranking Data [Market OI change ranking] (optional) ``` -### 4.2 账户信息格式 +### 4.2 Account Info Format ``` Account: Equity 1000.00 | Balance 800.00 (80.0%) | PnL +5.5% | Margin 20.0% | Positions 2 ``` -### 4.3 持仓信息格式 +### 4.3 Position Info Format ``` 1. BTCUSDT LONG | Entry 68000.0000 Current 69500.0000 @@ -383,7 +385,7 @@ Account: Equity 1000.00 | Balance 800.00 (80.0%) | PnL +5.5% | Margin 20.0% | Po Funding Rate: 0.0100% ``` -### 4.4 候选币种格式 +### 4.4 Candidate Coin Format ``` ### 1. ETHUSDT (AI500+OI_Top dual signal) @@ -406,11 +408,11 @@ RSI7: [55.0, 56.2, 57.1, 57.8, 58.0] --- -## 5. AI请求 (AI Request) +## 5. AI Request -**核心文件:** `decision/engine.go:222-293`, `mcp/client.go:136-150` +**Core File:** `decision/engine.go:222-293`, `mcp/client.go:136-150` -### 5.1 请求流程 +### 5.1 Request Flow ```go // decision/engine.go:263-268 @@ -419,10 +421,10 @@ aiResponse, err := mcpClient.CallWithMessages(systemPrompt, userPrompt) aiCallDuration := time.Since(aiCallStart) ``` -### 5.2 支持的AI模型 +### 5.2 Supported AI Models -| 模型 | 客户端文件 | 默认模型 | -|------|-----------|----------| +| Model | Client File | Default Model | +|-------|-------------|---------------| | **DeepSeek** | `mcp/deepseek_client.go` | deepseek-chat | | **Qwen** | `mcp/qwen_client.go` | qwen-max | | **Claude** | `mcp/claude_client.go` | claude-3-5-sonnet | @@ -431,7 +433,7 @@ aiCallDuration := time.Since(aiCallStart) | **OpenAI** | `mcp/openai_client.go` | gpt-5.2 | | **Kimi** | `mcp/kimi_client.go` | moonshot-v1-8k | -### 5.3 请求参数 +### 5.3 Request Parameters ```go // mcp/client.go @@ -442,164 +444,164 @@ RetryDelay: 2 seconds (exponential backoff) --- -## 6. AI响应解析 (Response Parsing) +## 6. AI Response Parsing -**核心文件:** `decision/engine.go:1303-1604` +**Core File:** `decision/engine.go:1303-1604` -**入口方法:** `parseFullDecisionResponse(response, accountEquity, leverage, ratio)` +**Entry Method:** `parseFullDecisionResponse(response, accountEquity, leverage, ratio)` -### 6.1 解析流程 +### 6.1 Parsing Flow ``` -原始AI响应 (文本) +Raw AI Response (text) ↓ -1. 提取思维链 [extractCoTTrace()] +1. Extract Chain of Thought [extractCoTTrace()] ↓ -2. 提取JSON决策 [extractDecisions()] +2. Extract JSON Decision [extractDecisions()] ↓ -3. 验证JSON格式 [validateJSONFormat()] +3. Validate JSON Format [validateJSONFormat()] ↓ -4. 解析JSON [json.Unmarshal()] +4. Parse JSON [json.Unmarshal()] ↓ -5. 验证决策 [validateDecisions()] +5. Validate Decisions [validateDecisions()] ↓ -6. 构建FullDecision [返回结构化结果] +6. Build FullDecision [Return structured result] ``` -### 6.2 思维链提取 +### 6.2 Chain of Thought Extraction ```go // decision/engine.go:1327-1345 func extractCoTTrace(response string) string { - // 优先级1: XML标签 + // Priority 1: XML tag if match := reReasoningTag.FindStringSubmatch(response); len(match) > 1 { return strings.TrimSpace(match[1]) } - // 优先级2: 标签之前的文本 - // 优先级3: JSON [ 之前的文本 - // 优先级4: 完整响应 + // Priority 2: Text before tag + // Priority 3: Text before JSON [ + // Priority 4: Full response } ``` -### 6.3 JSON决策提取 +### 6.3 JSON Decision Extraction ```go // decision/engine.go:1347-1408 func extractDecisions(response string) (string, error) { - // 1. 移除不可见字符 + // 1. Remove invisible characters response = removeInvisibleRunes(response) - // 2. 修复字符编码 + // 2. Fix character encoding response = fixMissingQuotes(response) - // 3. 提取JSON (优先级) - // - XML标签 + ```json - // - 独立 ```json 代码块 - // - 裸JSON数组 + // 3. Extract JSON (priority) + // - XML tag + ```json + // - Standalone ```json code block + // - Bare JSON array } ``` -### 6.4 字符编码修复 +### 6.4 Character Encoding Fix ```go // decision/engine.go:1410-1432 func fixMissingQuotes(s string) string { - // 中文引号 → ASCII + // Chinese quotes → ASCII s = strings.ReplaceAll(s, """, "\"") s = strings.ReplaceAll(s, """, "\"") - // 中文括号 → ASCII + // Chinese brackets → ASCII s = strings.ReplaceAll(s, "[", "[") s = strings.ReplaceAll(s, "]", "]") s = strings.ReplaceAll(s, "{", "{") s = strings.ReplaceAll(s, "}", "}") - // 中文标点 → ASCII + // Chinese punctuation → ASCII s = strings.ReplaceAll(s, ":", ":") s = strings.ReplaceAll(s, ",", ",") } ``` -### 6.5 决策验证 +### 6.5 Decision Validation ```go // decision/engine.go:1480-1602 func validateDecisions(decisions []Decision, equity, leverage, ratio float64) error { for _, d := range decisions { - // 1. 验证action类型 + // 1. Validate action type validActions := []string{"open_long", "open_short", "close_long", "close_short", "hold", "wait"} - // 2. 开仓验证 + // 2. Open position validation if isOpenAction(d.Action) { - // 杠杆范围检查 - // 仓位大小检查 - // 止损止盈检查 - // 风险回报比检查 - // 置信度检查 + // Leverage range check + // Position size check + // Stop loss/take profit check + // Risk/reward ratio check + // Confidence check } - // 3. 平仓验证 + // 3. Close position validation if isCloseAction(d.Action) { - // Symbol必须存在 + // Symbol must exist } } } ``` -### 6.6 Decision结构体 +### 6.6 Decision Structure ```go // decision/engine.go:128-143 type Decision struct { - Symbol string // 交易对: "BTCUSDT" + Symbol string // Trading pair: "BTCUSDT" Action string // "open_long", "open_short", "close_long", "close_short", "hold", "wait" - Leverage int // 杠杆倍数 - PositionSizeUSD float64 // 仓位价值 (USDT) - StopLoss float64 // 止损价格 - TakeProfit float64 // 止盈价格 - Confidence int // 置信度 0-100 - RiskUSD float64 // 最大风险 (USDT) - Reasoning string // 决策理由 + Leverage int // Leverage multiplier + PositionSizeUSD float64 // Position value (USDT) + StopLoss float64 // Stop loss price + TakeProfit float64 // Take profit price + Confidence int // Confidence 0-100 + RiskUSD float64 // Max risk (USDT) + Reasoning string // Decision reasoning } ``` --- -## 7. 决策执行 (Execution) +## 7. Decision Execution -**核心文件:** `trader/auto_trader.go:392-560` +**Core File:** `trader/auto_trader.go:392-560` -### 7.1 决策排序 +### 7.1 Decision Sorting ```go // trader/auto_trader.go:519-526 sort.SliceStable(decisions, func(i, j int) bool { priority := map[string]int{ - "close_long": 1, "close_short": 1, // 最高优先级 - "open_long": 2, "open_short": 2, // 次优先级 - "hold": 3, "wait": 3, // 最低优先级 + "close_long": 1, "close_short": 1, // Highest priority + "open_long": 2, "open_short": 2, // Second priority + "hold": 3, "wait": 3, // Lowest priority } return priority[decisions[i].Action] < priority[decisions[j].Action] }) ``` -### 7.2 风控强制执行 +### 7.2 Risk Control Enforcement -**文件:** `trader/auto_trader.go:1769-1851` +**File:** `trader/auto_trader.go:1769-1851` -| 检查项 | 方法 | 动作 | -|--------|------|------| -| 最大持仓数 | `enforceMaxPositions()` | 拒绝新开仓 | -| 仓位价值上限 | `enforcePositionValueRatio()` | 自动缩减仓位 | -| 最小仓位 | `enforceMinPositionSize()` | 拒绝过小订单 | -| 保证金调整 | 自动计算 | 根据可用余额调整 | +| Check | Method | Action | +|-------|--------|--------| +| Max positions | `enforceMaxPositions()` | Reject new opens | +| Position value cap | `enforcePositionValueRatio()` | Auto reduce size | +| Min position | `enforceMinPositionSize()` | Reject small orders | +| Margin adjustment | Auto calculate | Adjust by available balance | -### 7.3 订单执行 +### 7.3 Order Execution ```go // trader/auto_trader.go:1631-1767 func (at *AutoTrader) recordAndConfirmOrder(orderID, symbol, side, action string) { - // 1. 轮询订单状态 (5次重试, 500ms间隔) + // 1. Poll order status (5 retries, 500ms interval) for i := 0; i < 5; i++ { status := at.trader.GetOrderStatus(orderID) if status.Status == "FILLED" { @@ -608,17 +610,17 @@ func (at *AutoTrader) recordAndConfirmOrder(orderID, symbol, side, action string time.Sleep(500 * time.Millisecond) } - // 2. 提取成交信息 + // 2. Extract fill info filledPrice := status.AvgPrice filledQty := status.FilledQty fee := status.Fee - // 3. 记录到数据库 + // 3. Record to database at.store.Position().SaveOrder(...) } ``` -### 7.4 决策日志保存 +### 7.4 Decision Log Saving ```go // trader/auto_trader.go:1235-1256 @@ -626,62 +628,62 @@ record := &store.DecisionRecord{ CycleNumber: cycleNumber, TraderID: traderID, Timestamp: time.Now(), - SystemPrompt: systemPrompt, // 完整系统提示词 - InputPrompt: userPrompt, // 完整用户提示词 - CoTTrace: cotTrace, // AI思维链 - DecisionJSON: decisionsJSON, // 解析后的决策 - RawResponse: rawResponse, // 原始AI响应 - ExecutionLog: executionResults, // 执行结果 - CandidateCoins: candidateCoins, // 候选币种 - Success: success, // 执行状态 + SystemPrompt: systemPrompt, // Full system prompt + InputPrompt: userPrompt, // Full user prompt + CoTTrace: cotTrace, // AI chain of thought + DecisionJSON: decisionsJSON, // Parsed decisions + RawResponse: rawResponse, // Raw AI response + ExecutionLog: executionResults, // Execution results + CandidateCoins: candidateCoins, // Candidate coins + Success: success, // Execution status } at.store.Decision().LogDecision(record) ``` --- -## 核心文件索引 +## Core File Index -| 模块 | 文件 | 关键方法 | -|------|------|----------| -| **主循环** | `trader/auto_trader.go` | `Run()`, `runCycle()`, `buildTradingContext()` | -| **币种选择** | `decision/engine.go:380-454` | `GetCandidateCoins()` | -| **数据获取** | `market/data.go` | `Get()`, `GetWithTimeframes()` | -| **指标计算** | `market/data.go:59-98` | `calculateEMA()`, `calculateMACD()`, `calculateRSI()` | -| **系统提示词** | `decision/engine.go:700-818` | `BuildSystemPrompt()` | -| **用户提示词** | `decision/engine.go:884-1007` | `BuildUserPrompt()` | -| **市场数据格式化** | `decision/engine.go:1029-1099` | `formatMarketData()` | -| **AI请求** | `decision/engine.go:222-293` | `GetFullDecisionWithStrategy()` | -| **MCP客户端** | `mcp/client.go:136-150` | `CallWithMessages()` | -| **响应解析** | `decision/engine.go:1303-1604` | `parseFullDecisionResponse()` | -| **思维链提取** | `decision/engine.go:1327-1345` | `extractCoTTrace()` | -| **JSON提取** | `decision/engine.go:1347-1408` | `extractDecisions()` | -| **决策验证** | `decision/engine.go:1480-1602` | `validateDecisions()` | -| **风控执行** | `trader/auto_trader.go:1769-1851` | `enforceMaxPositions()`, `enforcePositionValueRatio()` | -| **策略配置** | `store/strategy.go` | `StrategyConfig`, `RiskControlConfig` | -| **数据提供者** | `provider/data_provider.go` | `GetAI500Data()`, `GetOITopPositions()` | +| Module | File | Key Methods | +|--------|------|-------------| +| **Main Loop** | `trader/auto_trader.go` | `Run()`, `runCycle()`, `buildTradingContext()` | +| **Coin Selection** | `decision/engine.go:380-454` | `GetCandidateCoins()` | +| **Data Fetching** | `market/data.go` | `Get()`, `GetWithTimeframes()` | +| **Indicator Calc** | `market/data.go:59-98` | `calculateEMA()`, `calculateMACD()`, `calculateRSI()` | +| **System Prompt** | `decision/engine.go:700-818` | `BuildSystemPrompt()` | +| **User Prompt** | `decision/engine.go:884-1007` | `BuildUserPrompt()` | +| **Market Format** | `decision/engine.go:1029-1099` | `formatMarketData()` | +| **AI Request** | `decision/engine.go:222-293` | `GetFullDecisionWithStrategy()` | +| **MCP Client** | `mcp/client.go:136-150` | `CallWithMessages()` | +| **Response Parse** | `decision/engine.go:1303-1604` | `parseFullDecisionResponse()` | +| **CoT Extract** | `decision/engine.go:1327-1345` | `extractCoTTrace()` | +| **JSON Extract** | `decision/engine.go:1347-1408` | `extractDecisions()` | +| **Decision Valid** | `decision/engine.go:1480-1602` | `validateDecisions()` | +| **Risk Enforce** | `trader/auto_trader.go:1769-1851` | `enforceMaxPositions()`, `enforcePositionValueRatio()` | +| **Strategy Config** | `store/strategy.go` | `StrategyConfig`, `RiskControlConfig` | +| **Data Provider** | `provider/data_provider.go` | `GetAI500Data()`, `GetOITopPositions()` | --- -## 配置参考 +## Configuration Reference -### 策略配置结构 +### Strategy Config Structure ```go // store/strategy.go type StrategyConfig struct { - // 币种来源 + // Coin Source CoinSource struct { SourceType string // "static", "coinpool", "oi_top", "mixed" - StaticCoins []string // 静态币种列表 - UseCoinPool bool // 是否使用AI500 - UseOITop bool // 是否使用OI排行 - CoinPoolLimit int // AI500获取数量 - CoinPoolAPIURL string // AI500 API地址 - OITopAPIURL string // OI排行 API地址 + StaticCoins []string // Static coin list + UseCoinPool bool // Use AI500 + UseOITop bool // Use OI ranking + CoinPoolLimit int // AI500 fetch limit + CoinPoolAPIURL string // AI500 API URL + OITopAPIURL string // OI ranking API URL } - // 技术指标 + // Technical Indicators Indicators struct { EnableEMA bool EMAPeriods []int // [20, 50] @@ -703,20 +705,20 @@ type StrategyConfig struct { } } - // 风控配置 + // Risk Control RiskControl struct { - MaxPositions int // 最大持仓数 - BTCETHMaxLeverage int // BTC/ETH最大杠杆 - AltcoinMaxLeverage int // 山寨币最大杠杆 - BTCETHMaxPositionValueRatio float64 // BTC/ETH仓位比例上限 - AltcoinMaxPositionValueRatio float64 // 山寨币仓位比例上限 - MaxMarginUsage float64 // 最大保证金使用率 - MinPositionSize float64 // 最小仓位 - MinRiskRewardRatio float64 // 最小风险回报比 - MinConfidence int // 最小置信度 + MaxPositions int // Max positions + BTCETHMaxLeverage int // BTC/ETH max leverage + AltcoinMaxLeverage int // Altcoin max leverage + BTCETHMaxPositionValueRatio float64 // BTC/ETH position ratio cap + AltcoinMaxPositionValueRatio float64 // Altcoin position ratio cap + MaxMarginUsage float64 // Max margin usage + MinPositionSize float64 // Min position size + MinRiskRewardRatio float64 // Min risk/reward ratio + MinConfidence int // Min confidence } - // 提示词部分 + // Prompt Sections PromptSections struct { RoleDefinition string TradingFrequency string @@ -724,12 +726,12 @@ type StrategyConfig struct { DecisionProcess string } - // 自定义提示词 + // Custom Prompt CustomPrompt string } ``` --- -**文档版本:** 1.0.0 -**最后更新:** 2025-01-15 +**Document Version:** 1.0.0 +**Last Updated:** 2025-01-15 diff --git a/docs/architecture/STRATEGY_MODULE.zh-CN.md b/docs/architecture/STRATEGY_MODULE.zh-CN.md new file mode 100644 index 00000000..1ef8c8e3 --- /dev/null +++ b/docs/architecture/STRATEGY_MODULE.zh-CN.md @@ -0,0 +1,737 @@ +# NOFX 策略模块技术文档 + +**语言:** [English](STRATEGY_MODULE.md) | [中文](STRATEGY_MODULE.zh-CN.md) + +## 概述 + +本文档详细描述 NOFX 策略模块的完整数据流程,包括币种选择、数据组装、提示词构建、AI 请求、响应解析和决策执行。 + +--- + +## 完整数据流程图 + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ 交易周期 (每 N 分钟) │ +└─────────────────────────────────────────────────────────────────┘ + +1. 币种选择 (GetCandidateCoins) + ├─ Static (静态列表) + ├─ AI500 Pool (AI评分池) + ├─ OI Top (持仓增长榜) + └─ Mixed (混合模式) + ↓ +2. 数据组装 (buildTradingContext) + ├─ 账户余额 → equity, available, unrealizedPnL + ├─ 当前持仓 → symbol, side, entry, mark, qty, leverage + ├─ K线数据 → OHLCV (5m, 15m, 1h, 4h) + ├─ 技术指标 → EMA, MACD, RSI, ATR, Volume + ├─ 链上数据 → OI, Funding Rate + ├─ 量化数据 → 资金流向, OI变化 (可选) + └─ 最近交易 → 最近10笔已平仓 + ↓ +3. 系统提示词 (BuildSystemPrompt) + ├─ 角色定义 + ├─ 交易模式 (aggressive/conservative/scalping) + ├─ 硬性约束 (代码强制执行) + ├─ AI引导 (建议值) + ├─ 交易频率 + ├─ 入场标准 + ├─ 决策流程 + └─ 输出格式 (XML + JSON) + ↓ +4. 用户提示词 (BuildUserPrompt) + ├─ 系统状态 (时间, 周期号) + ├─ BTC市场概览 + ├─ 账户信息 + ├─ 当前持仓 (含技术指标) + ├─ 候选币种 (完整市场数据) + └─ "请分析并输出决策..." + ↓ +5. AI请求 (CallWithMessages) + ├─ 选择AI模型 + ├─ POST: system_prompt + user_prompt + ├─ 超时: 120秒, 重试: 3次 + └─ 返回原始响应 + ↓ +6. AI解析 (parseFullDecisionResponse) + ├─ 提取思维链 + ├─ 提取JSON决策 + ├─ 修复字符编码 + ├─ 验证JSON格式 + ├─ 解析决策数组 + └─ 验证风控参数 + ↓ +7. 决策执行 + ├─ 排序: 平仓优先 → 开仓 → hold/wait + ├─ 风控强制执行 + ├─ 提交订单 + ├─ 确认成交 + └─ 记录到数据库 +``` + +--- + +## 1. 币种选择 (Coin Selection) + +**核心文件:** `decision/engine.go:380-454` + +**入口方法:** `StrategyEngine.GetCandidateCoins()` + +### 1.1 静态币种列表 (Static) + +```go +// decision/engine.go:395-403 +if config.CoinSource.SourceType == "static" { + for _, symbol := range config.CoinSource.StaticCoins { + coins = append(coins, CandidateCoin{ + Symbol: market.Normalize(symbol), + Sources: []string{"static"}, + }) + } +} +``` + +- **配置:** `StrategyConfig.CoinSource.StaticCoins` +- **用途:** 手动指定交易币种 +- **标签:** `["static"]` + +### 1.2 AI500 币种池 (CoinPool) + +```go +// decision/engine.go:405-406, 456-474 +func (e *StrategyEngine) getCoinPoolCoins(limit int) []CandidateCoin { + coins, err := e.provider.GetTopRatedCoins(limit) + // ... + for _, coin := range coins { + result = append(result, CandidateCoin{ + Symbol: coin.Symbol, + Sources: []string{"ai500"}, + }) + } +} +``` + +- **API:** `config.CoinSource.CoinPoolAPIURL` (默认: `http://nofxaios.com:30006/api/ai500/list`) +- **用途:** 获取 AI 评分最高的 N 个币种 +- **标签:** `["ai500"]` + +### 1.3 OI Top 币种 (持仓增长榜) + +```go +// decision/engine.go:408-409, 476-498 +func (e *StrategyEngine) getOITopCoins() []CandidateCoin { + positions, err := e.provider.GetOITopPositions() + // ... + for _, pos := range positions { + result = append(result, CandidateCoin{ + Symbol: pos.Symbol, + Sources: []string{"oi_top"}, + }) + } +} +``` + +- **API:** `config.CoinSource.OITopAPIURL` +- **用途:** 获取持仓量增长最快的币种 +- **标签:** `["oi_top"]` + +### 1.4 混合模式 (Mixed) + +```go +// decision/engine.go:411-449 +if config.CoinSource.SourceType == "mixed" { + if config.CoinSource.UseCoinPool { + // 添加 AI500 币种 + } + if config.CoinSource.UseOITop { + // 添加 OI Top 币种 + } + if len(config.CoinSource.StaticCoins) > 0 { + // 添加静态币种 + } + // 去重合并,保留多来源标签 +} +``` + +- **特点:** 同时使用多个数据源 +- **标签示例:** `["ai500", "oi_top"]` (双信号币种) + +--- + +## 2. 数据组装 (Data Assembly) + +**核心文件:** `trader/auto_trader.go:562-791`, `decision/engine.go:299-374` + +**入口方法:** `AutoTrader.buildTradingContext()` + +### 2.1 账户数据 + +```go +// trader/auto_trader.go:565-583 +balance, err := at.trader.GetBalance() +equity := balance["total_equity"].(float64) +available := balance["available_balance"].(float64) +unrealizedPnL := balance["total_pnl"].(float64) +``` + +**提取字段:** +- `total_equity` - 账户总权益 +- `available_balance` - 可用余额 +- `total_pnl` - 未实现盈亏 + +### 2.2 持仓数据 + +```go +// trader/auto_trader.go:588-682 +positions, err := at.trader.GetPositions() +for _, pos := range positions { + position := decision.Position{ + Symbol: pos.Symbol, + Side: pos.Side, // "long" / "short" + EntryPrice: pos.EntryPrice, + MarkPrice: pos.MarkPrice, + Quantity: pos.Quantity, + Leverage: pos.Leverage, + UnrealizedPnL: pos.UnrealizedPnL, + LiquidationPrice: pos.LiquidationPrice, + } +} +``` + +### 2.3 市场数据获取 + +```go +// decision/engine.go:299-374 +func (e *StrategyEngine) fetchMarketDataWithStrategy(symbols []string) map[string]*market.Data { + timeframes := config.Indicators.Klines.SelectedTimeframes // ["5m", "15m", "1h", "4h"] + primaryTF := config.Indicators.Klines.PrimaryTimeframe // "5m" + count := config.Indicators.Klines.PrimaryCount // 30 + + for _, symbol := range symbols { + data := market.GetWithTimeframes(symbol, timeframes, primaryTF, count) + result[symbol] = data + } +} +``` + +### 2.4 技术指标计算 + +**文件:** `market/data.go:59-98` + +| 指标 | 配置 | 计算方法 | +|------|------|----------| +| **EMA** | `EnableEMA`, `EMAPeriods` | `calculateEMA(klines, period)` | +| **MACD** | `EnableMACD` | `calculateMACD(klines)` - 12/26/9 | +| **RSI** | `EnableRSI`, `RSIPeriods` | `calculateRSI(klines, period)` | +| **ATR** | `EnableATR`, `ATRPeriods` | `calculateATR(klines, period)` | +| **Volume** | `EnableVolume` | 原始成交量数据 | +| **OI** | `EnableOI` | 持仓量数据 | +| **Funding Rate** | `EnableFundingRate` | 资金费率 | + +### 2.5 量化数据 (可选) + +```go +// trader/auto_trader.go:759-778 +if config.Indicators.EnableQuantData { + quantData := provider.GetQuantData(symbol) + // 包含: 资金流向、OI变化、价格变化 +} +``` + +**数据结构:** +```go +QuantData { + Netflow { + Institution: {Future, Spot}, // 机构资金流 + Personal: {Future, Spot} // 散户资金流 + }, + OI { + CurrentOI: float64, + Delta: {1h, 4h, 24h} // OI变化 + }, + PriceChange { + "1h", "4h", "24h": float64 // 价格变化百分比 + } +} +``` + +--- + +## 3. 系统提示词 (System Prompt) + +**核心文件:** `decision/engine.go:700-818` + +**入口方法:** `StrategyEngine.BuildSystemPrompt(accountEquity, variant)` + +### 3.1 提示词结构 (8个部分) + +``` +1. 角色定义 [可编辑] +2. 交易模式变体 [运行时确定] +3. 硬性约束 [代码强制 + AI引导] +4. 交易频率 [可编辑] +5. 入场标准 [可编辑] +6. 决策流程 [可编辑] +7. 输出格式 [固定XML + JSON结构] +8. 自定义提示词 [可选] +``` + +### 3.2 角色定义 + +```go +// decision/engine.go:706-713 +roleDefinition := config.PromptSections.RoleDefinition +if roleDefinition == "" { + roleDefinition = "You are a professional cryptocurrency trading AI..." +} +``` + +### 3.3 交易模式变体 + +| 模式 | 特点 | +|------|------| +| `aggressive` | 趋势突破,较高仓位容忍度 | +| `conservative` | 多信号确认,保守资金管理 | +| `scalping` | 短线动量,紧止盈 | + +### 3.4 硬性约束 + +**代码强制执行 (CODE ENFORCED):** + +```go +// decision/engine.go:725-749 +maxPositions := config.RiskControl.MaxPositions // 默认: 3 +altcoinMaxRatio := config.RiskControl.AltcoinMaxPositionValueRatio // 默认: 1.0 +btcethMaxRatio := config.RiskControl.BTCETHMaxPositionValueRatio // 默认: 5.0 +maxMarginUsage := config.RiskControl.MaxMarginUsage // 默认: 90% +minPositionSize := config.RiskControl.MinPositionSize // 默认: 12 USDT +``` + +**AI引导 (建议值):** + +```go +altcoinMaxLeverage := config.RiskControl.AltcoinMaxLeverage // 默认: 5x +btcethMaxLeverage := config.RiskControl.BTCETHMaxLeverage // 默认: 5x +minRiskRewardRatio := config.RiskControl.MinRiskRewardRatio // 默认: 1:3 +minConfidence := config.RiskControl.MinConfidence // 默认: 75 +``` + +### 3.5 输出格式要求 + +```xml + +[思维链分析过程] + + + +```json +[ + { + "symbol": "BTCUSDT", + "action": "open_long", + "leverage": 5, + "position_size_usd": 100.00, + "stop_loss": 65000.00, + "take_profit": 72000.00, + "confidence": 85, + "risk_usd": 20.00, + "reasoning": "..." + } +] +``` + +``` + +--- + +## 4. 用户提示词 (User Prompt) + +**核心文件:** `decision/engine.go:884-1007` + +**入口方法:** `StrategyEngine.BuildUserPrompt(ctx)` + +### 4.1 提示词内容结构 + +``` +1. 系统状态 [时间, 周期号, 运行时长] +2. BTC市场概览 [价格, 涨跌幅, MACD, RSI] +3. 账户信息 [权益, 余额%, 盈亏%, 保证金%, 持仓数] +4. 最近成交 [最近10笔已平仓交易] +5. 当前持仓 [详细持仓数据 + 技术指标] +6. 候选币种 [完整市场数据] +7. 量化数据 [资金流向, OI数据] (可选) +8. OI排行数据 [市场OI变化排行] (可选) +``` + +### 4.2 账户信息格式 + +``` +Account: Equity 1000.00 | Balance 800.00 (80.0%) | PnL +5.5% | Margin 20.0% | Positions 2 +``` + +### 4.3 持仓信息格式 + +``` +1. BTCUSDT LONG | Entry 68000.0000 Current 69500.0000 + Qty 0.0100 | Position Value $695.00 + PnL +2.21% | Amount +$15.00 + Peak PnL +3.50% | Leverage 5x + Margin $139.00 | Liquidation Price 55000.0000 + Holding Duration 2 hours 30 minutes + + Market: price=69500, ema20=68800, macd=150.5, rsi7=62.3 + OI: Latest=15000000, Avg=14500000 + Funding Rate: 0.0100% +``` + +### 4.4 候选币种格式 + +``` +### 1. ETHUSDT (AI500+OI_Top dual signal) + +current_price = 3500.00, current_ema20 = 3450.00, current_macd = 25.5, current_rsi7 = 58.0 + +Open Interest: Latest: 8500000.00 Average: 8200000.00 +Funding Rate: 0.0050 + +=== 5M TIMEFRAME (oldest → latest) === +Prices: [3480, 3485, 3490, 3495, 3500] +Volumes: [1000, 1200, 1100, 1300, 1150] +EMA20: [3470, 3475, 3478, 3482, 3485] +MACD: [20.1, 21.5, 22.8, 24.0, 25.5] +RSI7: [55.0, 56.2, 57.1, 57.8, 58.0] + +=== 15M TIMEFRAME === +... +``` + +--- + +## 5. AI请求 (AI Request) + +**核心文件:** `decision/engine.go:222-293`, `mcp/client.go:136-150` + +### 5.1 请求流程 + +```go +// decision/engine.go:263-268 +aiCallStart := time.Now() +aiResponse, err := mcpClient.CallWithMessages(systemPrompt, userPrompt) +aiCallDuration := time.Since(aiCallStart) +``` + +### 5.2 支持的AI模型 + +| 模型 | 客户端文件 | 默认模型 | +|------|-----------|----------| +| **DeepSeek** | `mcp/deepseek_client.go` | deepseek-chat | +| **Qwen** | `mcp/qwen_client.go` | qwen-max | +| **Claude** | `mcp/claude_client.go` | claude-3-5-sonnet | +| **Gemini** | `mcp/gemini_client.go` | gemini-pro | +| **Grok** | `mcp/grok_client.go` | grok-beta | +| **OpenAI** | `mcp/openai_client.go` | gpt-5.2 | +| **Kimi** | `mcp/kimi_client.go` | moonshot-v1-8k | + +### 5.3 请求参数 + +```go +// mcp/client.go +Timeout: 120 seconds +MaxRetries: 3 +RetryDelay: 2 seconds (exponential backoff) +``` + +--- + +## 6. AI响应解析 (Response Parsing) + +**核心文件:** `decision/engine.go:1303-1604` + +**入口方法:** `parseFullDecisionResponse(response, accountEquity, leverage, ratio)` + +### 6.1 解析流程 + +``` +原始AI响应 (文本) + ↓ +1. 提取思维链 [extractCoTTrace()] + ↓ +2. 提取JSON决策 [extractDecisions()] + ↓ +3. 验证JSON格式 [validateJSONFormat()] + ↓ +4. 解析JSON [json.Unmarshal()] + ↓ +5. 验证决策 [validateDecisions()] + ↓ +6. 构建FullDecision [返回结构化结果] +``` + +### 6.2 思维链提取 + +```go +// decision/engine.go:1327-1345 +func extractCoTTrace(response string) string { + // 优先级1: XML标签 + if match := reReasoningTag.FindStringSubmatch(response); len(match) > 1 { + return strings.TrimSpace(match[1]) + } + // 优先级2: 标签之前的文本 + // 优先级3: JSON [ 之前的文本 + // 优先级4: 完整响应 +} +``` + +### 6.3 JSON决策提取 + +```go +// decision/engine.go:1347-1408 +func extractDecisions(response string) (string, error) { + // 1. 移除不可见字符 + response = removeInvisibleRunes(response) + + // 2. 修复字符编码 + response = fixMissingQuotes(response) + + // 3. 提取JSON (优先级) + // - XML标签 + ```json + // - 独立 ```json 代码块 + // - 裸JSON数组 +} +``` + +### 6.4 字符编码修复 + +```go +// decision/engine.go:1410-1432 +func fixMissingQuotes(s string) string { + // 中文引号 → ASCII + s = strings.ReplaceAll(s, """, "\"") + s = strings.ReplaceAll(s, """, "\"") + + // 中文括号 → ASCII + s = strings.ReplaceAll(s, "[", "[") + s = strings.ReplaceAll(s, "]", "]") + s = strings.ReplaceAll(s, "{", "{") + s = strings.ReplaceAll(s, "}", "}") + + // 中文标点 → ASCII + s = strings.ReplaceAll(s, ":", ":") + s = strings.ReplaceAll(s, ",", ",") +} +``` + +### 6.5 决策验证 + +```go +// decision/engine.go:1480-1602 +func validateDecisions(decisions []Decision, equity, leverage, ratio float64) error { + for _, d := range decisions { + // 1. 验证action类型 + validActions := []string{"open_long", "open_short", "close_long", "close_short", "hold", "wait"} + + // 2. 开仓验证 + if isOpenAction(d.Action) { + // 杠杆范围检查 + // 仓位大小检查 + // 止损止盈检查 + // 风险回报比检查 + // 置信度检查 + } + + // 3. 平仓验证 + if isCloseAction(d.Action) { + // Symbol必须存在 + } + } +} +``` + +### 6.6 Decision结构体 + +```go +// decision/engine.go:128-143 +type Decision struct { + Symbol string // 交易对: "BTCUSDT" + Action string // "open_long", "open_short", "close_long", "close_short", "hold", "wait" + Leverage int // 杠杆倍数 + PositionSizeUSD float64 // 仓位价值 (USDT) + StopLoss float64 // 止损价格 + TakeProfit float64 // 止盈价格 + Confidence int // 置信度 0-100 + RiskUSD float64 // 最大风险 (USDT) + Reasoning string // 决策理由 +} +``` + +--- + +## 7. 决策执行 (Execution) + +**核心文件:** `trader/auto_trader.go:392-560` + +### 7.1 决策排序 + +```go +// trader/auto_trader.go:519-526 +sort.SliceStable(decisions, func(i, j int) bool { + priority := map[string]int{ + "close_long": 1, "close_short": 1, // 最高优先级 + "open_long": 2, "open_short": 2, // 次优先级 + "hold": 3, "wait": 3, // 最低优先级 + } + return priority[decisions[i].Action] < priority[decisions[j].Action] +}) +``` + +### 7.2 风控强制执行 + +**文件:** `trader/auto_trader.go:1769-1851` + +| 检查项 | 方法 | 动作 | +|--------|------|------| +| 最大持仓数 | `enforceMaxPositions()` | 拒绝新开仓 | +| 仓位价值上限 | `enforcePositionValueRatio()` | 自动缩减仓位 | +| 最小仓位 | `enforceMinPositionSize()` | 拒绝过小订单 | +| 保证金调整 | 自动计算 | 根据可用余额调整 | + +### 7.3 订单执行 + +```go +// trader/auto_trader.go:1631-1767 +func (at *AutoTrader) recordAndConfirmOrder(orderID, symbol, side, action string) { + // 1. 轮询订单状态 (5次重试, 500ms间隔) + for i := 0; i < 5; i++ { + status := at.trader.GetOrderStatus(orderID) + if status.Status == "FILLED" { + break + } + time.Sleep(500 * time.Millisecond) + } + + // 2. 提取成交信息 + filledPrice := status.AvgPrice + filledQty := status.FilledQty + fee := status.Fee + + // 3. 记录到数据库 + at.store.Position().SaveOrder(...) +} +``` + +### 7.4 决策日志保存 + +```go +// trader/auto_trader.go:1235-1256 +record := &store.DecisionRecord{ + CycleNumber: cycleNumber, + TraderID: traderID, + Timestamp: time.Now(), + SystemPrompt: systemPrompt, // 完整系统提示词 + InputPrompt: userPrompt, // 完整用户提示词 + CoTTrace: cotTrace, // AI思维链 + DecisionJSON: decisionsJSON, // 解析后的决策 + RawResponse: rawResponse, // 原始AI响应 + ExecutionLog: executionResults, // 执行结果 + CandidateCoins: candidateCoins, // 候选币种 + Success: success, // 执行状态 +} +at.store.Decision().LogDecision(record) +``` + +--- + +## 核心文件索引 + +| 模块 | 文件 | 关键方法 | +|------|------|----------| +| **主循环** | `trader/auto_trader.go` | `Run()`, `runCycle()`, `buildTradingContext()` | +| **币种选择** | `decision/engine.go:380-454` | `GetCandidateCoins()` | +| **数据获取** | `market/data.go` | `Get()`, `GetWithTimeframes()` | +| **指标计算** | `market/data.go:59-98` | `calculateEMA()`, `calculateMACD()`, `calculateRSI()` | +| **系统提示词** | `decision/engine.go:700-818` | `BuildSystemPrompt()` | +| **用户提示词** | `decision/engine.go:884-1007` | `BuildUserPrompt()` | +| **市场数据格式化** | `decision/engine.go:1029-1099` | `formatMarketData()` | +| **AI请求** | `decision/engine.go:222-293` | `GetFullDecisionWithStrategy()` | +| **MCP客户端** | `mcp/client.go:136-150` | `CallWithMessages()` | +| **响应解析** | `decision/engine.go:1303-1604` | `parseFullDecisionResponse()` | +| **思维链提取** | `decision/engine.go:1327-1345` | `extractCoTTrace()` | +| **JSON提取** | `decision/engine.go:1347-1408` | `extractDecisions()` | +| **决策验证** | `decision/engine.go:1480-1602` | `validateDecisions()` | +| **风控执行** | `trader/auto_trader.go:1769-1851` | `enforceMaxPositions()`, `enforcePositionValueRatio()` | +| **策略配置** | `store/strategy.go` | `StrategyConfig`, `RiskControlConfig` | +| **数据提供者** | `provider/data_provider.go` | `GetAI500Data()`, `GetOITopPositions()` | + +--- + +## 配置参考 + +### 策略配置结构 + +```go +// store/strategy.go +type StrategyConfig struct { + // 币种来源 + CoinSource struct { + SourceType string // "static", "coinpool", "oi_top", "mixed" + StaticCoins []string // 静态币种列表 + UseCoinPool bool // 是否使用AI500 + UseOITop bool // 是否使用OI排行 + CoinPoolLimit int // AI500获取数量 + CoinPoolAPIURL string // AI500 API地址 + OITopAPIURL string // OI排行 API地址 + } + + // 技术指标 + Indicators struct { + EnableEMA bool + EMAPeriods []int // [20, 50] + EnableMACD bool + EnableRSI bool + RSIPeriods []int // [7, 14] + EnableATR bool + ATRPeriods []int // [14] + EnableVolume bool + EnableOI bool + EnableFundingRate bool + EnableQuantData bool + EnableOIRanking bool + + Klines struct { + PrimaryTimeframe string // "5m" + SelectedTimeframes []string // ["5m", "15m", "1h", "4h"] + PrimaryCount int // 30 + } + } + + // 风控配置 + RiskControl struct { + MaxPositions int // 最大持仓数 + BTCETHMaxLeverage int // BTC/ETH最大杠杆 + AltcoinMaxLeverage int // 山寨币最大杠杆 + BTCETHMaxPositionValueRatio float64 // BTC/ETH仓位比例上限 + AltcoinMaxPositionValueRatio float64 // 山寨币仓位比例上限 + MaxMarginUsage float64 // 最大保证金使用率 + MinPositionSize float64 // 最小仓位 + MinRiskRewardRatio float64 // 最小风险回报比 + MinConfidence int // 最小置信度 + } + + // 提示词部分 + PromptSections struct { + RoleDefinition string + TradingFrequency string + EntryStandards string + DecisionProcess string + } + + // 自定义提示词 + CustomPrompt string +} +``` + +--- + +**文档版本:** 1.0.0 +**最后更新:** 2025-01-15