mirror of
https://github.com/NoFxAiOS/nofx.git
synced 2026-07-14 08:16:56 +08:00
docs: add bilingual module documentation (EN/ZH)
This commit is contained in:
@@ -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()
|
2. Manager.Start()
|
||||||
├─ 验证配置
|
├─ Validate config
|
||||||
├─ 解析 AI 模型
|
├─ Parse AI model
|
||||||
├─ 创建 Runner 实例
|
├─ Create Runner instance
|
||||||
└─ 启动 runner.Start() (goroutine)
|
└─ Start runner.Start() (goroutine)
|
||||||
↓
|
↓
|
||||||
3. Runner.Start() → Runner.loop()
|
3. Runner.Start() → Runner.loop()
|
||||||
└─ 遍历每个决策时间点:
|
└─ Iterate each decision time point:
|
||||||
├─ DataFeed.BuildMarketData() [构建市场数据]
|
├─ DataFeed.BuildMarketData() [Build market data]
|
||||||
├─ 检查决策触发条件 [每 N 根 K 线]
|
├─ Check decision trigger [Every N bars]
|
||||||
├─ buildDecisionContext() [构建决策上下文]
|
├─ buildDecisionContext() [Build decision context]
|
||||||
├─ invokeAIWithRetry() [调用 AI + 缓存]
|
├─ invokeAIWithRetry() [Call AI + cache]
|
||||||
├─ executeDecision() [执行交易]
|
├─ executeDecision() [Execute trades]
|
||||||
├─ checkLiquidation() [检查爆仓]
|
├─ checkLiquidation() [Check liquidation]
|
||||||
├─ updateState() [更新状态]
|
├─ updateState() [Update state]
|
||||||
├─ appendEquityPoint() [记录权益]
|
├─ appendEquityPoint() [Record equity]
|
||||||
├─ appendTradeEvent() [记录交易]
|
├─ appendTradeEvent() [Record trades]
|
||||||
├─ maybeCheckpoint() [保存检查点]
|
├─ maybeCheckpoint() [Save checkpoint]
|
||||||
└─ persistMetrics() [持久化指标]
|
└─ 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
|
||||||
|
|
||||||
| 参数 | 类型 | 默认值 | 说明 |
|
| Parameter | Type | Default | Description |
|
||||||
|------|------|--------|------|
|
|-----------|------|---------|-------------|
|
||||||
| `RunID` | string | (必填) | 回测运行唯一标识 |
|
| `RunID` | string | (required) | Unique backtest run ID |
|
||||||
| `UserID` | string | "default" | 用户 ID |
|
| `UserID` | string | "default" | User ID |
|
||||||
| `Symbols` | []string | (必填) | 交易币种列表 |
|
| `Symbols` | []string | (required) | Trading symbols list |
|
||||||
| `Timeframes` | []string | ["3m", "15m", "4h"] | K 线周期 |
|
| `Timeframes` | []string | ["3m", "15m", "4h"] | K-line timeframes |
|
||||||
| `DecisionTimeframe` | string | Symbols[0] | 主决策周期 |
|
| `DecisionTimeframe` | string | Symbols[0] | Primary decision timeframe |
|
||||||
| `DecisionCadenceNBars` | int | 20 | 每 N 根 K 线触发一次决策 |
|
| `DecisionCadenceNBars` | int | 20 | Trigger decision every N bars |
|
||||||
| `StartTS`, `EndTS` | int64 | (必填) | 回测时间范围 (Unix 时间戳) |
|
| `StartTS`, `EndTS` | int64 | (required) | Backtest time range (Unix timestamp) |
|
||||||
| `InitialBalance` | float64 | 1000 | 初始资金 (USD) |
|
| `InitialBalance` | float64 | 1000 | Initial balance (USD) |
|
||||||
| `FeeBps` | float64 | 5 | 手续费 (基点) |
|
| `FeeBps` | float64 | 5 | Trading fee (basis points) |
|
||||||
| `SlippageBps` | float64 | 2 | 滑点 (基点) |
|
| `SlippageBps` | float64 | 2 | Slippage (basis points) |
|
||||||
| `FillPolicy` | string | "next_open" | 成交策略 |
|
| `FillPolicy` | string | "next_open" | Fill policy |
|
||||||
| `PromptVariant` | string | "baseline" | AI 提示词变体 |
|
| `PromptVariant` | string | "baseline" | AI prompt variant |
|
||||||
| `CacheAI` | bool | false | 是否缓存 AI 决策 |
|
| `CacheAI` | bool | false | Cache AI decisions |
|
||||||
| `Leverage` | LeverageConfig | BTC/ETH:5, Altcoin:5 | 杠杆设置 |
|
| `Leverage` | LeverageConfig | BTC/ETH:5, Altcoin:5 | Leverage settings |
|
||||||
|
|
||||||
### 1.2 成交策略 (Fill Policy)
|
### 1.2 Fill Policy
|
||||||
|
|
||||||
```go
|
```go
|
||||||
// backtest/config.go:163-179
|
// backtest/config.go:163-179
|
||||||
switch fillPolicy {
|
switch fillPolicy {
|
||||||
case "next_open": // 下一根 K 线开盘价
|
case "next_open": // Next bar open price
|
||||||
case "bar_vwap": // 当前 K 线 VWAP
|
case "bar_vwap": // Current bar VWAP
|
||||||
case "mid": // 当前 K 线 (High+Low)/2
|
case "mid": // Current bar (High+Low)/2
|
||||||
default: // Mark Price
|
default: // Mark Price
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### 1.3 配置示例
|
### 1.3 Config Example
|
||||||
|
|
||||||
```go
|
```go
|
||||||
cfg := backtest.BacktestConfig{
|
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() - 加载所有历史数据
|
2. loadAll() - Load all historical data
|
||||||
├─ 计算缓冲区 (StartTS 前 200 根 K 线)
|
├─ Calculate buffer (200 bars before StartTS)
|
||||||
├─ 调用 market.GetKlinesRange() 获取数据
|
├─ Call market.GetKlinesRange() to fetch data
|
||||||
├─ 存储到 symbolSeries map
|
├─ Store in symbolSeries map
|
||||||
└─ 从主周期构建决策时间线
|
└─ Build decision timeline from primary timeframe
|
||||||
↓
|
↓
|
||||||
3. BuildMarketData() - 构建市场数据快照
|
3. BuildMarketData() - Build market data snapshot
|
||||||
├─ 切片 K 线数据到当前时间戳
|
├─ Slice K-line data to current timestamp
|
||||||
├─ 计算技术指标 (EMA, MACD, RSI, ATR)
|
├─ Calculate technical indicators (EMA, MACD, RSI, ATR)
|
||||||
└─ 返回 market.Data 结构
|
└─ Return market.Data structure
|
||||||
```
|
```
|
||||||
|
|
||||||
### 2.2 数据结构
|
### 2.2 Data Structure
|
||||||
|
|
||||||
```go
|
```go
|
||||||
// DataFeed 核心结构
|
// DataFeed core structure
|
||||||
type DataFeed struct {
|
type DataFeed struct {
|
||||||
decisionTimes []int64 // 决策时间点列表
|
decisionTimes []int64 // Decision time points list
|
||||||
symbolSeries map[string]*symbolSeries // 按币种存储的数据
|
symbolSeries map[string]*symbolSeries // Data stored by symbol
|
||||||
}
|
}
|
||||||
|
|
||||||
// 单币种时间序列
|
// Single symbol time series
|
||||||
type symbolSeries struct {
|
type symbolSeries struct {
|
||||||
timeframes map[string]*timeframeSeries // 按周期存储
|
timeframes map[string]*timeframeSeries // Stored by timeframe
|
||||||
}
|
}
|
||||||
|
|
||||||
// 单周期数据
|
// Single timeframe data
|
||||||
type timeframeSeries struct {
|
type timeframeSeries struct {
|
||||||
klines []market.Kline // K 线数据
|
klines []market.Kline // K-line data
|
||||||
closeTimes []int64 // 收盘时间索引
|
closeTimes []int64 // Close time index
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### 2.3 关键代码引用
|
### 2.3 Key Code References
|
||||||
|
|
||||||
- 数据获取: `backtest/datafeed.go:48-93`
|
- Data fetching: `backtest/datafeed.go:48-93`
|
||||||
- 时间线生成: `backtest/datafeed.go:96-115`
|
- Timeline generation: `backtest/datafeed.go:96-115`
|
||||||
- 市场数据组装: `backtest/datafeed.go:141-171`
|
- 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
|
```go
|
||||||
// backtest/runner.go:232-264
|
// backtest/runner.go:232-264
|
||||||
@@ -169,44 +171,44 @@ func (r *Runner) loop() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### 3.2 单步执行
|
### 3.2 Single Step Execution
|
||||||
|
|
||||||
```go
|
```go
|
||||||
// backtest/runner.go:266-471
|
// backtest/runner.go:266-471
|
||||||
func (r *Runner) stepOnce(ts int64) {
|
func (r *Runner) stepOnce(ts int64) {
|
||||||
// 1. 获取当前 K 线时间戳
|
// 1. Get current bar timestamp
|
||||||
// 2. 构建市场数据
|
// 2. Build market data
|
||||||
// 3. 检查决策触发条件 (每 N 根 K 线)
|
// 3. Check decision trigger (every N bars)
|
||||||
// 4. 执行决策周期 (如果触发)
|
// 4. Execute decision cycle (if triggered)
|
||||||
// 5. 检查爆仓
|
// 5. Check liquidation
|
||||||
// 6. 更新状态并记录
|
// 6. Update state and record
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### 3.3 状态管理
|
### 3.3 State Management
|
||||||
|
|
||||||
```go
|
```go
|
||||||
// backtest/types.go:31-47
|
// backtest/types.go:31-47
|
||||||
type BacktestState struct {
|
type BacktestState struct {
|
||||||
BarIndex int // 当前 K 线索引
|
BarIndex int // Current bar index
|
||||||
Cash float64 // 可用余额
|
Cash float64 // Available balance
|
||||||
Equity float64 // 总权益
|
Equity float64 // Total equity
|
||||||
UnrealizedPnL float64 // 未实现盈亏
|
UnrealizedPnL float64 // Unrealized PnL
|
||||||
RealizedPnL float64 // 已实现盈亏
|
RealizedPnL float64 // Realized PnL
|
||||||
MaxEquity float64 // 最高权益
|
MaxEquity float64 // Peak equity
|
||||||
MinEquity float64 // 最低权益
|
MinEquity float64 // Trough equity
|
||||||
MaxDrawdownPct float64 // 最大回撤
|
MaxDrawdownPct float64 // Max drawdown
|
||||||
Positions map[string]*position // 持仓
|
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
|
```go
|
||||||
// backtest/runner.go:473-532
|
// backtest/runner.go:473-532
|
||||||
@@ -226,29 +228,29 @@ func (r *Runner) buildDecisionContext() *decision.Context {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### 4.2 AI 调用
|
### 4.2 AI Invocation
|
||||||
|
|
||||||
```go
|
```go
|
||||||
// backtest/runner.go:544-563
|
// backtest/runner.go:544-563
|
||||||
func (r *Runner) invokeAIWithRetry() (*decision.FullDecision, error) {
|
func (r *Runner) invokeAIWithRetry() (*decision.FullDecision, error) {
|
||||||
// 最多重试 3 次
|
// Max 3 retries
|
||||||
// 指数退避: 500ms, 1000ms, 1500ms
|
// Exponential backoff: 500ms, 1000ms, 1500ms
|
||||||
// 使用 decision.GetFullDecisionWithStrategy() 统一提示词生成
|
// Uses decision.GetFullDecisionWithStrategy() for unified prompt generation
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### 4.3 AI 缓存
|
### 4.3 AI Cache
|
||||||
|
|
||||||
```go
|
```go
|
||||||
// backtest/aicache.go:127-168
|
// backtest/aicache.go:127-168
|
||||||
// 缓存键: SHA256(context payload)
|
// Cache key: SHA256(context payload)
|
||||||
// 包含: variant, timestamp, account, positions, market data
|
// Contains: variant, timestamp, account, positions, market data
|
||||||
```
|
```
|
||||||
|
|
||||||
### 4.4 支持的 AI 模型
|
### 4.4 Supported AI Models
|
||||||
|
|
||||||
| 模型 | 客户端文件 |
|
| Model | Client File |
|
||||||
|------|-----------|
|
|-------|-------------|
|
||||||
| DeepSeek | `mcp/deepseek_client.go` |
|
| DeepSeek | `mcp/deepseek_client.go` |
|
||||||
| Qwen | `mcp/qwen_client.go` |
|
| Qwen | `mcp/qwen_client.go` |
|
||||||
| Claude | `mcp/claude_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
|
||||||
|
|
||||||
| 指标 | 公式 | 代码位置 |
|
| Metric | Formula | Code Location |
|
||||||
|------|------|----------|
|
|--------|---------|---------------|
|
||||||
| **总收益率** | (最终权益 - 初始资金) / 初始资金 × 100 | metrics.go:36-42 |
|
| **Total Return** | (Final Equity - Initial) / Initial × 100 | metrics.go:36-42 |
|
||||||
| **最大回撤** | max((峰值 - 当前) / 峰值 × 100) | metrics.go:64-91 |
|
| **Max Drawdown** | max((Peak - Current) / Peak × 100) | metrics.go:64-91 |
|
||||||
| **夏普比率** | 平均收益 / 收益标准差 | metrics.go:94-138 |
|
| **Sharpe Ratio** | Avg Return / Return StdDev | metrics.go:94-138 |
|
||||||
| **胜率** | 盈利交易数 / 总交易数 × 100 | metrics.go:180-181 |
|
| **Win Rate** | Winning Trades / Total Trades × 100 | metrics.go:180-181 |
|
||||||
| **盈亏比** | 总盈利 / 总亏损 | metrics.go:189-193 |
|
| **Profit Factor** | Total Profit / Total Loss | metrics.go:189-193 |
|
||||||
|
|
||||||
### 5.2 交易统计
|
### 5.2 Trade Statistics
|
||||||
|
|
||||||
```go
|
```go
|
||||||
// backtest/metrics.go:141-225
|
// 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
|
```json
|
||||||
{
|
{
|
||||||
@@ -309,56 +311,56 @@ type TradeMetrics struct {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### 6.2 权益更新
|
### 6.2 Equity Update
|
||||||
|
|
||||||
```go
|
```go
|
||||||
// backtest/runner.go:829-872
|
// backtest/runner.go:829-872
|
||||||
func (r *Runner) updateState() {
|
func (r *Runner) updateState() {
|
||||||
// 1. 计算总权益: cash + margin + 未实现盈亏
|
// 1. Calculate total equity: cash + margin + unrealized PnL
|
||||||
// 2. 追踪峰值 (MaxEquity)
|
// 2. Track peak (MaxEquity)
|
||||||
// 3. 追踪谷值 (MinEquity)
|
// 3. Track trough (MinEquity)
|
||||||
// 4. 重新计算回撤: (MaxEquity - Equity) / MaxEquity × 100
|
// 4. Recalculate drawdown: (MaxEquity - Equity) / MaxEquity × 100
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### 6.3 数据重采样
|
### 6.3 Data Resampling
|
||||||
|
|
||||||
```go
|
```go
|
||||||
// backtest/equity.go:10-50
|
// backtest/equity.go:10-50
|
||||||
func ResampleEquity(points []EquityPoint, timeframe string) []EquityPoint {
|
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/
|
backtests/
|
||||||
├── <run_id>/
|
├── <run_id>/
|
||||||
│ ├── run.json # 运行元数据
|
│ ├── run.json # Run metadata
|
||||||
│ ├── checkpoint.json # 检查点 (用于恢复)
|
│ ├── checkpoint.json # Checkpoint (for resume)
|
||||||
│ ├── equity.jsonl # 权益曲线 (逐行 JSON)
|
│ ├── equity.jsonl # Equity curve (line-delimited JSON)
|
||||||
│ ├── trades.jsonl # 交易记录 (逐行 JSON)
|
│ ├── trades.jsonl # Trade records (line-delimited JSON)
|
||||||
│ ├── metrics.json # 性能指标
|
│ ├── metrics.json # Performance metrics
|
||||||
│ ├── progress.json # 进度信息
|
│ ├── progress.json # Progress info
|
||||||
│ ├── ai_cache.json # AI 决策缓存
|
│ ├── ai_cache.json # AI decision cache
|
||||||
│ └── decision_logs/ # 决策日志
|
│ └── decision_logs/ # Decision logs
|
||||||
│ ├── 0.json
|
│ ├── 0.json
|
||||||
│ ├── 1.json
|
│ ├── 1.json
|
||||||
│ └── ...
|
│ └── ...
|
||||||
```
|
```
|
||||||
|
|
||||||
### 7.2 数据库表结构
|
### 7.2 Database Schema
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
-- 回测运行元数据
|
-- Backtest run metadata
|
||||||
CREATE TABLE backtest_runs (
|
CREATE TABLE backtest_runs (
|
||||||
run_id TEXT PRIMARY KEY,
|
run_id TEXT PRIMARY KEY,
|
||||||
user_id TEXT,
|
user_id TEXT,
|
||||||
@@ -375,7 +377,7 @@ CREATE TABLE backtest_runs (
|
|||||||
updated_at DATETIME
|
updated_at DATETIME
|
||||||
);
|
);
|
||||||
|
|
||||||
-- 权益曲线
|
-- Equity curve
|
||||||
CREATE TABLE backtest_equity (
|
CREATE TABLE backtest_equity (
|
||||||
id INTEGER PRIMARY KEY,
|
id INTEGER PRIMARY KEY,
|
||||||
run_id TEXT,
|
run_id TEXT,
|
||||||
@@ -388,7 +390,7 @@ CREATE TABLE backtest_equity (
|
|||||||
cycle INTEGER
|
cycle INTEGER
|
||||||
);
|
);
|
||||||
|
|
||||||
-- 交易记录
|
-- Trade records
|
||||||
CREATE TABLE backtest_trades (
|
CREATE TABLE backtest_trades (
|
||||||
id INTEGER PRIMARY KEY,
|
id INTEGER PRIMARY KEY,
|
||||||
run_id TEXT,
|
run_id TEXT,
|
||||||
@@ -405,14 +407,14 @@ CREATE TABLE backtest_trades (
|
|||||||
liquidation BOOLEAN
|
liquidation BOOLEAN
|
||||||
);
|
);
|
||||||
|
|
||||||
-- 性能指标
|
-- Performance metrics
|
||||||
CREATE TABLE backtest_metrics (
|
CREATE TABLE backtest_metrics (
|
||||||
run_id TEXT PRIMARY KEY,
|
run_id TEXT PRIMARY KEY,
|
||||||
payload BLOB,
|
payload BLOB,
|
||||||
updated_at DATETIME
|
updated_at DATETIME
|
||||||
);
|
);
|
||||||
|
|
||||||
-- 检查点 (暂停/恢复)
|
-- Checkpoints (pause/resume)
|
||||||
CREATE TABLE backtest_checkpoints (
|
CREATE TABLE backtest_checkpoints (
|
||||||
run_id TEXT PRIMARY KEY,
|
run_id TEXT PRIMARY KEY,
|
||||||
payload BLOB,
|
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
|
||||||
|
|
||||||
| 接口 | 方法 | 说明 |
|
| Endpoint | Method | Description |
|
||||||
|------|------|------|
|
|----------|--------|-------------|
|
||||||
| `/backtest/start` | POST | 开始回测 |
|
| `/backtest/start` | POST | Start backtest |
|
||||||
| `/backtest/pause` | POST | 暂停回测 |
|
| `/backtest/pause` | POST | Pause backtest |
|
||||||
| `/backtest/resume` | POST | 恢复回测 |
|
| `/backtest/resume` | POST | Resume backtest |
|
||||||
| `/backtest/stop` | POST | 停止回测 |
|
| `/backtest/stop` | POST | Stop backtest |
|
||||||
| `/backtest/status` | GET | 获取状态 |
|
| `/backtest/status` | GET | Get status |
|
||||||
| `/backtest/runs` | GET | 列出所有回测 |
|
| `/backtest/runs` | GET | List all backtests |
|
||||||
| `/backtest/equity` | GET | 获取权益曲线 |
|
| `/backtest/equity` | GET | Get equity curve |
|
||||||
| `/backtest/trades` | GET | 获取交易记录 |
|
| `/backtest/trades` | GET | Get trade records |
|
||||||
| `/backtest/metrics` | GET | 获取性能指标 |
|
| `/backtest/metrics` | GET | Get performance metrics |
|
||||||
| `/backtest/trace` | GET | 获取决策日志 |
|
| `/backtest/trace` | GET | Get decision logs |
|
||||||
| `/backtest/export` | GET | 导出 ZIP |
|
| `/backtest/export` | GET | Export ZIP |
|
||||||
| `/backtest/delete` | POST | 删除回测 |
|
| `/backtest/delete` | POST | Delete backtest |
|
||||||
|
|
||||||
### 8.2 请求示例
|
### 8.2 Request Examples
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# 开始回测
|
# Start backtest
|
||||||
POST /backtest/start
|
POST /backtest/start
|
||||||
{
|
{
|
||||||
"config": {
|
"config": {
|
||||||
@@ -460,17 +462,17 @@ POST /backtest/start
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# 获取权益曲线
|
# Get equity curve
|
||||||
GET /backtest/equity?run_id=bt_20231215&tf=1h&limit=1000
|
GET /backtest/equity?run_id=bt_20231215&tf=1h&limit=1000
|
||||||
|
|
||||||
# 获取指标
|
# Get metrics
|
||||||
GET /backtest/metrics?run_id=bt_20231215
|
GET /backtest/metrics?run_id=bt_20231215
|
||||||
```
|
```
|
||||||
|
|
||||||
### 8.3 响应示例
|
### 8.3 Response Examples
|
||||||
|
|
||||||
```json
|
```json
|
||||||
// 状态响应
|
// Status response
|
||||||
{
|
{
|
||||||
"run_id": "bt_20231215",
|
"run_id": "bt_20231215",
|
||||||
"state": "running",
|
"state": "running",
|
||||||
@@ -480,7 +482,7 @@ GET /backtest/metrics?run_id=bt_20231215
|
|||||||
"unrealized_pnl": 234.50
|
"unrealized_pnl": 234.50
|
||||||
}
|
}
|
||||||
|
|
||||||
// 指标响应
|
// Metrics response
|
||||||
{
|
{
|
||||||
"total_return_pct": 12.34,
|
"total_return_pct": 12.34,
|
||||||
"max_drawdown_pct": 5.67,
|
"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
|
```go
|
||||||
type position struct {
|
type position struct {
|
||||||
Symbol string
|
Symbol string
|
||||||
Side string // "long" 或 "short"
|
Side string // "long" or "short"
|
||||||
Quantity float64
|
Quantity float64
|
||||||
EntryPrice float64
|
EntryPrice float64
|
||||||
Leverage int
|
Leverage int
|
||||||
Margin float64 // 保证金
|
Margin float64 // Margin
|
||||||
Notional float64 // 名义价值
|
Notional float64 // Notional value
|
||||||
LiquidationPrice float64 // 爆仓价格
|
LiquidationPrice float64 // Liquidation price
|
||||||
OpenTime int64
|
OpenTime int64
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### 9.2 开仓逻辑
|
### 9.2 Open Position Logic
|
||||||
|
|
||||||
```go
|
```go
|
||||||
// backtest/account.go:61-104
|
// backtest/account.go:61-104
|
||||||
func (a *BacktestAccount) Open(symbol, side string, qty, price float64, leverage int) {
|
func (a *BacktestAccount) Open(symbol, side string, qty, price float64, leverage int) {
|
||||||
// 1. 应用滑点
|
// 1. Apply slippage
|
||||||
// 2. 计算名义价值 (qty × price)
|
// 2. Calculate notional value (qty × price)
|
||||||
// 3. 计算保证金 (notional / leverage)
|
// 3. Calculate margin (notional / leverage)
|
||||||
// 4. 扣除保证金 + 手续费
|
// 4. Deduct margin + fees
|
||||||
// 5. 创建/加仓
|
// 5. Create/add to position
|
||||||
// 6. 计算爆仓价格
|
// 6. Calculate liquidation price
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### 9.3 平仓逻辑
|
### 9.3 Close Position Logic
|
||||||
|
|
||||||
```go
|
```go
|
||||||
// backtest/account.go:106-140
|
// backtest/account.go:106-140
|
||||||
func (a *BacktestAccount) Close(symbol, side string, qty, price float64) {
|
func (a *BacktestAccount) Close(symbol, side string, qty, price float64) {
|
||||||
// 1. 验证持仓存在
|
// 1. Verify position exists
|
||||||
// 2. 应用滑点 (反向)
|
// 2. Apply slippage (reverse direction)
|
||||||
// 3. 计算已实现盈亏
|
// 3. Calculate realized PnL
|
||||||
// long: (exit - entry) × qty
|
// long: (exit - entry) × qty
|
||||||
// short: (entry - exit) × qty
|
// short: (entry - exit) × qty
|
||||||
// 4. 返还保证金 + 盈亏 - 手续费
|
// 4. Return margin + PnL - fees
|
||||||
// 5. 更新/删除持仓
|
// 5. Update/delete position
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### 9.4 爆仓价格计算
|
### 9.4 Liquidation Price Calculation
|
||||||
|
|
||||||
```go
|
```go
|
||||||
// backtest/account.go:177-186
|
// backtest/account.go:177-186
|
||||||
func computeLiquidation(entry float64, leverage int, side string) float64 {
|
func computeLiquidation(entry float64, leverage int, side string) float64 {
|
||||||
if side == "long" {
|
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
|
```json
|
||||||
{
|
{
|
||||||
@@ -576,47 +578,47 @@ func computeLiquidation(entry float64, leverage int, side string) float64 {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### 10.2 检查点触发
|
### 10.2 Checkpoint Trigger
|
||||||
|
|
||||||
```go
|
```go
|
||||||
// backtest/runner.go:874-898
|
// backtest/runner.go:874-898
|
||||||
func (r *Runner) maybeCheckpoint() {
|
func (r *Runner) maybeCheckpoint() {
|
||||||
// 每 N 根 K 线保存
|
// Save every N bars
|
||||||
// 或每 N 秒保存
|
// Or save every N seconds
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### 10.3 恢复流程
|
### 10.3 Resume Flow
|
||||||
|
|
||||||
```go
|
```go
|
||||||
func (r *Runner) RestoreFromCheckpoint() {
|
func (r *Runner) RestoreFromCheckpoint() {
|
||||||
// 1. 加载检查点
|
// 1. Load checkpoint
|
||||||
// 2. 恢复账户状态
|
// 2. Restore account state
|
||||||
// 3. 恢复 K 线索引 (从下一根继续)
|
// 3. Restore bar index (continue from next bar)
|
||||||
// 4. 恢复权益曲线、交易记录
|
// 4. Restore equity curve, trade records
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 核心文件索引
|
## Core File Index
|
||||||
|
|
||||||
| 模块 | 文件 | 关键方法 |
|
| Module | File | Key Methods |
|
||||||
|------|------|----------|
|
|--------|------|-------------|
|
||||||
| **配置** | `backtest/config.go` | `BacktestConfig`, `Validate()` |
|
| **Config** | `backtest/config.go` | `BacktestConfig`, `Validate()` |
|
||||||
| **数据加载** | `backtest/datafeed.go` | `NewDataFeed()`, `loadAll()`, `BuildMarketData()` |
|
| **Data Loading** | `backtest/datafeed.go` | `NewDataFeed()`, `loadAll()`, `BuildMarketData()` |
|
||||||
| **模拟引擎** | `backtest/runner.go` | `Start()`, `loop()`, `stepOnce()` |
|
| **Sim Engine** | `backtest/runner.go` | `Start()`, `loop()`, `stepOnce()` |
|
||||||
| **决策** | `backtest/runner.go` | `buildDecisionContext()`, `invokeAIWithRetry()` |
|
| **Decision** | `backtest/runner.go` | `buildDecisionContext()`, `invokeAIWithRetry()` |
|
||||||
| **执行** | `backtest/runner.go` | `executeDecision()` |
|
| **Execution** | `backtest/runner.go` | `executeDecision()` |
|
||||||
| **账户** | `backtest/account.go` | `Open()`, `Close()`, `TotalEquity()` |
|
| **Account** | `backtest/account.go` | `Open()`, `Close()`, `TotalEquity()` |
|
||||||
| **指标** | `backtest/metrics.go` | `CalculateMetrics()` |
|
| **Metrics** | `backtest/metrics.go` | `CalculateMetrics()` |
|
||||||
| **权益** | `backtest/equity.go` | `ResampleEquity()`, `LimitEquityPoints()` |
|
| **Equity** | `backtest/equity.go` | `ResampleEquity()`, `LimitEquityPoints()` |
|
||||||
| **存储** | `backtest/storage.go` | `SaveCheckpoint()`, `appendEquityPoint()` |
|
| **Storage** | `backtest/storage.go` | `SaveCheckpoint()`, `appendEquityPoint()` |
|
||||||
| **数据库** | `store/backtest.go` | 表结构和 CRUD 操作 |
|
| **Database** | `store/backtest.go` | Schema and CRUD operations |
|
||||||
| **API** | `api/backtest.go` | HTTP 处理器 |
|
| **API** | `api/backtest.go` | HTTP handlers |
|
||||||
| **AI 缓存** | `backtest/aicache.go` | `Get()`, `Put()`, `save()` |
|
| **AI Cache** | `backtest/aicache.go` | `Get()`, `Put()`, `save()` |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
**文档版本:** 1.0.0
|
**Document Version:** 1.0.0
|
||||||
**最后更新:** 2025-01-15
|
**Last Updated:** 2025-01-15
|
||||||
|
|||||||
624
docs/architecture/BACKTEST_MODULE.zh-CN.md
Normal file
624
docs/architecture/BACKTEST_MODULE.zh-CN.md
Normal file
@@ -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_id>/
|
||||||
|
│ ├── 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
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
# Debate Arena Module - Technical Documentation
|
# Debate Arena Module - Technical Documentation
|
||||||
|
|
||||||
|
**Language:** [English](DEBATE_MODULE.md) | [中文](DEBATE_MODULE.zh-CN.md)
|
||||||
|
|
||||||
## Overview
|
## 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.
|
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.
|
||||||
|
|||||||
606
docs/architecture/DEBATE_MODULE.zh-CN.md
Normal file
606
docs/architecture/DEBATE_MODULE.zh-CN.md
Normal file
@@ -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):
|
||||||
|
<reasoning>
|
||||||
|
- 带数据引用的市场分析
|
||||||
|
- 主要交易论点
|
||||||
|
- 对他人的回应 (第2轮起)
|
||||||
|
</reasoning>
|
||||||
|
|
||||||
|
<decision>
|
||||||
|
[
|
||||||
|
{"symbol": "BTCUSDT", "action": "open_long", "confidence": 75, ...},
|
||||||
|
{"symbol": "ETHUSDT", "action": "open_short", "confidence": 80, ...}
|
||||||
|
]
|
||||||
|
</decision>
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 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: <TrendingUp />,
|
||||||
|
label: 'LONG'
|
||||||
|
},
|
||||||
|
open_short: {
|
||||||
|
color: 'text-red-400',
|
||||||
|
bg: 'bg-red-500/20',
|
||||||
|
icon: <TrendingDown />,
|
||||||
|
label: 'SHORT'
|
||||||
|
},
|
||||||
|
hold: {
|
||||||
|
color: 'text-blue-400',
|
||||||
|
bg: 'bg-blue-500/20',
|
||||||
|
icon: <Minus />,
|
||||||
|
label: 'HOLD'
|
||||||
|
},
|
||||||
|
wait: {
|
||||||
|
color: 'text-gray-400',
|
||||||
|
bg: 'bg-gray-500/20',
|
||||||
|
icon: <Clock />,
|
||||||
|
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
|
||||||
@@ -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)
|
1. Coin Selection (GetCandidateCoins)
|
||||||
├─ Static (静态列表)
|
├─ Static (Static list)
|
||||||
├─ AI500 Pool (AI评分池)
|
├─ AI500 Pool (AI rating pool)
|
||||||
├─ OI Top (持仓增长榜)
|
├─ OI Top (Position growth ranking)
|
||||||
└─ Mixed (混合模式)
|
└─ Mixed (Mixed mode)
|
||||||
↓
|
↓
|
||||||
2. 数据组装 (buildTradingContext)
|
2. Data Assembly (buildTradingContext)
|
||||||
├─ 账户余额 → equity, available, unrealizedPnL
|
├─ Account balance → equity, available, unrealizedPnL
|
||||||
├─ 当前持仓 → symbol, side, entry, mark, qty, leverage
|
├─ Current positions → symbol, side, entry, mark, qty, leverage
|
||||||
├─ K线数据 → OHLCV (5m, 15m, 1h, 4h)
|
├─ K-line data → OHLCV (5m, 15m, 1h, 4h)
|
||||||
├─ 技术指标 → EMA, MACD, RSI, ATR, Volume
|
├─ Technical indicators → EMA, MACD, RSI, ATR, Volume
|
||||||
├─ 链上数据 → OI, Funding Rate
|
├─ On-chain data → OI, Funding Rate
|
||||||
├─ 量化数据 → 资金流向, OI变化 (可选)
|
├─ Quant data → Capital flow, OI changes (optional)
|
||||||
└─ 最近交易 → 最近10笔已平仓
|
└─ Recent trades → Last 10 closed trades
|
||||||
↓
|
↓
|
||||||
3. 系统提示词 (BuildSystemPrompt)
|
3. System Prompt (BuildSystemPrompt)
|
||||||
├─ 角色定义
|
├─ Role definition
|
||||||
├─ 交易模式 (aggressive/conservative/scalping)
|
├─ Trading mode (aggressive/conservative/scalping)
|
||||||
├─ 硬性约束 (代码强制执行)
|
├─ Hard constraints (code enforced)
|
||||||
├─ AI引导 (建议值)
|
├─ AI guidance (suggested values)
|
||||||
├─ 交易频率
|
├─ Trading frequency
|
||||||
├─ 入场标准
|
├─ Entry standards
|
||||||
├─ 决策流程
|
├─ Decision process
|
||||||
└─ 输出格式 (XML + JSON)
|
└─ Output format (XML + JSON)
|
||||||
↓
|
↓
|
||||||
4. 用户提示词 (BuildUserPrompt)
|
4. User Prompt (BuildUserPrompt)
|
||||||
├─ 系统状态 (时间, 周期号)
|
├─ System status (time, cycle number)
|
||||||
├─ BTC市场概览
|
├─ BTC market overview
|
||||||
├─ 账户信息
|
├─ Account information
|
||||||
├─ 当前持仓 (含技术指标)
|
├─ Current positions (with indicators)
|
||||||
├─ 候选币种 (完整市场数据)
|
├─ Candidate coins (full market data)
|
||||||
└─ "请分析并输出决策..."
|
└─ "Please analyze and output decisions..."
|
||||||
↓
|
↓
|
||||||
5. AI请求 (CallWithMessages)
|
5. AI Request (CallWithMessages)
|
||||||
├─ 选择AI模型
|
├─ Select AI model
|
||||||
├─ POST: system_prompt + user_prompt
|
├─ POST: system_prompt + user_prompt
|
||||||
├─ 超时: 120秒, 重试: 3次
|
├─ Timeout: 120s, Retries: 3
|
||||||
└─ 返回原始响应
|
└─ Return raw response
|
||||||
↓
|
↓
|
||||||
6. AI解析 (parseFullDecisionResponse)
|
6. AI Parsing (parseFullDecisionResponse)
|
||||||
├─ 提取思维链 <reasoning>
|
├─ Extract Chain of Thought <reasoning>
|
||||||
├─ 提取JSON决策 <decision>
|
├─ Extract JSON decision <decision>
|
||||||
├─ 修复字符编码
|
├─ Fix character encoding
|
||||||
├─ 验证JSON格式
|
├─ Validate JSON format
|
||||||
├─ 解析决策数组
|
├─ Parse decision array
|
||||||
└─ 验证风控参数
|
└─ Validate risk parameters
|
||||||
↓
|
↓
|
||||||
7. 决策执行
|
7. Decision Execution
|
||||||
├─ 排序: 平仓优先 → 开仓 → hold/wait
|
├─ 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
|
```go
|
||||||
// decision/engine.go:395-403
|
// decision/engine.go:395-403
|
||||||
@@ -90,11 +92,11 @@ if config.CoinSource.SourceType == "static" {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
- **配置:** `StrategyConfig.CoinSource.StaticCoins`
|
- **Config:** `StrategyConfig.CoinSource.StaticCoins`
|
||||||
- **用途:** 手动指定交易币种
|
- **Usage:** Manually specify trading coins
|
||||||
- **标签:** `["static"]`
|
- **Tag:** `["static"]`
|
||||||
|
|
||||||
### 1.2 AI500 币种池 (CoinPool)
|
### 1.2 AI500 Coin Pool
|
||||||
|
|
||||||
```go
|
```go
|
||||||
// decision/engine.go:405-406, 456-474
|
// 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`)
|
- **API:** `config.CoinSource.CoinPoolAPIURL`
|
||||||
- **用途:** 获取 AI 评分最高的 N 个币种
|
- **Usage:** Get top N coins by AI rating
|
||||||
- **标签:** `["ai500"]`
|
- **Tag:** `["ai500"]`
|
||||||
|
|
||||||
### 1.3 OI Top 币种 (持仓增长榜)
|
### 1.3 OI Top Coins (Position Growth Ranking)
|
||||||
|
|
||||||
```go
|
```go
|
||||||
// decision/engine.go:408-409, 476-498
|
// decision/engine.go:408-409, 476-498
|
||||||
@@ -131,39 +133,39 @@ func (e *StrategyEngine) getOITopCoins() []CandidateCoin {
|
|||||||
```
|
```
|
||||||
|
|
||||||
- **API:** `config.CoinSource.OITopAPIURL`
|
- **API:** `config.CoinSource.OITopAPIURL`
|
||||||
- **用途:** 获取持仓量增长最快的币种
|
- **Usage:** Get coins with fastest OI growth
|
||||||
- **标签:** `["oi_top"]`
|
- **Tag:** `["oi_top"]`
|
||||||
|
|
||||||
### 1.4 混合模式 (Mixed)
|
### 1.4 Mixed Mode
|
||||||
|
|
||||||
```go
|
```go
|
||||||
// decision/engine.go:411-449
|
// decision/engine.go:411-449
|
||||||
if config.CoinSource.SourceType == "mixed" {
|
if config.CoinSource.SourceType == "mixed" {
|
||||||
if config.CoinSource.UseCoinPool {
|
if config.CoinSource.UseCoinPool {
|
||||||
// 添加 AI500 币种
|
// Add AI500 coins
|
||||||
}
|
}
|
||||||
if config.CoinSource.UseOITop {
|
if config.CoinSource.UseOITop {
|
||||||
// 添加 OI Top 币种
|
// Add OI Top coins
|
||||||
}
|
}
|
||||||
if len(config.CoinSource.StaticCoins) > 0 {
|
if len(config.CoinSource.StaticCoins) > 0 {
|
||||||
// 添加静态币种
|
// Add static coins
|
||||||
}
|
}
|
||||||
// 去重合并,保留多来源标签
|
// Deduplicate and merge, keep multi-source tags
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
- **特点:** 同时使用多个数据源
|
- **Feature:** Use multiple data sources simultaneously
|
||||||
- **标签示例:** `["ai500", "oi_top"]` (双信号币种)
|
- **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
|
```go
|
||||||
// trader/auto_trader.go:565-583
|
// trader/auto_trader.go:565-583
|
||||||
@@ -173,12 +175,12 @@ available := balance["available_balance"].(float64)
|
|||||||
unrealizedPnL := balance["total_pnl"].(float64)
|
unrealizedPnL := balance["total_pnl"].(float64)
|
||||||
```
|
```
|
||||||
|
|
||||||
**提取字段:**
|
**Extracted Fields:**
|
||||||
- `total_equity` - 账户总权益
|
- `total_equity` - Total account equity
|
||||||
- `available_balance` - 可用余额
|
- `available_balance` - Available balance
|
||||||
- `total_pnl` - 未实现盈亏
|
- `total_pnl` - Unrealized PnL
|
||||||
|
|
||||||
### 2.2 持仓数据
|
### 2.2 Position Data
|
||||||
|
|
||||||
```go
|
```go
|
||||||
// trader/auto_trader.go:588-682
|
// trader/auto_trader.go:588-682
|
||||||
@@ -197,7 +199,7 @@ for _, pos := range positions {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### 2.3 市场数据获取
|
### 2.3 Market Data Fetching
|
||||||
|
|
||||||
```go
|
```go
|
||||||
// decision/engine.go:299-374
|
// 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)` |
|
| **EMA** | `EnableEMA`, `EMAPeriods` | `calculateEMA(klines, period)` |
|
||||||
| **MACD** | `EnableMACD` | `calculateMACD(klines)` - 12/26/9 |
|
| **MACD** | `EnableMACD` | `calculateMACD(klines)` - 12/26/9 |
|
||||||
| **RSI** | `EnableRSI`, `RSIPeriods` | `calculateRSI(klines, period)` |
|
| **RSI** | `EnableRSI`, `RSIPeriods` | `calculateRSI(klines, period)` |
|
||||||
| **ATR** | `EnableATR`, `ATRPeriods` | `calculateATR(klines, period)` |
|
| **ATR** | `EnableATR`, `ATRPeriods` | `calculateATR(klines, period)` |
|
||||||
| **Volume** | `EnableVolume` | 原始成交量数据 |
|
| **Volume** | `EnableVolume` | Raw volume data |
|
||||||
| **OI** | `EnableOI` | 持仓量数据 |
|
| **OI** | `EnableOI` | Open interest data |
|
||||||
| **Funding Rate** | `EnableFundingRate` | 资金费率 |
|
| **Funding Rate** | `EnableFundingRate` | Funding rate |
|
||||||
|
|
||||||
### 2.5 量化数据 (可选)
|
### 2.5 Quant Data (Optional)
|
||||||
|
|
||||||
```go
|
```go
|
||||||
// trader/auto_trader.go:759-778
|
// trader/auto_trader.go:759-778
|
||||||
if config.Indicators.EnableQuantData {
|
if config.Indicators.EnableQuantData {
|
||||||
quantData := provider.GetQuantData(symbol)
|
quantData := provider.GetQuantData(symbol)
|
||||||
// 包含: 资金流向、OI变化、价格变化
|
// Contains: Capital flow, OI changes, Price changes
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
**数据结构:**
|
**Data Structure:**
|
||||||
```go
|
```go
|
||||||
QuantData {
|
QuantData {
|
||||||
Netflow {
|
Netflow {
|
||||||
Institution: {Future, Spot}, // 机构资金流
|
Institution: {Future, Spot}, // Institutional flow
|
||||||
Personal: {Future, Spot} // 散户资金流
|
Personal: {Future, Spot} // Retail flow
|
||||||
},
|
},
|
||||||
OI {
|
OI {
|
||||||
CurrentOI: float64,
|
CurrentOI: float64,
|
||||||
Delta: {1h, 4h, 24h} // OI变化
|
Delta: {1h, 4h, 24h} // OI changes
|
||||||
},
|
},
|
||||||
PriceChange {
|
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. 角色定义 [可编辑]
|
1. Role Definition [Editable]
|
||||||
2. 交易模式变体 [运行时确定]
|
2. Trading Mode Variant [Runtime determined]
|
||||||
3. 硬性约束 [代码强制 + AI引导]
|
3. Hard Constraints [Code enforced + AI guided]
|
||||||
4. 交易频率 [可编辑]
|
4. Trading Frequency [Editable]
|
||||||
5. 入场标准 [可编辑]
|
5. Entry Standards [Editable]
|
||||||
6. 决策流程 [可编辑]
|
6. Decision Process [Editable]
|
||||||
7. 输出格式 [固定XML + JSON结构]
|
7. Output Format [Fixed XML + JSON structure]
|
||||||
8. 自定义提示词 [可选]
|
8. Custom Prompt [Optional]
|
||||||
```
|
```
|
||||||
|
|
||||||
### 3.2 角色定义
|
### 3.2 Role Definition
|
||||||
|
|
||||||
```go
|
```go
|
||||||
// decision/engine.go:706-713
|
// decision/engine.go:706-713
|
||||||
@@ -285,41 +287,41 @@ if roleDefinition == "" {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### 3.3 交易模式变体
|
### 3.3 Trading Mode Variants
|
||||||
|
|
||||||
| 模式 | 特点 |
|
| Mode | Characteristics |
|
||||||
|------|------|
|
|------|-----------------|
|
||||||
| `aggressive` | 趋势突破,较高仓位容忍度 |
|
| `aggressive` | Trend breakout, higher position tolerance |
|
||||||
| `conservative` | 多信号确认,保守资金管理 |
|
| `conservative` | Multi-signal confirmation, conservative money management |
|
||||||
| `scalping` | 短线动量,紧止盈 |
|
| `scalping` | Short-term momentum, tight take-profit |
|
||||||
|
|
||||||
### 3.4 硬性约束
|
### 3.4 Hard Constraints
|
||||||
|
|
||||||
**代码强制执行 (CODE ENFORCED):**
|
**Code Enforced:**
|
||||||
|
|
||||||
```go
|
```go
|
||||||
// decision/engine.go:725-749
|
// decision/engine.go:725-749
|
||||||
maxPositions := config.RiskControl.MaxPositions // 默认: 3
|
maxPositions := config.RiskControl.MaxPositions // Default: 3
|
||||||
altcoinMaxRatio := config.RiskControl.AltcoinMaxPositionValueRatio // 默认: 1.0
|
altcoinMaxRatio := config.RiskControl.AltcoinMaxPositionValueRatio // Default: 1.0
|
||||||
btcethMaxRatio := config.RiskControl.BTCETHMaxPositionValueRatio // 默认: 5.0
|
btcethMaxRatio := config.RiskControl.BTCETHMaxPositionValueRatio // Default: 5.0
|
||||||
maxMarginUsage := config.RiskControl.MaxMarginUsage // 默认: 90%
|
maxMarginUsage := config.RiskControl.MaxMarginUsage // Default: 90%
|
||||||
minPositionSize := config.RiskControl.MinPositionSize // 默认: 12 USDT
|
minPositionSize := config.RiskControl.MinPositionSize // Default: 12 USDT
|
||||||
```
|
```
|
||||||
|
|
||||||
**AI引导 (建议值):**
|
**AI Guided (Suggested Values):**
|
||||||
|
|
||||||
```go
|
```go
|
||||||
altcoinMaxLeverage := config.RiskControl.AltcoinMaxLeverage // 默认: 5x
|
altcoinMaxLeverage := config.RiskControl.AltcoinMaxLeverage // Default: 5x
|
||||||
btcethMaxLeverage := config.RiskControl.BTCETHMaxLeverage // 默认: 5x
|
btcethMaxLeverage := config.RiskControl.BTCETHMaxLeverage // Default: 5x
|
||||||
minRiskRewardRatio := config.RiskControl.MinRiskRewardRatio // 默认: 1:3
|
minRiskRewardRatio := config.RiskControl.MinRiskRewardRatio // Default: 1:3
|
||||||
minConfidence := config.RiskControl.MinConfidence // 默认: 75
|
minConfidence := config.RiskControl.MinConfidence // Default: 75
|
||||||
```
|
```
|
||||||
|
|
||||||
### 3.5 输出格式要求
|
### 3.5 Output Format Requirements
|
||||||
|
|
||||||
```xml
|
```xml
|
||||||
<reasoning>
|
<reasoning>
|
||||||
[思维链分析过程]
|
[Chain of Thought analysis process]
|
||||||
</reasoning>
|
</reasoning>
|
||||||
|
|
||||||
<decision>
|
<decision>
|
||||||
@@ -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. 系统状态 [时间, 周期号, 运行时长]
|
1. System Status [Time, cycle number, runtime]
|
||||||
2. BTC市场概览 [价格, 涨跌幅, MACD, RSI]
|
2. BTC Market Overview [Price, change%, MACD, RSI]
|
||||||
3. 账户信息 [权益, 余额%, 盈亏%, 保证金%, 持仓数]
|
3. Account Info [Equity, balance%, PnL%, margin%, positions]
|
||||||
4. 最近成交 [最近10笔已平仓交易]
|
4. Recent Trades [Last 10 closed trades]
|
||||||
5. 当前持仓 [详细持仓数据 + 技术指标]
|
5. Current Positions [Detailed position data + indicators]
|
||||||
6. 候选币种 [完整市场数据]
|
6. Candidate Coins [Full market data]
|
||||||
7. 量化数据 [资金流向, OI数据] (可选)
|
7. Quant Data [Capital flow, OI data] (optional)
|
||||||
8. OI排行数据 [市场OI变化排行] (可选)
|
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
|
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
|
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%
|
Funding Rate: 0.0100%
|
||||||
```
|
```
|
||||||
|
|
||||||
### 4.4 候选币种格式
|
### 4.4 Candidate Coin Format
|
||||||
|
|
||||||
```
|
```
|
||||||
### 1. ETHUSDT (AI500+OI_Top dual signal)
|
### 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
|
```go
|
||||||
// decision/engine.go:263-268
|
// decision/engine.go:263-268
|
||||||
@@ -419,10 +421,10 @@ aiResponse, err := mcpClient.CallWithMessages(systemPrompt, userPrompt)
|
|||||||
aiCallDuration := time.Since(aiCallStart)
|
aiCallDuration := time.Since(aiCallStart)
|
||||||
```
|
```
|
||||||
|
|
||||||
### 5.2 支持的AI模型
|
### 5.2 Supported AI Models
|
||||||
|
|
||||||
| 模型 | 客户端文件 | 默认模型 |
|
| Model | Client File | Default Model |
|
||||||
|------|-----------|----------|
|
|-------|-------------|---------------|
|
||||||
| **DeepSeek** | `mcp/deepseek_client.go` | deepseek-chat |
|
| **DeepSeek** | `mcp/deepseek_client.go` | deepseek-chat |
|
||||||
| **Qwen** | `mcp/qwen_client.go` | qwen-max |
|
| **Qwen** | `mcp/qwen_client.go` | qwen-max |
|
||||||
| **Claude** | `mcp/claude_client.go` | claude-3-5-sonnet |
|
| **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 |
|
| **OpenAI** | `mcp/openai_client.go` | gpt-5.2 |
|
||||||
| **Kimi** | `mcp/kimi_client.go` | moonshot-v1-8k |
|
| **Kimi** | `mcp/kimi_client.go` | moonshot-v1-8k |
|
||||||
|
|
||||||
### 5.3 请求参数
|
### 5.3 Request Parameters
|
||||||
|
|
||||||
```go
|
```go
|
||||||
// mcp/client.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
|
```go
|
||||||
// decision/engine.go:1327-1345
|
// decision/engine.go:1327-1345
|
||||||
func extractCoTTrace(response string) string {
|
func extractCoTTrace(response string) string {
|
||||||
// 优先级1: <reasoning> XML标签
|
// Priority 1: <reasoning> XML tag
|
||||||
if match := reReasoningTag.FindStringSubmatch(response); len(match) > 1 {
|
if match := reReasoningTag.FindStringSubmatch(response); len(match) > 1 {
|
||||||
return strings.TrimSpace(match[1])
|
return strings.TrimSpace(match[1])
|
||||||
}
|
}
|
||||||
// 优先级2: <decision>标签之前的文本
|
// Priority 2: Text before <decision> tag
|
||||||
// 优先级3: JSON [ 之前的文本
|
// Priority 3: Text before JSON [
|
||||||
// 优先级4: 完整响应
|
// Priority 4: Full response
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### 6.3 JSON决策提取
|
### 6.3 JSON Decision Extraction
|
||||||
|
|
||||||
```go
|
```go
|
||||||
// decision/engine.go:1347-1408
|
// decision/engine.go:1347-1408
|
||||||
func extractDecisions(response string) (string, error) {
|
func extractDecisions(response string) (string, error) {
|
||||||
// 1. 移除不可见字符
|
// 1. Remove invisible characters
|
||||||
response = removeInvisibleRunes(response)
|
response = removeInvisibleRunes(response)
|
||||||
|
|
||||||
// 2. 修复字符编码
|
// 2. Fix character encoding
|
||||||
response = fixMissingQuotes(response)
|
response = fixMissingQuotes(response)
|
||||||
|
|
||||||
// 3. 提取JSON (优先级)
|
// 3. Extract JSON (priority)
|
||||||
// - <decision> XML标签 + ```json
|
// - <decision> XML tag + ```json
|
||||||
// - 独立 ```json 代码块
|
// - Standalone ```json code block
|
||||||
// - 裸JSON数组
|
// - Bare JSON array
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### 6.4 字符编码修复
|
### 6.4 Character Encoding Fix
|
||||||
|
|
||||||
```go
|
```go
|
||||||
// decision/engine.go:1410-1432
|
// decision/engine.go:1410-1432
|
||||||
func fixMissingQuotes(s string) string {
|
func fixMissingQuotes(s string) string {
|
||||||
// 中文引号 → ASCII
|
// Chinese quotes → ASCII
|
||||||
s = strings.ReplaceAll(s, """, "\"")
|
s = strings.ReplaceAll(s, """, "\"")
|
||||||
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, "]", "]")
|
||||||
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, ":", ":")
|
||||||
s = strings.ReplaceAll(s, ",", ",")
|
s = strings.ReplaceAll(s, ",", ",")
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### 6.5 决策验证
|
### 6.5 Decision Validation
|
||||||
|
|
||||||
```go
|
```go
|
||||||
// decision/engine.go:1480-1602
|
// decision/engine.go:1480-1602
|
||||||
func validateDecisions(decisions []Decision, equity, leverage, ratio float64) error {
|
func validateDecisions(decisions []Decision, equity, leverage, ratio float64) error {
|
||||||
for _, d := range decisions {
|
for _, d := range decisions {
|
||||||
// 1. 验证action类型
|
// 1. Validate action type
|
||||||
validActions := []string{"open_long", "open_short", "close_long", "close_short", "hold", "wait"}
|
validActions := []string{"open_long", "open_short", "close_long", "close_short", "hold", "wait"}
|
||||||
|
|
||||||
// 2. 开仓验证
|
// 2. Open position validation
|
||||||
if isOpenAction(d.Action) {
|
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) {
|
if isCloseAction(d.Action) {
|
||||||
// Symbol必须存在
|
// Symbol must exist
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### 6.6 Decision结构体
|
### 6.6 Decision Structure
|
||||||
|
|
||||||
```go
|
```go
|
||||||
// decision/engine.go:128-143
|
// decision/engine.go:128-143
|
||||||
type Decision struct {
|
type Decision struct {
|
||||||
Symbol string // 交易对: "BTCUSDT"
|
Symbol string // Trading pair: "BTCUSDT"
|
||||||
Action string // "open_long", "open_short", "close_long", "close_short", "hold", "wait"
|
Action string // "open_long", "open_short", "close_long", "close_short", "hold", "wait"
|
||||||
Leverage int // 杠杆倍数
|
Leverage int // Leverage multiplier
|
||||||
PositionSizeUSD float64 // 仓位价值 (USDT)
|
PositionSizeUSD float64 // Position value (USDT)
|
||||||
StopLoss float64 // 止损价格
|
StopLoss float64 // Stop loss price
|
||||||
TakeProfit float64 // 止盈价格
|
TakeProfit float64 // Take profit price
|
||||||
Confidence int // 置信度 0-100
|
Confidence int // Confidence 0-100
|
||||||
RiskUSD float64 // 最大风险 (USDT)
|
RiskUSD float64 // Max risk (USDT)
|
||||||
Reasoning string // 决策理由
|
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
|
```go
|
||||||
// trader/auto_trader.go:519-526
|
// trader/auto_trader.go:519-526
|
||||||
sort.SliceStable(decisions, func(i, j int) bool {
|
sort.SliceStable(decisions, func(i, j int) bool {
|
||||||
priority := map[string]int{
|
priority := map[string]int{
|
||||||
"close_long": 1, "close_short": 1, // 最高优先级
|
"close_long": 1, "close_short": 1, // Highest priority
|
||||||
"open_long": 2, "open_short": 2, // 次优先级
|
"open_long": 2, "open_short": 2, // Second priority
|
||||||
"hold": 3, "wait": 3, // 最低优先级
|
"hold": 3, "wait": 3, // Lowest priority
|
||||||
}
|
}
|
||||||
return priority[decisions[i].Action] < priority[decisions[j].Action]
|
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`
|
||||||
|
|
||||||
| 检查项 | 方法 | 动作 |
|
| Check | Method | Action |
|
||||||
|--------|------|------|
|
|-------|--------|--------|
|
||||||
| 最大持仓数 | `enforceMaxPositions()` | 拒绝新开仓 |
|
| Max positions | `enforceMaxPositions()` | Reject new opens |
|
||||||
| 仓位价值上限 | `enforcePositionValueRatio()` | 自动缩减仓位 |
|
| Position value cap | `enforcePositionValueRatio()` | Auto reduce size |
|
||||||
| 最小仓位 | `enforceMinPositionSize()` | 拒绝过小订单 |
|
| Min position | `enforceMinPositionSize()` | Reject small orders |
|
||||||
| 保证金调整 | 自动计算 | 根据可用余额调整 |
|
| Margin adjustment | Auto calculate | Adjust by available balance |
|
||||||
|
|
||||||
### 7.3 订单执行
|
### 7.3 Order Execution
|
||||||
|
|
||||||
```go
|
```go
|
||||||
// trader/auto_trader.go:1631-1767
|
// trader/auto_trader.go:1631-1767
|
||||||
func (at *AutoTrader) recordAndConfirmOrder(orderID, symbol, side, action string) {
|
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++ {
|
for i := 0; i < 5; i++ {
|
||||||
status := at.trader.GetOrderStatus(orderID)
|
status := at.trader.GetOrderStatus(orderID)
|
||||||
if status.Status == "FILLED" {
|
if status.Status == "FILLED" {
|
||||||
@@ -608,17 +610,17 @@ func (at *AutoTrader) recordAndConfirmOrder(orderID, symbol, side, action string
|
|||||||
time.Sleep(500 * time.Millisecond)
|
time.Sleep(500 * time.Millisecond)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. 提取成交信息
|
// 2. Extract fill info
|
||||||
filledPrice := status.AvgPrice
|
filledPrice := status.AvgPrice
|
||||||
filledQty := status.FilledQty
|
filledQty := status.FilledQty
|
||||||
fee := status.Fee
|
fee := status.Fee
|
||||||
|
|
||||||
// 3. 记录到数据库
|
// 3. Record to database
|
||||||
at.store.Position().SaveOrder(...)
|
at.store.Position().SaveOrder(...)
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### 7.4 决策日志保存
|
### 7.4 Decision Log Saving
|
||||||
|
|
||||||
```go
|
```go
|
||||||
// trader/auto_trader.go:1235-1256
|
// trader/auto_trader.go:1235-1256
|
||||||
@@ -626,62 +628,62 @@ record := &store.DecisionRecord{
|
|||||||
CycleNumber: cycleNumber,
|
CycleNumber: cycleNumber,
|
||||||
TraderID: traderID,
|
TraderID: traderID,
|
||||||
Timestamp: time.Now(),
|
Timestamp: time.Now(),
|
||||||
SystemPrompt: systemPrompt, // 完整系统提示词
|
SystemPrompt: systemPrompt, // Full system prompt
|
||||||
InputPrompt: userPrompt, // 完整用户提示词
|
InputPrompt: userPrompt, // Full user prompt
|
||||||
CoTTrace: cotTrace, // AI思维链
|
CoTTrace: cotTrace, // AI chain of thought
|
||||||
DecisionJSON: decisionsJSON, // 解析后的决策
|
DecisionJSON: decisionsJSON, // Parsed decisions
|
||||||
RawResponse: rawResponse, // 原始AI响应
|
RawResponse: rawResponse, // Raw AI response
|
||||||
ExecutionLog: executionResults, // 执行结果
|
ExecutionLog: executionResults, // Execution results
|
||||||
CandidateCoins: candidateCoins, // 候选币种
|
CandidateCoins: candidateCoins, // Candidate coins
|
||||||
Success: success, // 执行状态
|
Success: success, // Execution status
|
||||||
}
|
}
|
||||||
at.store.Decision().LogDecision(record)
|
at.store.Decision().LogDecision(record)
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 核心文件索引
|
## Core File Index
|
||||||
|
|
||||||
| 模块 | 文件 | 关键方法 |
|
| Module | File | Key Methods |
|
||||||
|------|------|----------|
|
|--------|------|-------------|
|
||||||
| **主循环** | `trader/auto_trader.go` | `Run()`, `runCycle()`, `buildTradingContext()` |
|
| **Main Loop** | `trader/auto_trader.go` | `Run()`, `runCycle()`, `buildTradingContext()` |
|
||||||
| **币种选择** | `decision/engine.go:380-454` | `GetCandidateCoins()` |
|
| **Coin Selection** | `decision/engine.go:380-454` | `GetCandidateCoins()` |
|
||||||
| **数据获取** | `market/data.go` | `Get()`, `GetWithTimeframes()` |
|
| **Data Fetching** | `market/data.go` | `Get()`, `GetWithTimeframes()` |
|
||||||
| **指标计算** | `market/data.go:59-98` | `calculateEMA()`, `calculateMACD()`, `calculateRSI()` |
|
| **Indicator Calc** | `market/data.go:59-98` | `calculateEMA()`, `calculateMACD()`, `calculateRSI()` |
|
||||||
| **系统提示词** | `decision/engine.go:700-818` | `BuildSystemPrompt()` |
|
| **System Prompt** | `decision/engine.go:700-818` | `BuildSystemPrompt()` |
|
||||||
| **用户提示词** | `decision/engine.go:884-1007` | `BuildUserPrompt()` |
|
| **User Prompt** | `decision/engine.go:884-1007` | `BuildUserPrompt()` |
|
||||||
| **市场数据格式化** | `decision/engine.go:1029-1099` | `formatMarketData()` |
|
| **Market Format** | `decision/engine.go:1029-1099` | `formatMarketData()` |
|
||||||
| **AI请求** | `decision/engine.go:222-293` | `GetFullDecisionWithStrategy()` |
|
| **AI Request** | `decision/engine.go:222-293` | `GetFullDecisionWithStrategy()` |
|
||||||
| **MCP客户端** | `mcp/client.go:136-150` | `CallWithMessages()` |
|
| **MCP Client** | `mcp/client.go:136-150` | `CallWithMessages()` |
|
||||||
| **响应解析** | `decision/engine.go:1303-1604` | `parseFullDecisionResponse()` |
|
| **Response Parse** | `decision/engine.go:1303-1604` | `parseFullDecisionResponse()` |
|
||||||
| **思维链提取** | `decision/engine.go:1327-1345` | `extractCoTTrace()` |
|
| **CoT Extract** | `decision/engine.go:1327-1345` | `extractCoTTrace()` |
|
||||||
| **JSON提取** | `decision/engine.go:1347-1408` | `extractDecisions()` |
|
| **JSON Extract** | `decision/engine.go:1347-1408` | `extractDecisions()` |
|
||||||
| **决策验证** | `decision/engine.go:1480-1602` | `validateDecisions()` |
|
| **Decision Valid** | `decision/engine.go:1480-1602` | `validateDecisions()` |
|
||||||
| **风控执行** | `trader/auto_trader.go:1769-1851` | `enforceMaxPositions()`, `enforcePositionValueRatio()` |
|
| **Risk Enforce** | `trader/auto_trader.go:1769-1851` | `enforceMaxPositions()`, `enforcePositionValueRatio()` |
|
||||||
| **策略配置** | `store/strategy.go` | `StrategyConfig`, `RiskControlConfig` |
|
| **Strategy Config** | `store/strategy.go` | `StrategyConfig`, `RiskControlConfig` |
|
||||||
| **数据提供者** | `provider/data_provider.go` | `GetAI500Data()`, `GetOITopPositions()` |
|
| **Data Provider** | `provider/data_provider.go` | `GetAI500Data()`, `GetOITopPositions()` |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 配置参考
|
## Configuration Reference
|
||||||
|
|
||||||
### 策略配置结构
|
### Strategy Config Structure
|
||||||
|
|
||||||
```go
|
```go
|
||||||
// store/strategy.go
|
// store/strategy.go
|
||||||
type StrategyConfig struct {
|
type StrategyConfig struct {
|
||||||
// 币种来源
|
// Coin Source
|
||||||
CoinSource struct {
|
CoinSource struct {
|
||||||
SourceType string // "static", "coinpool", "oi_top", "mixed"
|
SourceType string // "static", "coinpool", "oi_top", "mixed"
|
||||||
StaticCoins []string // 静态币种列表
|
StaticCoins []string // Static coin list
|
||||||
UseCoinPool bool // 是否使用AI500
|
UseCoinPool bool // Use AI500
|
||||||
UseOITop bool // 是否使用OI排行
|
UseOITop bool // Use OI ranking
|
||||||
CoinPoolLimit int // AI500获取数量
|
CoinPoolLimit int // AI500 fetch limit
|
||||||
CoinPoolAPIURL string // AI500 API地址
|
CoinPoolAPIURL string // AI500 API URL
|
||||||
OITopAPIURL string // OI排行 API地址
|
OITopAPIURL string // OI ranking API URL
|
||||||
}
|
}
|
||||||
|
|
||||||
// 技术指标
|
// Technical Indicators
|
||||||
Indicators struct {
|
Indicators struct {
|
||||||
EnableEMA bool
|
EnableEMA bool
|
||||||
EMAPeriods []int // [20, 50]
|
EMAPeriods []int // [20, 50]
|
||||||
@@ -703,20 +705,20 @@ type StrategyConfig struct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 风控配置
|
// Risk Control
|
||||||
RiskControl struct {
|
RiskControl struct {
|
||||||
MaxPositions int // 最大持仓数
|
MaxPositions int // Max positions
|
||||||
BTCETHMaxLeverage int // BTC/ETH最大杠杆
|
BTCETHMaxLeverage int // BTC/ETH max leverage
|
||||||
AltcoinMaxLeverage int // 山寨币最大杠杆
|
AltcoinMaxLeverage int // Altcoin max leverage
|
||||||
BTCETHMaxPositionValueRatio float64 // BTC/ETH仓位比例上限
|
BTCETHMaxPositionValueRatio float64 // BTC/ETH position ratio cap
|
||||||
AltcoinMaxPositionValueRatio float64 // 山寨币仓位比例上限
|
AltcoinMaxPositionValueRatio float64 // Altcoin position ratio cap
|
||||||
MaxMarginUsage float64 // 最大保证金使用率
|
MaxMarginUsage float64 // Max margin usage
|
||||||
MinPositionSize float64 // 最小仓位
|
MinPositionSize float64 // Min position size
|
||||||
MinRiskRewardRatio float64 // 最小风险回报比
|
MinRiskRewardRatio float64 // Min risk/reward ratio
|
||||||
MinConfidence int // 最小置信度
|
MinConfidence int // Min confidence
|
||||||
}
|
}
|
||||||
|
|
||||||
// 提示词部分
|
// Prompt Sections
|
||||||
PromptSections struct {
|
PromptSections struct {
|
||||||
RoleDefinition string
|
RoleDefinition string
|
||||||
TradingFrequency string
|
TradingFrequency string
|
||||||
@@ -724,12 +726,12 @@ type StrategyConfig struct {
|
|||||||
DecisionProcess string
|
DecisionProcess string
|
||||||
}
|
}
|
||||||
|
|
||||||
// 自定义提示词
|
// Custom Prompt
|
||||||
CustomPrompt string
|
CustomPrompt string
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
**文档版本:** 1.0.0
|
**Document Version:** 1.0.0
|
||||||
**最后更新:** 2025-01-15
|
**Last Updated:** 2025-01-15
|
||||||
|
|||||||
737
docs/architecture/STRATEGY_MODULE.zh-CN.md
Normal file
737
docs/architecture/STRATEGY_MODULE.zh-CN.md
Normal file
@@ -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)
|
||||||
|
├─ 提取思维链 <reasoning>
|
||||||
|
├─ 提取JSON决策 <decision>
|
||||||
|
├─ 修复字符编码
|
||||||
|
├─ 验证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
|
||||||
|
<reasoning>
|
||||||
|
[思维链分析过程]
|
||||||
|
</reasoning>
|
||||||
|
|
||||||
|
<decision>
|
||||||
|
```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": "..."
|
||||||
|
}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
</decision>
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 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: <reasoning> XML标签
|
||||||
|
if match := reReasoningTag.FindStringSubmatch(response); len(match) > 1 {
|
||||||
|
return strings.TrimSpace(match[1])
|
||||||
|
}
|
||||||
|
// 优先级2: <decision>标签之前的文本
|
||||||
|
// 优先级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 (优先级)
|
||||||
|
// - <decision> 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
|
||||||
Reference in New Issue
Block a user