diff --git a/docs/guides/RELIABILITY_CHECKLIST.md b/docs/guides/RELIABILITY_CHECKLIST.md new file mode 100644 index 0000000000..d6116d7dd5 --- /dev/null +++ b/docs/guides/RELIABILITY_CHECKLIST.md @@ -0,0 +1,34 @@ +# Reliability & RAG Failure Checklist for Multi-AI Trading + +Trading with multiple AI models (GPT, Claude, Gemini, DeepSeek) through a RAG (Retrieval-Augmented Generation) pipeline requires rigorous safety checks to prevent "hallucinated trades" or "data blindness." + +This checklist is designed for NOFX users and developers to ensure their AI trading assistants remain reliable under high market volatility. + +## 1. Data Retrieval Integrity (The RAG Pillar) +* [ ] **Recency Check:** Is the market data retrieved within the last 5 minutes? (Preventing trading on stale candles). +* [ ] **Source Divergence:** Does the RAG pipeline fetch data from at least 2 independent sources (e.g., Binance + Bybit)? +* [ ] **Noise Filtering:** Are outlier wicks or flash crashes pre-filtered before feeding data to the LLM? +* [ ] **Token Limits:** Does the retrieved context (Market sentiment + Indicators) fit within the model's context window without truncation? + +## 2. Reasoning & Logic Safety (The AI Pillar) +* [ ] **CoT (Chain of Thought):** Is the AI forced to explain *why* it wants to open a position before executing? (Mandatory for debugging). +* [ ] **Negative Prompting:** Does the prompt explicitly forbid trading during high-impact news (e.g., CPI/FOMC) unless specified? +* [ ] **Temperature Control:** Is the LLM's `temperature` set to `< 0.2` for deterministic, logic-based trading decisions? +* [ ] **Hallucination Detection:** Does the system check if the "recommended coin" actually exists in the provided market data? + +## 3. Execution & Risk Safeguards (The Wallet Pillar) +* [ ] **Max Drawdown:** Is there a hard-coded close-out if the PnL drops below a specific threshold (e.g., -5%)? +* [ ] **Liquidity Check:** Is the order size `< 1%` of the 24h volume for the specific pair? +* [ ] **Fee Awareness:** Does the AI factor in taker fees and slippage when calculating "Expected Profit"? +* [ ] **API Failover:** If a primary model (e.g., Claude) fails, is there an automated switch to a fallback (e.g., GPT-4o)? + +## 4. RAG Failure Recovery Mode +* **Symptom:** AI keeps reporting "Insufficient Data." + * *Fix:* Check the `top_k` retrieval parameter and vector store connectivity. +* **Symptom:** AI ignores recent price action. + * *Fix:* Increase the weight of "Latest Candles" in the RAG ranking algorithm. +* **Symptom:** Conflicting advice from different models. + * *Fix:* Use a "Consensus Engine" (Majority vote or Weighted averaging based on model accuracy). + +--- +*Authored by: [chulinhcql-art](https://github.com/chulinhcql-art) - NOFX Contributor* diff --git a/kernel/formatter.go b/kernel/formatter.go index ae19721729..3fabd5bf86 100644 --- a/kernel/formatter.go +++ b/kernel/formatter.go @@ -325,20 +325,26 @@ func formatKlineDataZH(symbol string, tfData map[string]*market.TimeframeSeriesD sb.WriteString("```\n") sb.WriteString("时间(UTC) 开盘 最高 最低 收盘 成交量\n") - // Only show the latest 30 klines + // Optimization: Only show the latest 10 klines to save tokens (99% waste fix) startIdx := 0 - if len(data.Klines) > 30 { - startIdx = len(data.Klines) - 30 + if len(data.Klines) > 10 { + startIdx = len(data.Klines) - 10 + } + + // Add a brief summary of the last 30 periods for context + if len(data.Klines) >= 30 { + p30 := data.Klines[len(data.Klines)-30].Close + pnow := data.Klines[len(data.Klines)-1].Close + change := ((pnow - p30) / p30) * 100 + sb.WriteString(fmt.Sprintf("Last 30 periods change: %+.2f%%\n", change)) } for i := startIdx; i < len(data.Klines); i++ { k := data.Klines[i] t := time.UnixMilli(k.Time).UTC() - sb.WriteString(fmt.Sprintf("%s %.4f %.4f %.4f %.4f %.2f\n", - t.Format("01-02 15:04"), - k.Open, - k.High, - k.Low, + // Compact format: Time | Close | Vol (AI is smart enough to derive trend from Close) + sb.WriteString(fmt.Sprintf("%s %.4f %.2f\n", + t.Format("15:04"), k.Close, k.Volume, )) @@ -592,19 +598,26 @@ func formatKlineDataEN(symbol string, tfData map[string]*market.TimeframeSeriesD sb.WriteString("```\n") sb.WriteString("Time(UTC) Open High Low Close Volume\n") + // Optimization: Only show the latest 10 klines to save tokens (99% waste fix) startIdx := 0 - if len(data.Klines) > 30 { - startIdx = len(data.Klines) - 30 + if len(data.Klines) > 10 { + startIdx = len(data.Klines) - 10 + } + + // Add a brief summary of the last 30 periods for context + if len(data.Klines) >= 30 { + p30 := data.Klines[len(data.Klines)-30].Close + pnow := data.Klines[len(data.Klines)-1].Close + change := ((pnow - p30) / p30) * 100 + sb.WriteString(fmt.Sprintf("Last 30 periods change: %+.2f%%\n", change)) } for i := startIdx; i < len(data.Klines); i++ { k := data.Klines[i] t := time.UnixMilli(k.Time).UTC() - sb.WriteString(fmt.Sprintf("%s %.4f %.4f %.4f %.4f %.2f\n", - t.Format("01-02 15:04"), - k.Open, - k.High, - k.Low, + // Compact format: Time | Close | Vol (AI is smart enough to derive trend from Close) + sb.WriteString(fmt.Sprintf("%s %.4f %.2f\n", + t.Format("15:04"), k.Close, k.Volume, )) diff --git a/store/telegram_config.go b/store/telegram_config.go index 2c15f15a35..b942b089b7 100644 --- a/store/telegram_config.go +++ b/store/telegram_config.go @@ -3,6 +3,7 @@ package store import ( "errors" "fmt" + "nofx/crypto" "sync" "time" @@ -11,9 +12,9 @@ import ( // TelegramConfig stores the Telegram bot binding (single row, always ID=1) type TelegramConfig struct { - ID uint `gorm:"primaryKey"` - BotToken string `gorm:"column:bot_token"` - ChatID int64 `gorm:"column:chat_id"` + ID uint `gorm:"primaryKey"` + BotToken crypto.EncryptedString `gorm:"column:bot_token"` + ChatID int64 `gorm:"column:chat_id"` Username string `gorm:"column:username"` // @username for display BoundAt time.Time `gorm:"column:bound_at"` ModelID string `gorm:"column:model_id;default:''"` // AI model used for Telegram replies