From 7532d09dfb4f20d9c0b04164e1ba91bf418f823c Mon Sep 17 00:00:00 2001 From: tinkle-community Date: Mon, 15 Dec 2025 15:33:40 +0800 Subject: [PATCH] docs: add strategy module technical documentation - Complete data flow from coin selection to execution - System/user prompt construction details - AI response parsing and validation - Risk control enforcement - Code file references with line numbers --- docs/architecture/STRATEGY_MODULE.md | 735 +++++++++++++++++++++++++++ 1 file changed, 735 insertions(+) create mode 100644 docs/architecture/STRATEGY_MODULE.md diff --git a/docs/architecture/STRATEGY_MODULE.md b/docs/architecture/STRATEGY_MODULE.md new file mode 100644 index 00000000..eebb8832 --- /dev/null +++ b/docs/architecture/STRATEGY_MODULE.md @@ -0,0 +1,735 @@ +# NOFX 策略模块技术文档 + +## 概述 + +本文档详细描述 NOFX 策略模块的完整数据流程,包括币种选择、数据组装、提示词构建、AI 请求、响应解析和决策执行。 + +--- + +## 完整数据流程图 + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ 交易周期 (每 N 分钟) │ +└─────────────────────────────────────────────────────────────────┘ + +1. 币种选择 (GetCandidateCoins) + ├─ Static (静态列表) + ├─ AI500 Pool (AI评分池) + ├─ OI Top (持仓增长榜) + └─ Mixed (混合模式) + ↓ +2. 数据组装 (buildTradingContext) + ├─ 账户余额 → equity, available, unrealizedPnL + ├─ 当前持仓 → symbol, side, entry, mark, qty, leverage + ├─ K线数据 → OHLCV (5m, 15m, 1h, 4h) + ├─ 技术指标 → EMA, MACD, RSI, ATR, Volume + ├─ 链上数据 → OI, Funding Rate + ├─ 量化数据 → 资金流向, OI变化 (可选) + └─ 最近交易 → 最近10笔已平仓 + ↓ +3. 系统提示词 (BuildSystemPrompt) + ├─ 角色定义 + ├─ 交易模式 (aggressive/conservative/scalping) + ├─ 硬性约束 (代码强制执行) + ├─ AI引导 (建议值) + ├─ 交易频率 + ├─ 入场标准 + ├─ 决策流程 + └─ 输出格式 (XML + JSON) + ↓ +4. 用户提示词 (BuildUserPrompt) + ├─ 系统状态 (时间, 周期号) + ├─ BTC市场概览 + ├─ 账户信息 + ├─ 当前持仓 (含技术指标) + ├─ 候选币种 (完整市场数据) + └─ "请分析并输出决策..." + ↓ +5. AI请求 (CallWithMessages) + ├─ 选择AI模型 + ├─ POST: system_prompt + user_prompt + ├─ 超时: 120秒, 重试: 3次 + └─ 返回原始响应 + ↓ +6. AI解析 (parseFullDecisionResponse) + ├─ 提取思维链 + ├─ 提取JSON决策 + ├─ 修复字符编码 + ├─ 验证JSON格式 + ├─ 解析决策数组 + └─ 验证风控参数 + ↓ +7. 决策执行 + ├─ 排序: 平仓优先 → 开仓 → hold/wait + ├─ 风控强制执行 + ├─ 提交订单 + ├─ 确认成交 + └─ 记录到数据库 +``` + +--- + +## 1. 币种选择 (Coin Selection) + +**核心文件:** `decision/engine.go:380-454` + +**入口方法:** `StrategyEngine.GetCandidateCoins()` + +### 1.1 静态币种列表 (Static) + +```go +// decision/engine.go:395-403 +if config.CoinSource.SourceType == "static" { + for _, symbol := range config.CoinSource.StaticCoins { + coins = append(coins, CandidateCoin{ + Symbol: market.Normalize(symbol), + Sources: []string{"static"}, + }) + } +} +``` + +- **配置:** `StrategyConfig.CoinSource.StaticCoins` +- **用途:** 手动指定交易币种 +- **标签:** `["static"]` + +### 1.2 AI500 币种池 (CoinPool) + +```go +// decision/engine.go:405-406, 456-474 +func (e *StrategyEngine) getCoinPoolCoins(limit int) []CandidateCoin { + coins, err := e.provider.GetTopRatedCoins(limit) + // ... + for _, coin := range coins { + result = append(result, CandidateCoin{ + Symbol: coin.Symbol, + Sources: []string{"ai500"}, + }) + } +} +``` + +- **API:** `config.CoinSource.CoinPoolAPIURL` (默认: `http://nofxaios.com:30006/api/ai500/list`) +- **用途:** 获取 AI 评分最高的 N 个币种 +- **标签:** `["ai500"]` + +### 1.3 OI Top 币种 (持仓增长榜) + +```go +// decision/engine.go:408-409, 476-498 +func (e *StrategyEngine) getOITopCoins() []CandidateCoin { + positions, err := e.provider.GetOITopPositions() + // ... + for _, pos := range positions { + result = append(result, CandidateCoin{ + Symbol: pos.Symbol, + Sources: []string{"oi_top"}, + }) + } +} +``` + +- **API:** `config.CoinSource.OITopAPIURL` +- **用途:** 获取持仓量增长最快的币种 +- **标签:** `["oi_top"]` + +### 1.4 混合模式 (Mixed) + +```go +// decision/engine.go:411-449 +if config.CoinSource.SourceType == "mixed" { + if config.CoinSource.UseCoinPool { + // 添加 AI500 币种 + } + if config.CoinSource.UseOITop { + // 添加 OI Top 币种 + } + if len(config.CoinSource.StaticCoins) > 0 { + // 添加静态币种 + } + // 去重合并,保留多来源标签 +} +``` + +- **特点:** 同时使用多个数据源 +- **标签示例:** `["ai500", "oi_top"]` (双信号币种) + +--- + +## 2. 数据组装 (Data Assembly) + +**核心文件:** `trader/auto_trader.go:562-791`, `decision/engine.go:299-374` + +**入口方法:** `AutoTrader.buildTradingContext()` + +### 2.1 账户数据 + +```go +// trader/auto_trader.go:565-583 +balance, err := at.trader.GetBalance() +equity := balance["total_equity"].(float64) +available := balance["available_balance"].(float64) +unrealizedPnL := balance["total_pnl"].(float64) +``` + +**提取字段:** +- `total_equity` - 账户总权益 +- `available_balance` - 可用余额 +- `total_pnl` - 未实现盈亏 + +### 2.2 持仓数据 + +```go +// trader/auto_trader.go:588-682 +positions, err := at.trader.GetPositions() +for _, pos := range positions { + position := decision.Position{ + Symbol: pos.Symbol, + Side: pos.Side, // "long" / "short" + EntryPrice: pos.EntryPrice, + MarkPrice: pos.MarkPrice, + Quantity: pos.Quantity, + Leverage: pos.Leverage, + UnrealizedPnL: pos.UnrealizedPnL, + LiquidationPrice: pos.LiquidationPrice, + } +} +``` + +### 2.3 市场数据获取 + +```go +// decision/engine.go:299-374 +func (e *StrategyEngine) fetchMarketDataWithStrategy(symbols []string) map[string]*market.Data { + timeframes := config.Indicators.Klines.SelectedTimeframes // ["5m", "15m", "1h", "4h"] + primaryTF := config.Indicators.Klines.PrimaryTimeframe // "5m" + count := config.Indicators.Klines.PrimaryCount // 30 + + for _, symbol := range symbols { + data := market.GetWithTimeframes(symbol, timeframes, primaryTF, count) + result[symbol] = data + } +} +``` + +### 2.4 技术指标计算 + +**文件:** `market/data.go:59-98` + +| 指标 | 配置 | 计算方法 | +|------|------|----------| +| **EMA** | `EnableEMA`, `EMAPeriods` | `calculateEMA(klines, period)` | +| **MACD** | `EnableMACD` | `calculateMACD(klines)` - 12/26/9 | +| **RSI** | `EnableRSI`, `RSIPeriods` | `calculateRSI(klines, period)` | +| **ATR** | `EnableATR`, `ATRPeriods` | `calculateATR(klines, period)` | +| **Volume** | `EnableVolume` | 原始成交量数据 | +| **OI** | `EnableOI` | 持仓量数据 | +| **Funding Rate** | `EnableFundingRate` | 资金费率 | + +### 2.5 量化数据 (可选) + +```go +// trader/auto_trader.go:759-778 +if config.Indicators.EnableQuantData { + quantData := provider.GetQuantData(symbol) + // 包含: 资金流向、OI变化、价格变化 +} +``` + +**数据结构:** +```go +QuantData { + Netflow { + Institution: {Future, Spot}, // 机构资金流 + Personal: {Future, Spot} // 散户资金流 + }, + OI { + CurrentOI: float64, + Delta: {1h, 4h, 24h} // OI变化 + }, + PriceChange { + "1h", "4h", "24h": float64 // 价格变化百分比 + } +} +``` + +--- + +## 3. 系统提示词 (System Prompt) + +**核心文件:** `decision/engine.go:700-818` + +**入口方法:** `StrategyEngine.BuildSystemPrompt(accountEquity, variant)` + +### 3.1 提示词结构 (8个部分) + +``` +1. 角色定义 [可编辑] +2. 交易模式变体 [运行时确定] +3. 硬性约束 [代码强制 + AI引导] +4. 交易频率 [可编辑] +5. 入场标准 [可编辑] +6. 决策流程 [可编辑] +7. 输出格式 [固定XML + JSON结构] +8. 自定义提示词 [可选] +``` + +### 3.2 角色定义 + +```go +// decision/engine.go:706-713 +roleDefinition := config.PromptSections.RoleDefinition +if roleDefinition == "" { + roleDefinition = "You are a professional cryptocurrency trading AI..." +} +``` + +### 3.3 交易模式变体 + +| 模式 | 特点 | +|------|------| +| `aggressive` | 趋势突破,较高仓位容忍度 | +| `conservative` | 多信号确认,保守资金管理 | +| `scalping` | 短线动量,紧止盈 | + +### 3.4 硬性约束 + +**代码强制执行 (CODE ENFORCED):** + +```go +// decision/engine.go:725-749 +maxPositions := config.RiskControl.MaxPositions // 默认: 3 +altcoinMaxRatio := config.RiskControl.AltcoinMaxPositionValueRatio // 默认: 1.0 +btcethMaxRatio := config.RiskControl.BTCETHMaxPositionValueRatio // 默认: 5.0 +maxMarginUsage := config.RiskControl.MaxMarginUsage // 默认: 90% +minPositionSize := config.RiskControl.MinPositionSize // 默认: 12 USDT +``` + +**AI引导 (建议值):** + +```go +altcoinMaxLeverage := config.RiskControl.AltcoinMaxLeverage // 默认: 5x +btcethMaxLeverage := config.RiskControl.BTCETHMaxLeverage // 默认: 5x +minRiskRewardRatio := config.RiskControl.MinRiskRewardRatio // 默认: 1:3 +minConfidence := config.RiskControl.MinConfidence // 默认: 75 +``` + +### 3.5 输出格式要求 + +```xml + +[思维链分析过程] + + + +```json +[ + { + "symbol": "BTCUSDT", + "action": "open_long", + "leverage": 5, + "position_size_usd": 100.00, + "stop_loss": 65000.00, + "take_profit": 72000.00, + "confidence": 85, + "risk_usd": 20.00, + "reasoning": "..." + } +] +``` + +``` + +--- + +## 4. 用户提示词 (User Prompt) + +**核心文件:** `decision/engine.go:884-1007` + +**入口方法:** `StrategyEngine.BuildUserPrompt(ctx)` + +### 4.1 提示词内容结构 + +``` +1. 系统状态 [时间, 周期号, 运行时长] +2. BTC市场概览 [价格, 涨跌幅, MACD, RSI] +3. 账户信息 [权益, 余额%, 盈亏%, 保证金%, 持仓数] +4. 最近成交 [最近10笔已平仓交易] +5. 当前持仓 [详细持仓数据 + 技术指标] +6. 候选币种 [完整市场数据] +7. 量化数据 [资金流向, OI数据] (可选) +8. OI排行数据 [市场OI变化排行] (可选) +``` + +### 4.2 账户信息格式 + +``` +Account: Equity 1000.00 | Balance 800.00 (80.0%) | PnL +5.5% | Margin 20.0% | Positions 2 +``` + +### 4.3 持仓信息格式 + +``` +1. BTCUSDT LONG | Entry 68000.0000 Current 69500.0000 + Qty 0.0100 | Position Value $695.00 + PnL +2.21% | Amount +$15.00 + Peak PnL +3.50% | Leverage 5x + Margin $139.00 | Liquidation Price 55000.0000 + Holding Duration 2 hours 30 minutes + + Market: price=69500, ema20=68800, macd=150.5, rsi7=62.3 + OI: Latest=15000000, Avg=14500000 + Funding Rate: 0.0100% +``` + +### 4.4 候选币种格式 + +``` +### 1. ETHUSDT (AI500+OI_Top dual signal) + +current_price = 3500.00, current_ema20 = 3450.00, current_macd = 25.5, current_rsi7 = 58.0 + +Open Interest: Latest: 8500000.00 Average: 8200000.00 +Funding Rate: 0.0050 + +=== 5M TIMEFRAME (oldest → latest) === +Prices: [3480, 3485, 3490, 3495, 3500] +Volumes: [1000, 1200, 1100, 1300, 1150] +EMA20: [3470, 3475, 3478, 3482, 3485] +MACD: [20.1, 21.5, 22.8, 24.0, 25.5] +RSI7: [55.0, 56.2, 57.1, 57.8, 58.0] + +=== 15M TIMEFRAME === +... +``` + +--- + +## 5. AI请求 (AI Request) + +**核心文件:** `decision/engine.go:222-293`, `mcp/client.go:136-150` + +### 5.1 请求流程 + +```go +// decision/engine.go:263-268 +aiCallStart := time.Now() +aiResponse, err := mcpClient.CallWithMessages(systemPrompt, userPrompt) +aiCallDuration := time.Since(aiCallStart) +``` + +### 5.2 支持的AI模型 + +| 模型 | 客户端文件 | 默认模型 | +|------|-----------|----------| +| **DeepSeek** | `mcp/deepseek_client.go` | deepseek-chat | +| **Qwen** | `mcp/qwen_client.go` | qwen-max | +| **Claude** | `mcp/claude_client.go` | claude-3-5-sonnet | +| **Gemini** | `mcp/gemini_client.go` | gemini-pro | +| **Grok** | `mcp/grok_client.go` | grok-beta | +| **OpenAI** | `mcp/openai_client.go` | gpt-5.2 | +| **Kimi** | `mcp/kimi_client.go` | moonshot-v1-8k | + +### 5.3 请求参数 + +```go +// mcp/client.go +Timeout: 120 seconds +MaxRetries: 3 +RetryDelay: 2 seconds (exponential backoff) +``` + +--- + +## 6. AI响应解析 (Response Parsing) + +**核心文件:** `decision/engine.go:1303-1604` + +**入口方法:** `parseFullDecisionResponse(response, accountEquity, leverage, ratio)` + +### 6.1 解析流程 + +``` +原始AI响应 (文本) + ↓ +1. 提取思维链 [extractCoTTrace()] + ↓ +2. 提取JSON决策 [extractDecisions()] + ↓ +3. 验证JSON格式 [validateJSONFormat()] + ↓ +4. 解析JSON [json.Unmarshal()] + ↓ +5. 验证决策 [validateDecisions()] + ↓ +6. 构建FullDecision [返回结构化结果] +``` + +### 6.2 思维链提取 + +```go +// decision/engine.go:1327-1345 +func extractCoTTrace(response string) string { + // 优先级1: XML标签 + if match := reReasoningTag.FindStringSubmatch(response); len(match) > 1 { + return strings.TrimSpace(match[1]) + } + // 优先级2: 标签之前的文本 + // 优先级3: JSON [ 之前的文本 + // 优先级4: 完整响应 +} +``` + +### 6.3 JSON决策提取 + +```go +// decision/engine.go:1347-1408 +func extractDecisions(response string) (string, error) { + // 1. 移除不可见字符 + response = removeInvisibleRunes(response) + + // 2. 修复字符编码 + response = fixMissingQuotes(response) + + // 3. 提取JSON (优先级) + // - XML标签 + ```json + // - 独立 ```json 代码块 + // - 裸JSON数组 +} +``` + +### 6.4 字符编码修复 + +```go +// decision/engine.go:1410-1432 +func fixMissingQuotes(s string) string { + // 中文引号 → ASCII + s = strings.ReplaceAll(s, """, "\"") + s = strings.ReplaceAll(s, """, "\"") + + // 中文括号 → ASCII + s = strings.ReplaceAll(s, "[", "[") + s = strings.ReplaceAll(s, "]", "]") + s = strings.ReplaceAll(s, "{", "{") + s = strings.ReplaceAll(s, "}", "}") + + // 中文标点 → ASCII + s = strings.ReplaceAll(s, ":", ":") + s = strings.ReplaceAll(s, ",", ",") +} +``` + +### 6.5 决策验证 + +```go +// decision/engine.go:1480-1602 +func validateDecisions(decisions []Decision, equity, leverage, ratio float64) error { + for _, d := range decisions { + // 1. 验证action类型 + validActions := []string{"open_long", "open_short", "close_long", "close_short", "hold", "wait"} + + // 2. 开仓验证 + if isOpenAction(d.Action) { + // 杠杆范围检查 + // 仓位大小检查 + // 止损止盈检查 + // 风险回报比检查 + // 置信度检查 + } + + // 3. 平仓验证 + if isCloseAction(d.Action) { + // Symbol必须存在 + } + } +} +``` + +### 6.6 Decision结构体 + +```go +// decision/engine.go:128-143 +type Decision struct { + Symbol string // 交易对: "BTCUSDT" + Action string // "open_long", "open_short", "close_long", "close_short", "hold", "wait" + Leverage int // 杠杆倍数 + PositionSizeUSD float64 // 仓位价值 (USDT) + StopLoss float64 // 止损价格 + TakeProfit float64 // 止盈价格 + Confidence int // 置信度 0-100 + RiskUSD float64 // 最大风险 (USDT) + Reasoning string // 决策理由 +} +``` + +--- + +## 7. 决策执行 (Execution) + +**核心文件:** `trader/auto_trader.go:392-560` + +### 7.1 决策排序 + +```go +// trader/auto_trader.go:519-526 +sort.SliceStable(decisions, func(i, j int) bool { + priority := map[string]int{ + "close_long": 1, "close_short": 1, // 最高优先级 + "open_long": 2, "open_short": 2, // 次优先级 + "hold": 3, "wait": 3, // 最低优先级 + } + return priority[decisions[i].Action] < priority[decisions[j].Action] +}) +``` + +### 7.2 风控强制执行 + +**文件:** `trader/auto_trader.go:1769-1851` + +| 检查项 | 方法 | 动作 | +|--------|------|------| +| 最大持仓数 | `enforceMaxPositions()` | 拒绝新开仓 | +| 仓位价值上限 | `enforcePositionValueRatio()` | 自动缩减仓位 | +| 最小仓位 | `enforceMinPositionSize()` | 拒绝过小订单 | +| 保证金调整 | 自动计算 | 根据可用余额调整 | + +### 7.3 订单执行 + +```go +// trader/auto_trader.go:1631-1767 +func (at *AutoTrader) recordAndConfirmOrder(orderID, symbol, side, action string) { + // 1. 轮询订单状态 (5次重试, 500ms间隔) + for i := 0; i < 5; i++ { + status := at.trader.GetOrderStatus(orderID) + if status.Status == "FILLED" { + break + } + time.Sleep(500 * time.Millisecond) + } + + // 2. 提取成交信息 + filledPrice := status.AvgPrice + filledQty := status.FilledQty + fee := status.Fee + + // 3. 记录到数据库 + at.store.Position().SaveOrder(...) +} +``` + +### 7.4 决策日志保存 + +```go +// trader/auto_trader.go:1235-1256 +record := &store.DecisionRecord{ + CycleNumber: cycleNumber, + TraderID: traderID, + Timestamp: time.Now(), + SystemPrompt: systemPrompt, // 完整系统提示词 + InputPrompt: userPrompt, // 完整用户提示词 + CoTTrace: cotTrace, // AI思维链 + DecisionJSON: decisionsJSON, // 解析后的决策 + RawResponse: rawResponse, // 原始AI响应 + ExecutionLog: executionResults, // 执行结果 + CandidateCoins: candidateCoins, // 候选币种 + Success: success, // 执行状态 +} +at.store.Decision().LogDecision(record) +``` + +--- + +## 核心文件索引 + +| 模块 | 文件 | 关键方法 | +|------|------|----------| +| **主循环** | `trader/auto_trader.go` | `Run()`, `runCycle()`, `buildTradingContext()` | +| **币种选择** | `decision/engine.go:380-454` | `GetCandidateCoins()` | +| **数据获取** | `market/data.go` | `Get()`, `GetWithTimeframes()` | +| **指标计算** | `market/data.go:59-98` | `calculateEMA()`, `calculateMACD()`, `calculateRSI()` | +| **系统提示词** | `decision/engine.go:700-818` | `BuildSystemPrompt()` | +| **用户提示词** | `decision/engine.go:884-1007` | `BuildUserPrompt()` | +| **市场数据格式化** | `decision/engine.go:1029-1099` | `formatMarketData()` | +| **AI请求** | `decision/engine.go:222-293` | `GetFullDecisionWithStrategy()` | +| **MCP客户端** | `mcp/client.go:136-150` | `CallWithMessages()` | +| **响应解析** | `decision/engine.go:1303-1604` | `parseFullDecisionResponse()` | +| **思维链提取** | `decision/engine.go:1327-1345` | `extractCoTTrace()` | +| **JSON提取** | `decision/engine.go:1347-1408` | `extractDecisions()` | +| **决策验证** | `decision/engine.go:1480-1602` | `validateDecisions()` | +| **风控执行** | `trader/auto_trader.go:1769-1851` | `enforceMaxPositions()`, `enforcePositionValueRatio()` | +| **策略配置** | `store/strategy.go` | `StrategyConfig`, `RiskControlConfig` | +| **数据提供者** | `provider/data_provider.go` | `GetAI500Data()`, `GetOITopPositions()` | + +--- + +## 配置参考 + +### 策略配置结构 + +```go +// store/strategy.go +type StrategyConfig struct { + // 币种来源 + CoinSource struct { + SourceType string // "static", "coinpool", "oi_top", "mixed" + StaticCoins []string // 静态币种列表 + UseCoinPool bool // 是否使用AI500 + UseOITop bool // 是否使用OI排行 + CoinPoolLimit int // AI500获取数量 + CoinPoolAPIURL string // AI500 API地址 + OITopAPIURL string // OI排行 API地址 + } + + // 技术指标 + Indicators struct { + EnableEMA bool + EMAPeriods []int // [20, 50] + EnableMACD bool + EnableRSI bool + RSIPeriods []int // [7, 14] + EnableATR bool + ATRPeriods []int // [14] + EnableVolume bool + EnableOI bool + EnableFundingRate bool + EnableQuantData bool + EnableOIRanking bool + + Klines struct { + PrimaryTimeframe string // "5m" + SelectedTimeframes []string // ["5m", "15m", "1h", "4h"] + PrimaryCount int // 30 + } + } + + // 风控配置 + RiskControl struct { + MaxPositions int // 最大持仓数 + BTCETHMaxLeverage int // BTC/ETH最大杠杆 + AltcoinMaxLeverage int // 山寨币最大杠杆 + BTCETHMaxPositionValueRatio float64 // BTC/ETH仓位比例上限 + AltcoinMaxPositionValueRatio float64 // 山寨币仓位比例上限 + MaxMarginUsage float64 // 最大保证金使用率 + MinPositionSize float64 // 最小仓位 + MinRiskRewardRatio float64 // 最小风险回报比 + MinConfidence int // 最小置信度 + } + + // 提示词部分 + PromptSections struct { + RoleDefinition string + TradingFrequency string + EntryStandards string + DecisionProcess string + } + + // 自定义提示词 + CustomPrompt string +} +``` + +--- + +**文档版本:** 1.0.0 +**最后更新:** 2025-01-15