diff --git a/README.md b/README.md index ede2ab31..7ac4f409 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,43 @@ -# 🤖 NOFX - Multi-AI Model Automated Trading Platform +# 🤖 NOFX - Agentic Trading OS [](https://golang.org/) [](https://reactjs.org/) [](https://www.typescriptlang.org/) -[](https://sqlite.org/) [](LICENSE) +[](https://amber.ac) **Languages:** [English](README.md) | [中文](README.zh-CN.md) | [Українська](README.uk.md) | [Русский](README.ru.md) +**Official Twitter:** [@nofx_ai](https://x.com/nofx_ai) + --- -A modern automated crypto futures trading platform powered by **DeepSeek/Qwen AI**, supporting **Binance, Hyperliquid, and Aster DEX exchanges**. Create and manage multiple AI traders with dynamic configuration through a web interface. Features comprehensive market analysis, AI decision-making, **multi-AI model live trading competition**, **self-learning mechanism**, and professional monitoring dashboard. +## 🚀 Universal AI Trading Operating System + +**NOFX** is a **universal Agentic Trading OS** built on a unified architecture. We've successfully closed the loop in crypto markets: **"Multi-Agent Decision → Unified Risk Control → Low-Latency Execution → Live/Paper Account Backtesting"**, and are now expanding this same technology stack to **stocks, futures, options, forex, and all financial markets**. + +### 🎯 Core Features + +- **Universal Data & Backtesting Layer**: Cross-market, cross-timeframe, cross-exchange unified representation and factor library, accumulating transferable "strategy memory" +- **Multi-Agent Self-Play & Self-Evolution**: Strategies automatically compete and select the best, continuously iterating based on account-level PnL and risk constraints +- **Integrated Execution & Risk Control**: Low-latency routing, slippage/risk control sandbox, account-level limits, one-click market switching + +### 🏢 Backed by [Amber.ac](https://amber.ac) + +### 👥 Core Team + +- **Tinkle** - [@Web3Tinkle](https://x.com/Web3Tinkle) +- **Zack** - [@0x_ZackH](https://x.com/0x_ZackH) + +### 💼 Seed Funding Round Open + +We are currently raising our **seed round**. + +**For investment inquiries**, please DM **Tinkle** or **Zack** via Twitter. + +**For partnerships and collaborations**, please DM our official Twitter [@nofx_ai](https://x.com/nofx_ai). + +--- > ⚠️ **Risk Warning**: This system is experimental. AI auto-trading carries significant risks. Strongly recommended for learning/research purposes or testing with small amounts only! @@ -24,11 +51,7 @@ Join our Telegram developer community to discuss, share ideas, and get support: ## 🆕 What's New (Latest Update) -### 🚀 Complete System Transformation - Web-Based Configuration! - -NOFX has been **completely transformed** from a static config-based system to a **dynamic web-based trading platform** with **multi-exchange support**! - -#### **Multi-Exchange Support** +### 🚀 Multi-Exchange Support! NOFX now supports **three major exchanges**: Binance, Hyperliquid, and Aster DEX! @@ -36,13 +59,12 @@ NOFX now supports **three major exchanges**: Binance, Hyperliquid, and Aster DEX A high-performance decentralized perpetual futures exchange! -**Major Changes:** -- ✅ **Web-Based Configuration**: Create and manage AI traders through a modern web interface -- ✅ **Database-Driven Architecture**: SQLite database replaces static JSON configuration -- ✅ **Separate AI Models & Exchanges**: Configure AI models and exchanges independently -- ✅ **Dynamic Trader Creation**: Create traders by combining configured AI models and exchanges -- ✅ **Real-Time Management**: Start/stop traders, update configurations without restart -- ✅ **No Default Traders**: Clean slate - create only the traders you need +**Key Features:** +- ✅ Full trading support (long/short, leverage, stop-loss/take-profit) +- ✅ Automatic precision handling (order size & price) +- ✅ Unified trader interface (seamless exchange switching) +- ✅ Support for both mainnet and testnet +- ✅ No API keys needed - just your Ethereum private key **New Workflow:** 1. **Configure AI Models**: Add your DeepSeek/Qwen API keys through the web interface @@ -96,58 +118,64 @@ A Binance-compatible decentralized perpetual futures exchange! --- -## ✨ Core Features +## ✨ Current Implementation - Crypto Markets -### 🎛️ Web-Based Configuration Management -- **Dynamic AI Model Setup**: Configure DeepSeek and Qwen API keys through web interface -- **Exchange Management**: Set up Binance and Hyperliquid credentials independently -- **Flexible Trader Creation**: Mix any AI model with any exchange -- **Real-Time Control**: Start/stop traders without system restart +NOFX is currently **fully operational in cryptocurrency markets** with the following proven capabilities: -### 🧠 AI Self-Learning Mechanism (NEW!) -- **Historical Feedback**: Analyzes last 20 cycles of trading performance before each decision -- **Smart Optimization**: - - Identifies best/worst performing coins - - Calculates win rate, profit/loss ratio, average profit - - Avoids repeating mistakes (consecutive losing coins) +### 🏆 Multi-Agent Competition Framework +- **Live Agent Battle**: Qwen vs DeepSeek models compete in real-time trading +- **Independent Account Management**: Each agent maintains its own decision logs and performance metrics +- **Real-time Performance Comparison**: Live ROI tracking, win rate statistics, and head-to-head analysis +- **Self-Evolution Loop**: Agents learn from their historical performance and continuously improve + +### 🧠 AI Self-Learning & Optimization +- **Historical Feedback System**: Analyzes last 20 trading cycles before each decision +- **Smart Performance Analysis**: + - Identifies best/worst performing assets + - Calculates win rate, profit/loss ratio, average profit in real USDT terms + - Avoids repeating mistakes (consecutive losing patterns) - Reinforces successful strategies (high win rate patterns) -- **Dynamic Adjustment**: AI autonomously adjusts trading style based on historical performance +- **Dynamic Strategy Adjustment**: AI autonomously adapts trading style based on backtest results -### 📊 Intelligent Market Analysis -- **3-minute K-line**: Real-time price, EMA20, MACD, RSI(7) -- **4-hour K-line**: Long-term trend, EMA20/50, ATR, RSI(14) -- **Open Interest Analysis**: Market sentiment, capital flow judgment -- **OI Top Tracking**: Top 20 coins with fastest growing open interest -- **AI500 Coin Pool**: Automatic high-score coin screening -- **Liquidity Filter**: Auto-filters low liquidity coins (<15M USD position value) +### 📊 Universal Market Data Layer (Crypto Implementation) +- **Multi-Timeframe Analysis**: 3-minute real-time + 4-hour trend data +- **Technical Indicators**: EMA20/50, MACD, RSI(7/14), ATR +- **Open Interest Tracking**: Market sentiment, capital flow analysis +- **Liquidity Filtering**: Auto-filters low liquidity assets (<15M USD) +- **Cross-Exchange Support**: Binance, Hyperliquid, Aster DEX with unified data interface -### 🎯 Professional Risk Control -- **Per-Coin Position Limit**: - - Altcoins ≤ 1.5x account equity - - BTC/ETH ≤ 10x account equity -- **Configurable Leverage** (v2.0.3+): - - Set maximum leverage in config.json - - Default: 5x for all coins (safe for subaccounts) - - Main accounts can increase: Altcoins up to 20x, BTC/ETH up to 50x - - ⚠️ Binance subaccounts restricted to ≤5x leverage -- **Margin Management**: Total usage ≤90%, AI autonomous decision on usage rate -- **Risk-Reward Ratio**: Mandatory ≥1:2 (stop-loss:take-profit) -- **Prevent Position Stacking**: No duplicate opening of same coin/direction +### 🎯 Unified Risk Control System +- **Position Limits**: Per-asset limits (Altcoins ≤1.5x equity, BTC/ETH ≤10x equity) +- **Configurable Leverage**: Dynamic leverage from 1x to 50x based on asset class and account type +- **Margin Management**: Total usage ≤90%, AI-controlled allocation +- **Risk-Reward Enforcement**: Mandatory ≥1:2 stop-loss to take-profit ratio +- **Anti-Stacking Protection**: Prevents duplicate positions in same asset/direction -### 🎨 Professional UI -- **Professional Trading Interface**: Binance-style visual design -- **Dark Theme**: Classic color scheme (Gold #F0B90B + dark background) -- **Real-time Data**: 5-second refresh for accounts, positions, charts -- **Equity Curve**: Historical account value trend (USD/percentage toggle) -- **Performance Comparison Chart**: Real-time multi-AI ROI comparison -- **Smooth Animations**: Fluid hover, transition, and loading effects +### ⚡ Low-Latency Execution Engine +- **Multi-Exchange API Integration**: Binance Futures, Hyperliquid DEX, Aster DEX +- **Automatic Precision Handling**: Smart order size & price formatting per exchange +- **Priority Execution**: Close existing positions first, then open new ones +- **Slippage Control**: Pre-execution validation, real-time precision checks -### 📝 Complete Decision Recording -- **Chain of Thought**: AI's complete reasoning process (CoT) -- **Historical Performance**: Overall win rate, average profit, profit/loss ratio -- **Recent Trades**: Last 5 trade details (entry price → exit price → P/L%) -- **Coin Statistics**: Per-coin performance (win rate, average P/L) -- **JSON Logs**: Complete decision records for post-trade analysis +### 🎨 Professional Monitoring Interface +- **Binance-Style Dashboard**: Professional dark theme with real-time updates +- **Equity Curves**: Historical account value tracking (USD/percentage toggle) +- **Performance Charts**: Multi-agent ROI comparison with live updates +- **Complete Decision Logs**: Full Chain of Thought (CoT) reasoning for every trade +- **5-Second Data Refresh**: Real-time account, position, and P/L updates + +--- + +## 🔮 Roadmap - Universal Market Expansion + +Our proven crypto infrastructure is being extended to: + +- **📈 Stock Markets**: US equities, A-shares, Hong Kong stocks +- **📊 Futures Markets**: Commodity futures, index futures +- **🎯 Options Trading**: Equity options, crypto options +- **💱 Forex Markets**: Major currency pairs, cross rates + +**Same architecture. Same agent framework. All markets.** --- @@ -1365,8 +1393,10 @@ Issues and Pull Requests are welcome! ## 📬 Contact -- **Twitter/X**: [@Web3Tinkle](https://x.com/Web3Tinkle) + +### 🐛 Technical Support - **GitHub Issues**: [Submit an Issue](https://github.com/tinkle-community/nofx/issues) +- **Developer Community**: [Telegram Group](https://t.me/nofx_dev_community) --- diff --git a/README.ru.md b/README.ru.md index 7c1d7aed..2d2e6ff3 100644 --- a/README.ru.md +++ b/README.ru.md @@ -1,15 +1,43 @@ -# 🤖 NOFX - AI-управляемая система автоматической торговли фьючерсами Binance +# 🤖 NOFX - Agentic Trading OS [](https://golang.org/) [](https://reactjs.org/) [](https://www.typescriptlang.org/) [](LICENSE) +[](https://amber.ac) **Языки / Languages:** [English](README.md) | [中文](README.zh-CN.md) | [Українська](README.uk.md) | [Русский](README.ru.md) +**Официальный Twitter:** [@nofx_ai](https://x.com/nofx_ai) + --- -Автоматизированная система торговли криптовалютными фьючерсами на базе **DeepSeek/Qwen AI**, поддерживающая **Binance, Hyperliquid и Aster DEX биржи**, **конкуренцию нескольких AI-моделей в реальной торговле**, с полным анализом рынка, принятием решений AI, **механизмом самообучения** и профессиональным веб-интерфейсом мониторинга. +## 🚀 Универсальная AI Торговая Операционная Система + +**NOFX** - это **универсальная Agentic Trading OS**, построенная на единой архитектуре. Мы успешно замкнули цикл на криптовалютных рынках: **"Решение Multi-Agent → Единый Контроль Рисков → Исполнение с Низкой Задержкой → Бэктестинг Реальных/Бумажных Счетов"**, и сейчас расширяем этот же технологический стек на **акции, фьючерсы, опционы, форекс и все финансовые рынки**. + +### 🎯 Основные Возможности + +- **Универсальный Слой Данных и Бэктестинга**: Кросс-рыночное, кросс-таймфреймовое, кросс-биржевое единое представление и библиотека факторов, накапливающая переносимую "память стратегий" +- **Multi-Agent Самоигра и Самоэволюция**: Стратегии автоматически конкурируют и выбирают лучшие, непрерывно итерируясь на основе PnL на уровне счета и ограничений рисков +- **Интегрированное Исполнение и Контроль Рисков**: Маршрутизация с низкой задержкой, песочница проскальзывания/контроля рисков, лимиты на уровне счета, переключение рынков одним кликом + +### 🏢 При поддержке [Amber.ac](https://amber.ac) + +### 👥 Основная Команда + +- **Tinkle** - [@Web3Tinkle](https://x.com/Web3Tinkle) +- **Zack** - [@0x_ZackH](https://x.com/0x_ZackH) + +### 💼 Открыт Посевной Раунд Финансирования + +Мы в настоящее время привлекаем **посевной раунд**. + +**По вопросам инвестиций**, пишите в DM **Tinkle** или **Zack** в Twitter. + +**По вопросам партнерства и сотрудничества**, пишите в DM нашего официального Twitter [@nofx_ai](https://x.com/nofx_ai). + +--- > ⚠️ **Предупреждение о рисках**: Эта система экспериментальная. Автоматическая торговля с AI несет значительные риски. Настоятельно рекомендуется использовать только для обучения/исследований или тестирования с небольшими суммами! diff --git a/README.uk.md b/README.uk.md index 0412e8dc..0ec6d5df 100644 --- a/README.uk.md +++ b/README.uk.md @@ -1,15 +1,43 @@ -# 🤖 NOFX - AI-керована система автоматичної торгівлі ф'ючерсами Binance +# 🤖 NOFX - Agentic Trading OS [](https://golang.org/) [](https://reactjs.org/) [](https://www.typescriptlang.org/) [](LICENSE) +[](https://amber.ac) **Мови / Languages:** [English](README.md) | [中文](README.zh-CN.md) | [Українська](README.uk.md) | [Русский](README.ru.md) +**Офіційний Twitter:** [@nofx_ai](https://x.com/nofx_ai) + --- -Автоматизована система торгівлі криптовалютними ф'ючерсами на базі **DeepSeek/Qwen AI**, що підтримує **Binance, Hyperliquid та Aster DEX біржі**, **змагання кількох AI-моделей у реальній торгівлі**, з повним аналізом ринку, прийняттям рішень AI, **механізмом самонавчання** та професійним веб-інтерфейсом моніторингу. +## 🚀 Універсальна AI Торгова Операційна Система + +**NOFX** - це **універсальна Agentic Trading OS**, побудована на єдиній архітектурі. Ми успішно замкнули цикл на криптовалютних ринках: **"Рішення Multi-Agent → Єдиний Контроль Ризиків → Виконання з Низькою Затримкою → Бектестинг Реальних/Паперових Рахунків"**, і зараз розширюємо цей же технологічний стек на **акції, ф'ючерси, опціони, форекс та всі фінансові ринки**. + +### 🎯 Основні Можливості + +- **Універсальний Шар Даних та Бектестингу**: Крос-ринкове, крос-таймфреймове, крос-біржеве єдине представлення та бібліотека факторів, що накопичує переносиму "пам'ять стратегій" +- **Multi-Agent Самогра та Самоеволюція**: Стратегії автоматично конкурують і вибирають кращі, безперервно ітеруючись на основі PnL на рівні рахунку та обмежень ризиків +- **Інтегроване Виконання та Контроль Ризиків**: Маршрутизація з низькою затримкою, пісочниця прослизання/контролю ризиків, ліміти на рівні рахунку, перемикання ринків одним кліком + +### 🏢 За підтримки [Amber.ac](https://amber.ac) + +### 👥 Основна Команда + +- **Tinkle** - [@Web3Tinkle](https://x.com/Web3Tinkle) +- **Zack** - [@0x_ZackH](https://x.com/0x_ZackH) + +### 💼 Відкритий Посівний Раунд Фінансування + +Ми зараз залучаємо **посівний раунд**. + +**З питань інвестицій**, пишіть в DM **Tinkle** або **Zack** в Twitter. + +**З питань партнерства та співпраці**, пишіть в DM нашого офіційного Twitter [@nofx_ai](https://x.com/nofx_ai). + +--- > ⚠️ **Попередження про ризики**: Ця система експериментальна. Автоматична торгівля з AI несе значні ризики. Наполегливо рекомендується використовувати лише для навчання/досліджень або тестування з невеликими сумами! diff --git a/README.zh-CN.md b/README.zh-CN.md index 4d479bd6..75be2f64 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -1,15 +1,43 @@ -# 🤖 NOFX - AI驱动的币安合约自动交易竞赛系统 +# 🤖 NOFX - AI交易操作系统 [](https://golang.org/) [](https://reactjs.org/) [](https://www.typescriptlang.org/) [](LICENSE) +[](https://amber.ac) **语言 / Languages:** [English](README.md) | [中文](README.zh-CN.md) | [Українська](README.uk.md) | [Русский](README.ru.md) +**官方推特:** [@nofx_ai](https://x.com/nofx_ai) + --- -一个基于 **DeepSeek/Qwen AI** 的加密货币期货自动交易系统,支持 **Binance、Hyperliquid和Aster DEX交易所**,**多AI模型实盘竞赛**,具备完整的市场分析、AI决策、**自我学习机制**和专业的Web监控界面。 +## 🚀 通用AI交易操作系统 + +**NOFX** 是通用架构的 **AI交易操作系统(Agentic Trading OS)**。我们已在加密市场打通"**多智能体决策 → 统一风控 → 低延迟执行 → 真实/纸面账户复盘**"的闭环,正按同一技术栈扩展到**股票、期货、期权、外汇等所有市场**。 + +### 🎯 核心特性 + +- **通用数据与回测层**:跨市场、跨周期、跨交易所统一表示与因子库,沉淀可迁移的"策略记忆" +- **多智能体自博弈与自进化**:策略自动对战择优,按账户级 PnL 与风险约束持续迭代 +- **执行与风控一体化**:低延迟路由、滑点/风控沙箱、账户级限额,一键切换市场 + +### 🏢 由 [Amber.ac](https://amber.ac) 背书 + +### 👥 核心团队 + +- **Tinkle** - [@Web3Tinkle](https://x.com/Web3Tinkle) +- **Zack** - [@0x_ZackH](https://x.com/0x_ZackH) + +### 💼 种子轮融资进行中 + +我们正在进行**种子轮融资**。 + +**投资咨询**,请通过 Twitter 私信联系 **Tinkle** 或 **Zack**。 + +**商务合作**,请私信官方推特 [@nofx_ai](https://x.com/nofx_ai)。 + +--- > ⚠️ **风险提示**:本系统为实验性项目,AI自动交易存在重大风险,强烈建议仅用于学习研究或小额资金测试! @@ -90,58 +118,64 @@ NOFX现已支持**三大交易所**:Binance、Hyperliquid和Aster DEX! --- -## ✨ 核心特性 +## ✨ 当前实现 - 加密货币市场 -### 🏆 多AI竞赛模式 -- **Qwen vs DeepSeek** 实盘对抗 -- 独立账户管理,独立决策日志 -- 实时性能对比图表 -- 收益率PK,胜率统计 +NOFX 目前已在**加密货币市场全面运行**,具备以下经过验证的能力: -### 🧠 AI自我学习机制(NEW!) -- **历史反馈**: 每次决策前分析最近20个周期的交易表现 -- **智能优化**: - - 识别表现最佳/最差币种 - - 计算胜率、盈亏比、平均盈利 - - 避免重复错误(连续亏损的币种) - - 强化成功策略(高胜率的交易模式) -- **动态调整**: AI根据历史表现自主调整交易风格 +### 🏆 多智能体竞赛框架 +- **实时智能体对战**:Qwen vs DeepSeek 模型实时交易竞赛 +- **独立账户管理**:每个智能体维护独立的决策日志和性能指标 +- **实时性能对比**:实时 ROI 追踪、胜率统计、正面对抗分析 +- **自进化循环**:智能体从历史表现中学习,持续改进 -### 📊 智能市场分析 -- **3分钟K线**: 实时价格、EMA20、MACD、RSI(7) -- **4小时K线**: 长期趋势、EMA20/50、ATR、RSI(14) -- **持仓量分析**: 市场情绪、资金流向判断 -- **OI Top追踪**: 持仓量增长最快的20个币种 -- **AI500币种池**: 高评分币种自动筛选 -- **流动性过滤**: 自动过滤持仓价值<15M USD的低流动性币种 +### 🧠 AI 自学习与优化 +- **历史反馈系统**:每次决策前分析最近 20 个交易周期 +- **智能性能分析**: + - 识别表现最佳/最差资产 + - 计算胜率、盈亏比、以真实 USDT 计的平均盈利 + - 避免重复错误(连续亏损模式) + - 强化成功策略(高胜率模式) +- **动态策略调整**:AI 根据回测结果自主调整交易风格 -### 🎯 专业风险控制 -- **单币种仓位上限**: - - 山寨币 ≤ 1.5倍账户净值 - - BTC/ETH ≤ 10倍账户净值 -- **可配置杠杆** (v2.0.3+): - - 在config.json中设置最大杠杆 - - 默认:所有币种5倍(子账户安全) - - 主账户可增加:山寨币最高20倍,BTC/ETH最高50倍 - - ⚠️ 币安子账户限制≤5倍杠杆 -- **保证金管理**: 总使用率≤90%,AI自主决策使用率 -- **风险回报比**: 强制≥1:2(止损:止盈) -- **防止仓位叠加**: 同币种同方向不允许重复开仓 +### 📊 通用市场数据层(加密货币实现) +- **多时间框架分析**:3分钟实时 + 4小时趋势数据 +- **技术指标**:EMA20/50、MACD、RSI(7/14)、ATR +- **持仓量追踪**:市场情绪、资金流向分析 +- **流动性过滤**:自动过滤低流动性资产(<15M USD) +- **跨交易所支持**:Binance、Hyperliquid、Aster DEX,统一数据接口 -### 🎨 风格UI -- **专业交易界面**: 视觉设计 -- **暗色主题**: 经典配色(金色#F0B90B + 深色背景) -- **实时数据**: 5秒刷新账户、持仓、图表 -- **收益率曲线**: 账户净值历史走势(美元/百分比切换) -- **性能对比图**: 多AI收益率实时对比 -- **动画效果**: 流畅的hover、过渡、加载动画 +### 🎯 统一风控系统 +- **仓位限制**:单资产限制(山寨币≤1.5x净值,BTC/ETH≤10x净值) +- **可配置杠杆**:根据资产类别和账户类型动态调整 1x 到 50x +- **保证金管理**:总使用率≤90%,AI 控制分配 +- **风险回报强制执行**:强制≥1:2 的止损止盈比 +- **防叠加保护**:防止同一资产/方向的重复仓位 -### 📝 完整决策记录 -- **思维链记录**: AI的完整推理过程(CoT) -- **历史表现**: 整体胜率、平均盈利、盈亏比 -- **最近交易**: 最近5笔交易详情(开仓价→平仓价→盈亏%) -- **币种统计**: 各币种表现(胜率、平均盈亏) -- **JSON日志**: 每次决策完整记录,便于复盘分析 +### ⚡ 低延迟执行引擎 +- **多交易所 API 集成**:Binance Futures、Hyperliquid DEX、Aster DEX +- **自动精度处理**:每个交易所智能订单大小和价格格式化 +- **优先级执行**:先平仓现有持仓,再开新仓 +- **滑点控制**:执行前验证,实时精度检查 + +### 🎨 专业监控界面 +- **币安风格仪表板**:专业暗色主题,实时更新 +- **净值曲线**:历史账户价值追踪(USD/百分比切换) +- **性能图表**:多智能体 ROI 对比,实时更新 +- **完整决策日志**:每笔交易的完整思维链(CoT)推理 +- **5秒数据刷新**:实时账户、持仓和盈亏更新 + +--- + +## 🔮 路线图 - 通用市场扩展 + +我们经过验证的加密货币基础设施正在扩展到: + +- **📈 股票市场**:美股、A股、港股 +- **📊 期货市场**:商品期货、指数期货 +- **🎯 期权交易**:股票期权、加密期权 +- **💱 外汇市场**:主要货币对、交叉盘 + +**相同架构。相同智能体框架。所有市场。** --- @@ -1310,8 +1344,9 @@ MIT License - 详见 [LICENSE](LICENSE) 文件 ## 📬 联系方式 -- **Twitter/X**: [@Web3Tinkle](https://x.com/Web3Tinkle) +### 🐛 技术支持 - **GitHub Issues**: [提交Issue](https://github.com/tinkle-community/nofx/issues) +- **开发者社区**: [Telegram群组](https://t.me/nofx_dev_community) --- diff --git a/api/server.go b/api/server.go index 388184d5..c9efe780 100644 --- a/api/server.go +++ b/api/server.go @@ -235,9 +235,10 @@ type ExchangeConfig struct { type UpdateModelConfigRequest struct { Models map[string]struct { - Enabled bool `json:"enabled"` - APIKey string `json:"api_key"` - CustomAPIURL string `json:"custom_api_url"` + Enabled bool `json:"enabled"` + APIKey string `json:"api_key"` + CustomAPIURL string `json:"custom_api_url"` + CustomModelName string `json:"custom_model_name"` } `json:"models"` } @@ -612,16 +613,23 @@ func (s *Server) handleUpdateModelConfigs(c *gin.Context) { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } - + // 更新每个模型的配置 for modelID, modelData := range req.Models { - err := s.database.UpdateAIModel(userID, modelID, modelData.Enabled, modelData.APIKey, modelData.CustomAPIURL) + err := s.database.UpdateAIModel(userID, modelID, modelData.Enabled, modelData.APIKey, modelData.CustomAPIURL, modelData.CustomModelName) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("更新模型 %s 失败: %v", modelID, err)}) return } } - + + // 重新加载该用户的所有交易员,使新配置立即生效 + err := s.traderManager.LoadUserTraders(s.database, userID) + if err != nil { + log.Printf("⚠️ 重新加载用户交易员到内存失败: %v", err) + // 这里不返回错误,因为模型配置已经成功更新到数据库 + } + log.Printf("✓ AI模型配置已更新: %+v", req.Models) c.JSON(http.StatusOK, gin.H{"message": "模型配置已更新"}) } @@ -649,7 +657,7 @@ func (s *Server) handleUpdateExchangeConfigs(c *gin.Context) { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } - + // 更新每个交易所的配置 for exchangeID, exchangeData := range req.Exchanges { err := s.database.UpdateExchange(userID, exchangeID, exchangeData.Enabled, exchangeData.APIKey, exchangeData.SecretKey, exchangeData.Testnet, exchangeData.HyperliquidWalletAddr, exchangeData.AsterUser, exchangeData.AsterSigner, exchangeData.AsterPrivateKey) @@ -658,7 +666,14 @@ func (s *Server) handleUpdateExchangeConfigs(c *gin.Context) { return } } - + + // 重新加载该用户的所有交易员,使新配置立即生效 + err := s.traderManager.LoadUserTraders(s.database, userID) + if err != nil { + log.Printf("⚠️ 重新加载用户交易员到内存失败: %v", err) + // 这里不返回错误,因为交易所配置已经成功更新到数据库 + } + log.Printf("✓ 交易所配置已更新: %+v", req.Exchanges) c.JSON(http.StatusOK, gin.H{"message": "交易所配置已更新"}) } @@ -725,12 +740,21 @@ func (s *Server) handleTraderList(c *gin.Context) { } } + // AIModelID 应该已经是 provider(如 "deepseek"),直接使用 + // 如果是旧数据格式(如 "admin_deepseek"),提取 provider 部分 + aiModelID := trader.AIModelID + // 兼容旧数据:如果包含下划线,提取最后一部分作为 provider + if strings.Contains(aiModelID, "_") { + parts := strings.Split(aiModelID, "_") + aiModelID = parts[len(parts)-1] + } + result = append(result, map[string]interface{}{ - "trader_id": trader.ID, - "trader_name": trader.Name, - "ai_model": trader.AIModelID, - "exchange_id": trader.ExchangeID, - "is_running": isRunning, + "trader_id": trader.ID, + "trader_name": trader.Name, + "ai_model": aiModelID, + "exchange_id": trader.ExchangeID, + "is_running": isRunning, "initial_balance": trader.InitialBalance, }) } @@ -763,21 +787,30 @@ func (s *Server) handleGetTraderConfig(c *gin.Context) { } } + // AIModelID 应该已经是 provider(如 "deepseek"),直接使用 + // 如果是旧数据格式(如 "admin_deepseek"),提取 provider 部分 + aiModelID := traderConfig.AIModelID + // 兼容旧数据:如果包含下划线,提取最后一部分作为 provider + if strings.Contains(aiModelID, "_") { + parts := strings.Split(aiModelID, "_") + aiModelID = parts[len(parts)-1] + } + result := map[string]interface{}{ - "trader_id": traderConfig.ID, - "trader_name": traderConfig.Name, - "ai_model": traderConfig.AIModelID, - "exchange_id": traderConfig.ExchangeID, - "initial_balance": traderConfig.InitialBalance, - "btc_eth_leverage": traderConfig.BTCETHLeverage, - "altcoin_leverage": traderConfig.AltcoinLeverage, - "trading_symbols": traderConfig.TradingSymbols, - "custom_prompt": traderConfig.CustomPrompt, + "trader_id": traderConfig.ID, + "trader_name": traderConfig.Name, + "ai_model": aiModelID, + "exchange_id": traderConfig.ExchangeID, + "initial_balance": traderConfig.InitialBalance, + "btc_eth_leverage": traderConfig.BTCETHLeverage, + "altcoin_leverage": traderConfig.AltcoinLeverage, + "trading_symbols": traderConfig.TradingSymbols, + "custom_prompt": traderConfig.CustomPrompt, "override_base_prompt": traderConfig.OverrideBasePrompt, - "is_cross_margin": traderConfig.IsCrossMargin, - "use_coin_pool": traderConfig.UseCoinPool, - "use_oi_top": traderConfig.UseOITop, - "is_running": isRunning, + "is_cross_margin": traderConfig.IsCrossMargin, + "use_coin_pool": traderConfig.UseCoinPool, + "use_oi_top": traderConfig.UseOITop, + "is_running": isRunning, } c.JSON(http.StatusOK, result) diff --git a/config/database.go b/config/database.go index 9e788665..0ad3bf16 100644 --- a/config/database.go +++ b/config/database.go @@ -185,6 +185,7 @@ func (d *Database) createTables() error { `ALTER TABLE traders ADD COLUMN use_coin_pool BOOLEAN DEFAULT 0`, // 是否使用COIN POOL信号源 `ALTER TABLE traders ADD COLUMN use_oi_top BOOLEAN DEFAULT 0`, // 是否使用OI TOP信号源 `ALTER TABLE ai_models ADD COLUMN custom_api_url TEXT DEFAULT ''`, // 自定义API地址 + `ALTER TABLE ai_models ADD COLUMN custom_model_name TEXT DEFAULT ''`, // 自定义模型名称 } for _, query := range alterQueries { @@ -362,15 +363,16 @@ type User struct { // AIModelConfig AI模型配置 type AIModelConfig struct { - ID string `json:"id"` - UserID string `json:"user_id"` - Name string `json:"name"` - Provider string `json:"provider"` - Enabled bool `json:"enabled"` - APIKey string `json:"apiKey"` - CustomAPIURL string `json:"customApiUrl"` - CreatedAt time.Time `json:"created_at"` - UpdatedAt time.Time `json:"updated_at"` + ID string `json:"id"` + UserID string `json:"user_id"` + Name string `json:"name"` + Provider string `json:"provider"` + Enabled bool `json:"enabled"` + APIKey string `json:"apiKey"` + CustomAPIURL string `json:"customApiUrl"` + CustomModelName string `json:"customModelName"` + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` } // ExchangeConfig 交易所配置 @@ -530,7 +532,10 @@ func (d *Database) UpdateUserOTPVerified(userID string, verified bool) error { // GetAIModels 获取用户的AI模型配置 func (d *Database) GetAIModels(userID string) ([]*AIModelConfig, error) { rows, err := d.db.Query(` - SELECT id, user_id, name, provider, enabled, api_key, COALESCE(custom_api_url, '') as custom_api_url, created_at, updated_at + SELECT id, user_id, name, provider, enabled, api_key, + COALESCE(custom_api_url, '') as custom_api_url, + COALESCE(custom_model_name, '') as custom_model_name, + created_at, updated_at FROM ai_models WHERE user_id = ? ORDER BY id `, userID) if err != nil { @@ -543,8 +548,8 @@ func (d *Database) GetAIModels(userID string) ([]*AIModelConfig, error) { for rows.Next() { var model AIModelConfig err := rows.Scan( - &model.ID, &model.UserID, &model.Name, &model.Provider, - &model.Enabled, &model.APIKey, &model.CustomAPIURL, + &model.ID, &model.UserID, &model.Name, &model.Provider, + &model.Enabled, &model.APIKey, &model.CustomAPIURL, &model.CustomModelName, &model.CreatedAt, &model.UpdatedAt, ) if err != nil { @@ -557,52 +562,50 @@ func (d *Database) GetAIModels(userID string) ([]*AIModelConfig, error) { } // UpdateAIModel 更新AI模型配置,如果不存在则创建用户特定配置 -func (d *Database) UpdateAIModel(userID, id string, enabled bool, apiKey, customAPIURL string) error { - // 首先尝试更新现有的用户配置 - result, err := d.db.Exec(` - UPDATE ai_models SET enabled = ?, api_key = ?, custom_api_url = ? WHERE id = ? AND user_id = ? - `, enabled, apiKey, customAPIURL, id, userID) - if err != nil { - return err - } - - // 检查是否有行被更新 - rowsAffected, err := result.RowsAffected() - if err != nil { - return err - } - - // 如果没有行被更新,说明用户没有这个模型的配置,需要创建 - if rowsAffected == 0 { - // 获取模型的基本信息 - var name, provider string - err = d.db.QueryRow(` - SELECT name, provider FROM ai_models WHERE provider = ? LIMIT 1 - `, id).Scan(&name, &provider) - if err != nil { - // 如果找不到基本信息,使用默认值 - if id == "deepseek" { - name = "DeepSeek AI" - provider = "deepseek" - } else if id == "qwen" { - name = "Qwen AI" - provider = "qwen" - } else { - name = id + " AI" - provider = id - } - } - - // 创建用户特定的配置 - userModelID := fmt.Sprintf("%s_%s", userID, id) +func (d *Database) UpdateAIModel(userID, id string, enabled bool, apiKey, customAPIURL, customModelName string) error { + // id 参数实际上是 provider(如 "deepseek", "qwen") + provider := id + + // 先查找用户是否已有这个 provider 的配置 + var existingID string + err := d.db.QueryRow(` + SELECT id FROM ai_models WHERE user_id = ? AND provider = ? LIMIT 1 + `, userID, provider).Scan(&existingID) + + if err == nil { + // 找到了现有配置,更新它 _, err = d.db.Exec(` - INSERT INTO ai_models (id, user_id, name, provider, enabled, api_key, custom_api_url, created_at, updated_at) - VALUES (?, ?, ?, ?, ?, ?, ?, datetime('now'), datetime('now')) - `, userModelID, userID, name, provider, enabled, apiKey, customAPIURL) + UPDATE ai_models SET enabled = ?, api_key = ?, custom_api_url = ?, custom_model_name = ?, updated_at = datetime('now') + WHERE id = ? AND user_id = ? + `, enabled, apiKey, customAPIURL, customModelName, existingID, userID) return err } - - return nil + + // 没有找到现有配置,创建新的 + // 获取模型的基本信息 + var name string + err = d.db.QueryRow(` + SELECT name FROM ai_models WHERE provider = ? LIMIT 1 + `, provider).Scan(&name) + if err != nil { + // 如果找不到基本信息,使用默认值 + if provider == "deepseek" { + name = "DeepSeek AI" + } else if provider == "qwen" { + name = "Qwen AI" + } else { + name = provider + " AI" + } + } + + // 创建用户特定的配置 + userModelID := fmt.Sprintf("%s_%s", userID, provider) + _, err = d.db.Exec(` + INSERT INTO ai_models (id, user_id, name, provider, enabled, api_key, custom_api_url, custom_model_name, created_at, updated_at) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, datetime('now'), datetime('now')) + `, userModelID, userID, name, provider, enabled, apiKey, customAPIURL, customModelName) + + return err } // GetExchanges 获取用户的交易所配置 diff --git a/decision/engine.go b/decision/engine.go index 1e990670..4f1ae721 100644 --- a/decision/engine.go +++ b/decision/engine.go @@ -226,7 +226,7 @@ func buildSystemPromptWithCustom(accountEquity float64, btcEthLeverage, altcoinL sb.WriteString("# 📌 个性化交易策略\n\n") sb.WriteString(customPrompt) sb.WriteString("\n\n") - sb.WriteString("**注意**: 以上个性化策略是对基础规则的补充,不能违背基础风险控制原则。\n") + sb.WriteString("注意: 以上个性化策略是对基础规则的补充,不能违背基础风险控制原则。\n") return sb.String() } @@ -236,111 +236,116 @@ func buildSystemPrompt(accountEquity float64, btcEthLeverage, altcoinLeverage in var sb strings.Builder // === 核心使命 === - sb.WriteString("你是专业的加密货币交易AI,在币安合约市场进行自主交易。\n\n") - sb.WriteString("# 🎯 核心目标\n\n") - sb.WriteString("**最大化夏普比率(Sharpe Ratio)**\n\n") + sb.WriteString("你是专业的加密货币交易AI,在合约市场进行自主交易。\n\n") + sb.WriteString("# 核心目标\n\n") + sb.WriteString("最大化夏普比率(Sharpe Ratio)\n\n") sb.WriteString("夏普比率 = 平均收益 / 收益波动率\n\n") - sb.WriteString("**这意味着**:\n") - sb.WriteString("- ✅ 高质量交易(高胜率、大盈亏比)→ 提升夏普\n") - sb.WriteString("- ✅ 稳定收益、控制回撤 → 提升夏普\n") - sb.WriteString("- ✅ 耐心持仓、让利润奔跑 → 提升夏普\n") - sb.WriteString("- ❌ 频繁交易、小盈小亏 → 增加波动,严重降低夏普\n") - sb.WriteString("- ❌ 过度交易、手续费损耗 → 直接亏损\n") - sb.WriteString("- ❌ 过早平仓、频繁进出 → 错失大行情\n\n") - sb.WriteString("**关键认知**: 系统每3分钟扫描一次,但不意味着每次都要交易!\n") + sb.WriteString("这意味着:\n") + sb.WriteString("- 高质量交易(高胜率、大盈亏比)→ 提升夏普\n") + sb.WriteString("- 稳定收益、控制回撤 → 提升夏普\n") + sb.WriteString("- 耐心持仓、让利润奔跑 → 提升夏普\n") + sb.WriteString("- 频繁交易、小盈小亏 → 增加波动,严重降低夏普\n") + sb.WriteString("- 过度交易、手续费损耗 → 直接亏损\n") + sb.WriteString("- 过早平仓、频繁进出 → 错失大行情\n\n") + sb.WriteString("关键认知: 系统每3分钟扫描一次,但不意味着每次都要交易!\n") sb.WriteString("大多数时候应该是 `wait` 或 `hold`,只在极佳机会时才开仓。\n\n") // === 硬约束(风险控制)=== - sb.WriteString("# ⚖️ 硬约束(风险控制)\n\n") - sb.WriteString("1. **风险回报比**: 必须 ≥ 1:3(冒1%风险,赚3%+收益)\n") - sb.WriteString("2. **最多持仓**: 3个币种(质量>数量)\n") - sb.WriteString(fmt.Sprintf("3. **单币仓位**: 山寨%.0f-%.0f U(%dx杠杆) | BTC/ETH %.0f-%.0f U(%dx杠杆)\n", + sb.WriteString("# 硬约束(风险控制)\n\n") + sb.WriteString("1. 风险回报比: 必须 ≥ 1:3(冒1%风险,赚3%+收益)\n") + sb.WriteString("2. 最多持仓: 3个币种(质量>数量)\n") + sb.WriteString(fmt.Sprintf("3. 单币仓位: 山寨%.0f-%.0f U(%dx杠杆) | BTC/ETH %.0f-%.0f U(%dx杠杆)\n", accountEquity*0.8, accountEquity*1.5, altcoinLeverage, accountEquity*5, accountEquity*10, btcEthLeverage)) - sb.WriteString("4. **保证金**: 总使用率 ≤ 90%\n\n") + sb.WriteString("4. 保证金: 总使用率 ≤ 90%\n\n") - // === 做空激励 === - sb.WriteString("# 📉 做多做空平衡\n\n") - sb.WriteString("**重要**: 下跌趋势做空的利润 = 上涨趋势做多的利润\n\n") - sb.WriteString("- 上涨趋势 → 做多\n") - sb.WriteString("- 下跌趋势 → 做空\n") - sb.WriteString("- 震荡市场 → 观望\n\n") - sb.WriteString("**不要有做多偏见!做空是你的核心工具之一**\n\n") + // === 交易哲学 & 最佳实践 === + sb.WriteString("# 交易哲学 & 最佳实践\n\n") + sb.WriteString("## 核心原则:\n\n") + sb.WriteString("资金保全第一:保护资本比追求收益更重要\n\n") + sb.WriteString("纪律胜于情绪:执行你的退出方案,不随意移动止损或目标\n\n") + sb.WriteString("质量优于数量:少量高信念交易胜过大量低信念交易\n\n") + sb.WriteString("适应波动性:根据市场条件调整仓位\n\n") + sb.WriteString("尊重趋势:不要与强趋势作对\n\n") + sb.WriteString("## 常见误区避免:\n\n") + sb.WriteString("过度交易:频繁交易导致费用侵蚀利润\n\n") + sb.WriteString("复仇式交易:亏损后立即加码试图\"翻本\"\n\n") + sb.WriteString("分析瘫痪:过度等待完美信号,导致失机\n\n") + sb.WriteString("忽视相关性:BTC常引领山寨币,须优先观察BTC\n\n") + sb.WriteString("过度杠杆:放大收益同时放大亏损\n\n") // === 交易频率认知 === - sb.WriteString("# ⏱️ 交易频率认知\n\n") - sb.WriteString("**量化标准**:\n") + sb.WriteString("#交易频率认知\n\n") + sb.WriteString("量化标准:\n") sb.WriteString("- 优秀交易员:每天2-4笔 = 每小时0.1-0.2笔\n") sb.WriteString("- 过度交易:每小时>2笔 = 严重问题\n") sb.WriteString("- 最佳节奏:开仓后持有至少30-60分钟\n\n") - sb.WriteString("**自查**:\n") + sb.WriteString("自查:\n") sb.WriteString("如果你发现自己每个周期都在交易 → 说明标准太低\n") sb.WriteString("如果你发现持仓<30分钟就平仓 → 说明太急躁\n\n") // === 开仓信号强度 === - sb.WriteString("# 🎯 开仓标准(严格)\n\n") - sb.WriteString("只在**强信号**时开仓,不确定就观望。\n\n") - sb.WriteString("**你拥有的完整数据**:\n") - sb.WriteString("- 📊 **原始序列**:3分钟价格序列(MidPrices数组) + 4小时K线序列\n") - sb.WriteString("- 📈 **技术序列**:EMA20序列、MACD序列、RSI7序列、RSI14序列\n") - sb.WriteString("- 💰 **资金序列**:成交量序列、持仓量(OI)序列、资金费率\n") - sb.WriteString("- 🎯 **筛选标记**:AI500评分 / OI_Top排名(如果有标注)\n\n") - sb.WriteString("**分析方法**(完全由你自主决定):\n") + sb.WriteString("# 开仓标准(严格)\n\n") + sb.WriteString("只在强信号时开仓,不确定就观望。\n\n") + sb.WriteString("你拥有的完整数据:\n") + sb.WriteString("- 原始序列:3分钟价格序列(MidPrices数组) + 4小时K线序列\n") + sb.WriteString("- 技术序列:EMA20序列、MACD序列、RSI7序列、RSI14序列\n") + sb.WriteString("- 资金序列:成交量序列、持仓量(OI)序列、资金费率\n") + sb.WriteString("- 筛选标记:AI500评分 / OI_Top排名(如果有标注)\n\n") + sb.WriteString("分析方法(完全由你自主决定):\n") sb.WriteString("- 自由运用序列数据,你可以做但不限于趋势分析、形态识别、支撑阻力、技术阻力位、斐波那契、波动带计算\n") sb.WriteString("- 多维度交叉验证(价格+量+OI+指标+序列形态)\n") sb.WriteString("- 用你认为最有效的方法发现高确定性机会\n") sb.WriteString("- 综合信心度 ≥ 75 才开仓\n\n") - sb.WriteString("**避免低质量信号**:\n") + sb.WriteString("避免低质量信号:\n") sb.WriteString("- 单一维度(只看一个指标)\n") sb.WriteString("- 相互矛盾(涨但量萎缩)\n") sb.WriteString("- 横盘震荡\n") sb.WriteString("- 刚平仓不久(<15分钟)\n\n") // === 夏普比率自我进化 === - sb.WriteString("# 🧬 夏普比率自我进化\n\n") - sb.WriteString("每次你会收到**夏普比率**作为绩效反馈(周期级别):\n\n") - sb.WriteString("**夏普比率 < -0.5** (持续亏损):\n") - sb.WriteString(" → 🛑 停止交易,连续观望至少6个周期(18分钟)\n") - sb.WriteString(" → 🔍 深度反思:\n") +sb.WriteString("# 夏普比率自我进化\n\n") + sb.WriteString("每次你会收到夏普比率作为绩效反馈(周期级别):\n\n") + sb.WriteString("夏普比率 < -0.5 (持续亏损):\n") + sb.WriteString(" → 停止交易,连续观望至少6个周期(18分钟)\n") + sb.WriteString(" → 深度反思:\n") sb.WriteString(" • 交易频率过高?(每小时>2次就是过度)\n") sb.WriteString(" • 持仓时间过短?(<30分钟就是过早平仓)\n") sb.WriteString(" • 信号强度不足?(信心度<75)\n") - sb.WriteString(" • 是否在做空?(单边做多是错误的)\n\n") - sb.WriteString("**夏普比率 -0.5 ~ 0** (轻微亏损):\n") - sb.WriteString(" → ⚠️ 严格控制:只做信心度>80的交易\n") + sb.WriteString("夏普比率 -0.5 ~ 0 (轻微亏损):\n") + sb.WriteString(" → 严格控制:只做信心度>80的交易\n") sb.WriteString(" → 减少交易频率:每小时最多1笔新开仓\n") sb.WriteString(" → 耐心持仓:至少持有30分钟以上\n\n") - sb.WriteString("**夏普比率 0 ~ 0.7** (正收益):\n") - sb.WriteString(" → ✅ 维持当前策略\n\n") - sb.WriteString("**夏普比率 > 0.7** (优异表现):\n") - sb.WriteString(" → 🚀 可适度扩大仓位\n\n") - sb.WriteString("**关键**: 夏普比率是唯一指标,它会自然惩罚频繁交易和过度进出。\n\n") + sb.WriteString("夏普比率 0 ~ 0.7 (正收益):\n") + sb.WriteString(" → 维持当前策略\n\n") + sb.WriteString("夏普比率 > 0.7 (优异表现):\n") + sb.WriteString(" → 可适度扩大仓位\n\n") + sb.WriteString("关键: 夏普比率是唯一指标,它会自然惩罚频繁交易和过度进出。\n\n") // === 决策流程 === - sb.WriteString("# 📋 决策流程\n\n") - sb.WriteString("1. **分析夏普比率**: 当前策略是否有效?需要调整吗?\n") - sb.WriteString("2. **评估持仓**: 趋势是否改变?是否该止盈/止损?\n") - sb.WriteString("3. **寻找新机会**: 有强信号吗?多空机会?\n") - sb.WriteString("4. **输出决策**: 思维链分析 + JSON\n\n") + sb.WriteString("#决策流程\n\n") + sb.WriteString("1. 分析夏普比率: 当前策略是否有效?需要调整吗?\n") + sb.WriteString("2. 评估持仓: 趋势是否改变?是否该止盈/止损?\n") + sb.WriteString("3. 寻找新机会: 有强信号吗?多空机会?\n") + sb.WriteString("4. 输出决策: 思维链分析 + JSON\n\n") // === 输出格式 === - sb.WriteString("# 📤 输出格式\n\n") - sb.WriteString("**第一步: 思维链(纯文本)**\n") + sb.WriteString("#输出格式\n\n") + sb.WriteString("第一步: 思维链(纯文本)\n") sb.WriteString("简洁分析你的思考过程\n\n") - sb.WriteString("**第二步: JSON决策数组**\n\n") + sb.WriteString("第二步: JSON决策数组\n\n") sb.WriteString("```json\n[\n") sb.WriteString(fmt.Sprintf(" {\"symbol\": \"BTCUSDT\", \"action\": \"open_short\", \"leverage\": %d, \"position_size_usd\": %.0f, \"stop_loss\": 97000, \"take_profit\": 91000, \"confidence\": 85, \"risk_usd\": 300, \"reasoning\": \"下跌趋势+MACD死叉\"},\n", btcEthLeverage, accountEquity*5)) sb.WriteString(" {\"symbol\": \"ETHUSDT\", \"action\": \"close_long\", \"reasoning\": \"止盈离场\"}\n") sb.WriteString("]\n```\n\n") - sb.WriteString("**字段说明**:\n") + sb.WriteString("字段说明:\n") sb.WriteString("- `action`: open_long | open_short | close_long | close_short | hold | wait\n") sb.WriteString("- `confidence`: 0-100(开仓建议≥75)\n") sb.WriteString("- 开仓时必填: leverage, position_size_usd, stop_loss, take_profit, confidence, risk_usd, reasoning\n\n") // === 关键提醒 === sb.WriteString("---\n\n") - sb.WriteString("**记住**: \n") + sb.WriteString("记住: \n") sb.WriteString("- 目标是夏普比率,不是交易频率\n") - sb.WriteString("- 做空 = 做多,都是赚钱工具\n") sb.WriteString("- 宁可错过,不做低质量交易\n") sb.WriteString("- 风险回报比1:3是底线\n") @@ -352,18 +357,18 @@ func buildUserPrompt(ctx *Context) string { var sb strings.Builder // 系统状态 - sb.WriteString(fmt.Sprintf("**时间**: %s | **周期**: #%d | **运行**: %d分钟\n\n", + sb.WriteString(fmt.Sprintf("时间: %s | 周期: #%d | 运行: %d分钟\n\n", ctx.CurrentTime, ctx.CallCount, ctx.RuntimeMinutes)) // BTC 市场 if btcData, hasBTC := ctx.MarketDataMap["BTCUSDT"]; hasBTC { - sb.WriteString(fmt.Sprintf("**BTC**: %.2f (1h: %+.2f%%, 4h: %+.2f%%) | MACD: %.4f | RSI: %.2f\n\n", + sb.WriteString(fmt.Sprintf("BTC: %.2f (1h: %+.2f%%, 4h: %+.2f%%) | MACD: %.4f | RSI: %.2f\n\n", btcData.CurrentPrice, btcData.PriceChange1h, btcData.PriceChange4h, btcData.CurrentMACD, btcData.CurrentRSI7)) } // 账户 - sb.WriteString(fmt.Sprintf("**账户**: 净值%.2f | 余额%.2f (%.1f%%) | 盈亏%+.2f%% | 保证金%.1f%% | 持仓%d个\n\n", + sb.WriteString(fmt.Sprintf("账户: 净值%.2f | 余额%.2f (%.1f%%) | 盈亏%+.2f%% | 保证金%.1f%% | 持仓%d个\n\n", ctx.Account.TotalEquity, ctx.Account.AvailableBalance, (ctx.Account.AvailableBalance/ctx.Account.TotalEquity)*100, @@ -401,7 +406,7 @@ func buildUserPrompt(ctx *Context) string { } } } else { - sb.WriteString("**当前持仓**: 无\n\n") + sb.WriteString("当前持仓: 无\n\n") } // 候选币种(完整市场数据) diff --git a/manager/trader_manager.go b/manager/trader_manager.go index 014eefd1..e55b4acf 100644 --- a/manager/trader_manager.go +++ b/manager/trader_manager.go @@ -94,7 +94,9 @@ func (tm *TraderManager) LoadTradersFromDatabase(database *config.Database) erro var aiModelCfg *config.AIModelConfig for _, model := range aiModels { - if model.ID == traderCfg.AIModelID { + // 使用 provider 来匹配,因为 AIModelID 存储的是 provider(如 "deepseek") + // 而 model.ID 可能是 "admin_deepseek" + if model.Provider == traderCfg.AIModelID { aiModelCfg = model break } @@ -202,6 +204,8 @@ func (tm *TraderManager) addTraderFromDB(traderCfg *config.TraderRecord, aiModel UseQwen: aiModelCfg.Provider == "qwen", DeepSeekKey: "", QwenKey: "", + CustomAPIURL: aiModelCfg.CustomAPIURL, // 自定义API URL + CustomModelName: aiModelCfg.CustomModelName, // 自定义模型名称 ScanInterval: time.Duration(traderCfg.ScanIntervalMinutes) * time.Minute, InitialBalance: traderCfg.InitialBalance, BTCETHLeverage: traderCfg.BTCETHLeverage, @@ -306,6 +310,8 @@ func (tm *TraderManager) AddTraderFromDB(traderCfg *config.TraderRecord, aiModel UseQwen: aiModelCfg.Provider == "qwen", DeepSeekKey: "", QwenKey: "", + CustomAPIURL: aiModelCfg.CustomAPIURL, // 自定义API URL + CustomModelName: aiModelCfg.CustomModelName, // 自定义模型名称 ScanInterval: time.Duration(traderCfg.ScanIntervalMinutes) * time.Minute, InitialBalance: traderCfg.InitialBalance, BTCETHLeverage: traderCfg.BTCETHLeverage, @@ -616,7 +622,8 @@ func (tm *TraderManager) LoadUserTraders(database *config.Database, userID strin var aiModelCfg *config.AIModelConfig for _, model := range aiModels { - if model.ID == traderCfg.AIModelID { + // 使用 provider 来匹配,因为 AIModelID 存储的是 provider(如 "deepseek") + if model.Provider == traderCfg.AIModelID { aiModelCfg = model break } diff --git a/mcp/client.go b/mcp/client.go index eefddbe2..9191dfaf 100644 --- a/mcp/client.go +++ b/mcp/client.go @@ -5,6 +5,7 @@ import ( "encoding/json" "fmt" "io" + "log" "net/http" "strings" "time" @@ -23,7 +24,6 @@ const ( type Client struct { Provider Provider APIKey string - SecretKey string // 阿里云需要 BaseURL string Model string Timeout time.Duration @@ -41,20 +41,53 @@ func New() *Client { } // SetDeepSeekAPIKey 设置DeepSeek API密钥 -func (client *Client) SetDeepSeekAPIKey(apiKey string) { +// customURL 为空时使用默认URL,customModel 为空时使用默认模型 +func (client *Client) SetDeepSeekAPIKey(apiKey string, customURL string, customModel string) { client.Provider = ProviderDeepSeek client.APIKey = apiKey - client.BaseURL = "https://api.deepseek.com/v1" - client.Model = "deepseek-chat" + if customURL != "" { + client.BaseURL = customURL + log.Printf("🔧 [MCP] DeepSeek 使用自定义 BaseURL: %s", customURL) + } else { + client.BaseURL = "https://api.deepseek.com/v1" + log.Printf("🔧 [MCP] DeepSeek 使用默认 BaseURL: %s", client.BaseURL) + } + if customModel != "" { + client.Model = customModel + log.Printf("🔧 [MCP] DeepSeek 使用自定义 Model: %s", customModel) + } else { + client.Model = "deepseek-chat" + log.Printf("🔧 [MCP] DeepSeek 使用默认 Model: %s", client.Model) + } + // 打印 API Key 的前后各4位用于验证 + if len(apiKey) > 8 { + log.Printf("🔧 [MCP] DeepSeek API Key: %s...%s", apiKey[:4], apiKey[len(apiKey)-4:]) + } } // SetQwenAPIKey 设置阿里云Qwen API密钥 -func (client *Client) SetQwenAPIKey(apiKey, secretKey string) { +// customURL 为空时使用默认URL,customModel 为空时使用默认模型 +func (client *Client) SetQwenAPIKey(apiKey string, customURL string, customModel string) { client.Provider = ProviderQwen client.APIKey = apiKey - client.SecretKey = secretKey - client.BaseURL = "https://dashscope.aliyuncs.com/compatible-mode/v1" - client.Model = "qwen-plus" // 可选: qwen-turbo, qwen-plus, qwen-max + if customURL != "" { + client.BaseURL = customURL + log.Printf("🔧 [MCP] Qwen 使用自定义 BaseURL: %s", customURL) + } else { + client.BaseURL = "https://dashscope.aliyuncs.com/compatible-mode/v1" + log.Printf("🔧 [MCP] Qwen 使用默认 BaseURL: %s", client.BaseURL) + } + if customModel != "" { + client.Model = customModel + log.Printf("🔧 [MCP] Qwen 使用自定义 Model: %s", customModel) + } else { + client.Model = "qwen-plus" // 可选: qwen-turbo, qwen-plus, qwen-max + log.Printf("🔧 [MCP] Qwen 使用默认 Model: %s", client.Model) + } + // 打印 API Key 的前后各4位用于验证 + if len(apiKey) > 8 { + log.Printf("🔧 [MCP] Qwen API Key: %s...%s", apiKey[:4], apiKey[len(apiKey)-4:]) + } } // SetCustomAPI 设置自定义OpenAI兼容API @@ -125,6 +158,16 @@ func (client *Client) CallWithMessages(systemPrompt, userPrompt string) (string, // callOnce 单次调用AI API(内部使用) func (client *Client) callOnce(systemPrompt, userPrompt string) (string, error) { + // 打印当前 AI 配置 + log.Printf("📡 [MCP] AI 请求配置:") + log.Printf(" Provider: %s", client.Provider) + log.Printf(" BaseURL: %s", client.BaseURL) + log.Printf(" Model: %s", client.Model) + log.Printf(" UseFullURL: %v", client.UseFullURL) + if len(client.APIKey) > 8 { + log.Printf(" API Key: %s...%s", client.APIKey[:4], client.APIKey[len(client.APIKey)-4:]) + } + // 构建 messages 数组 messages := []map[string]string{} @@ -167,6 +210,8 @@ func (client *Client) callOnce(systemPrompt, userPrompt string) (string, error) // 默认行为:添加/chat/completions url = fmt.Sprintf("%s/chat/completions", client.BaseURL) } + log.Printf("📡 [MCP] 请求 URL: %s", url) + req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonData)) if err != nil { return "", fmt.Errorf("创建请求失败: %w", err) diff --git a/trader/auto_trader.go b/trader/auto_trader.go index 35472ab5..3c9a5e55 100644 --- a/trader/auto_trader.go +++ b/trader/auto_trader.go @@ -121,13 +121,21 @@ func NewAutoTrader(config AutoTraderConfig) (*AutoTrader, error) { mcpClient.SetCustomAPI(config.CustomAPIURL, config.CustomAPIKey, config.CustomModelName) log.Printf("🤖 [%s] 使用自定义AI API: %s (模型: %s)", config.Name, config.CustomAPIURL, config.CustomModelName) } else if config.UseQwen || config.AIModel == "qwen" { - // 使用Qwen - mcpClient.SetQwenAPIKey(config.QwenKey, "") - log.Printf("🤖 [%s] 使用阿里云Qwen AI", config.Name) + // 使用Qwen (支持自定义URL和Model) + mcpClient.SetQwenAPIKey(config.QwenKey, config.CustomAPIURL, config.CustomModelName) + if config.CustomAPIURL != "" || config.CustomModelName != "" { + log.Printf("🤖 [%s] 使用阿里云Qwen AI (自定义URL: %s, 模型: %s)", config.Name, config.CustomAPIURL, config.CustomModelName) + } else { + log.Printf("🤖 [%s] 使用阿里云Qwen AI", config.Name) + } } else { - // 默认使用DeepSeek - mcpClient.SetDeepSeekAPIKey(config.DeepSeekKey) - log.Printf("🤖 [%s] 使用DeepSeek AI", config.Name) + // 默认使用DeepSeek (支持自定义URL和Model) + mcpClient.SetDeepSeekAPIKey(config.DeepSeekKey, config.CustomAPIURL, config.CustomModelName) + if config.CustomAPIURL != "" || config.CustomModelName != "" { + log.Printf("🤖 [%s] 使用DeepSeek AI (自定义URL: %s, 模型: %s)", config.Name, config.CustomAPIURL, config.CustomModelName) + } else { + log.Printf("🤖 [%s] 使用DeepSeek AI", config.Name) + } } // 初始化币种池API diff --git a/web/src/App.tsx b/web/src/App.tsx index 228c87ef..c6092b5d 100644 --- a/web/src/App.tsx +++ b/web/src/App.tsx @@ -179,7 +179,7 @@ function App() { style={{ background: 'linear-gradient(135deg, #F0B90B 0%, #FCD535 100%)' }}> ⚡ -
加载中...
+{t('loading', language)}
); @@ -299,7 +299,7 @@ function App() { className="px-3 py-2 rounded text-sm font-semibold transition-all hover:scale-105" style={{ background: 'rgba(246, 70, 93, 0.1)', color: '#F6465D', border: '1px solid rgba(246, 70, 93, 0.2)' }} > - 退出 + {t('logout', language)} )} diff --git a/web/src/components/AITradersPage.tsx b/web/src/components/AITradersPage.tsx index ea0b2d2a..51511c90 100644 --- a/web/src/components/AITradersPage.tsx +++ b/web/src/components/AITradersPage.tsx @@ -3,7 +3,7 @@ import useSWR from 'swr'; import { api } from '../lib/api'; import type { TraderInfo, CreateTraderRequest, AIModel, Exchange } from '../types'; import { useLanguage } from '../contexts/LanguageContext'; -import { t, Language } from '../i18n/translations'; +import { t, type Language } from '../i18n/translations'; import { getExchangeIcon } from './ExchangeIcons'; import { getModelIcon } from './ModelIcons'; import { TraderConfigModal } from './TraderConfigModal'; @@ -134,25 +134,25 @@ export function AITradersPage({ onTraderSelect }: AITradersPageProps) { const handleCreateTrader = async (data: CreateTraderRequest) => { try { - const model = allModels?.find(m => m.id === data.ai_model_id); + const model = allModels?.find(m => m.provider === data.ai_model_id); const exchange = allExchanges?.find(e => e.id === data.exchange_id); - + if (!model?.enabled) { alert(t('modelNotConfigured', language)); return; } - + if (!exchange?.enabled) { alert(t('exchangeNotConfigured', language)); return; } - + await api.createTrader(data); setShowCreateModal(false); mutateTraders(); } catch (error) { console.error('Failed to create trader:', error); - alert('创建交易员失败'); + alert(t('createTraderFailed', language)); } }; @@ -163,24 +163,24 @@ export function AITradersPage({ onTraderSelect }: AITradersPageProps) { setShowEditModal(true); } catch (error) { console.error('Failed to fetch trader config:', error); - alert('获取交易员配置失败'); + alert(t('getTraderConfigFailed', language)); } }; const handleSaveEditTrader = async (data: CreateTraderRequest) => { if (!editingTrader) return; - + try { - const model = enabledModels?.find(m => m.id === data.ai_model_id); + const model = enabledModels?.find(m => m.provider === data.ai_model_id); const exchange = enabledExchanges?.find(e => e.id === data.exchange_id); - + if (!model) { - alert('AI模型配置不存在或未启用'); + alert(t('modelConfigNotExist', language)); return; } - + if (!exchange) { - alert('交易所配置不存在或未启用'); + alert(t('exchangeConfigNotExist', language)); return; } @@ -205,19 +205,19 @@ export function AITradersPage({ onTraderSelect }: AITradersPageProps) { mutateTraders(); } catch (error) { console.error('Failed to update trader:', error); - alert('更新交易员失败'); + alert(t('updateTraderFailed', language)); } }; const handleDeleteTrader = async (traderId: string) => { if (!confirm(t('confirmDeleteTrader', language))) return; - + try { await api.deleteTrader(traderId); mutateTraders(); } catch (error) { console.error('Failed to delete trader:', error); - alert('删除交易员失败'); + alert(t('deleteTraderFailed', language)); } }; @@ -231,7 +231,7 @@ export function AITradersPage({ onTraderSelect }: AITradersPageProps) { mutateTraders(); } catch (error) { console.error('Failed to toggle trader:', error); - alert('操作失败'); + alert(t('operationFailed', language)); } }; @@ -250,88 +250,91 @@ export function AITradersPage({ onTraderSelect }: AITradersPageProps) { }; const handleDeleteModelConfig = async (modelId: string) => { - if (!confirm('确定要删除此AI模型配置吗?')) return; - + if (!confirm(t('confirmDeleteModel', language))) return; + try { - const updatedModels = allModels?.map(m => - m.id === modelId ? { ...m, apiKey: '', enabled: false } : m + const updatedModels = allModels?.map(m => + m.id === modelId ? { ...m, apiKey: '', customApiUrl: '', customModelName: '', enabled: false } : m ) || []; - + const request = { models: Object.fromEntries( updatedModels.map(model => [ - model.id, + model.provider, // 使用 provider 而不是 id { enabled: model.enabled, - api_key: model.apiKey || '' + api_key: model.apiKey || '', + custom_api_url: model.customApiUrl || '', + custom_model_name: model.customModelName || '' } ]) ) }; - + await api.updateModelConfigs(request); setAllModels(updatedModels); setShowModelModal(false); setEditingModel(null); } catch (error) { console.error('Failed to delete model config:', error); - alert('删除配置失败'); + alert(t('deleteConfigFailed', language)); } }; - const handleSaveModelConfig = async (modelId: string, apiKey: string, customApiUrl?: string) => { + const handleSaveModelConfig = async (modelId: string, apiKey: string, customApiUrl?: string, customModelName?: string) => { try { // 找到要配置的模型(从supportedModels中) const modelToUpdate = supportedModels?.find(m => m.id === modelId); if (!modelToUpdate) { - alert('模型不存在'); + alert(t('modelNotExist', language)); return; } // 创建或更新用户的模型配置 const existingModel = allModels?.find(m => m.id === modelId); let updatedModels; - + if (existingModel) { // 更新现有配置 - updatedModels = allModels?.map(m => - m.id === modelId ? { ...m, apiKey, customApiUrl: customApiUrl || '', enabled: true } : m + updatedModels = allModels?.map(m => + m.id === modelId ? { ...m, apiKey, customApiUrl: customApiUrl || '', customModelName: customModelName || '', enabled: true } : m ) || []; } else { // 添加新配置 - const newModel = { ...modelToUpdate, apiKey, customApiUrl: customApiUrl || '', enabled: true }; + const newModel = { ...modelToUpdate, apiKey, customApiUrl: customApiUrl || '', customModelName: customModelName || '', enabled: true }; updatedModels = [...(allModels || []), newModel]; } - + const request = { models: Object.fromEntries( updatedModels.map(model => [ - model.id, + model.provider, // 使用 provider 而不是 id { enabled: model.enabled, api_key: model.apiKey || '', - custom_api_url: model.customApiUrl || '' + custom_api_url: model.customApiUrl || '', + custom_model_name: model.customModelName || '' } ]) ) }; - + await api.updateModelConfigs(request); - + // 重新获取用户配置以确保数据同步 const refreshedModels = await api.getModelConfigs(); setAllModels(refreshedModels); - + setShowModelModal(false); setEditingModel(null); } catch (error) { console.error('Failed to save model config:', error); - alert('保存配置失败'); + alert(t('saveConfigFailed', language)); } }; const handleDeleteExchangeConfig = async (exchangeId: string) => { - if (!confirm('确定要删除此交易所配置吗?')) return; + if (!confirm(t('confirmDeleteExchange', language))) return; try { const updatedExchanges = allExchanges?.map(e => @@ -358,7 +361,7 @@ export function AITradersPage({ onTraderSelect }: AITradersPageProps) { setEditingExchange(null); } catch (error) { console.error('Failed to delete exchange config:', error); - alert('删除交易所配置失败'); + alert(t('deleteExchangeConfigFailed', language)); } }; @@ -367,7 +370,7 @@ export function AITradersPage({ onTraderSelect }: AITradersPageProps) { // 找到要配置的交易所(从supportedExchanges中) const exchangeToUpdate = supportedExchanges?.find(e => e.id === exchangeId); if (!exchangeToUpdate) { - alert('交易所不存在'); + alert(t('exchangeNotExist', language)); return; } @@ -434,7 +437,7 @@ export function AITradersPage({ onTraderSelect }: AITradersPageProps) { setEditingExchange(null); } catch (error) { console.error('Failed to save exchange config:', error); - alert('保存交易所配置失败'); + alert(t('saveConfigFailed', language)); } }; @@ -455,7 +458,7 @@ export function AITradersPage({ onTraderSelect }: AITradersPageProps) { setShowSignalSourceModal(false); } catch (error) { console.error('Failed to save signal source:', error); - alert('保存信号源配置失败'); + alert(t('saveSignalSourceFailed', language)); } }; @@ -516,13 +519,13 @@ export function AITradersPage({ onTraderSelect }: AITradersPageProps) { )} @@ -814,6 +818,7 @@ export function AITradersPage({ onTraderSelect }: AITradersPageProps) { oiTopUrl={userSignalSource.oiTopUrl} onSave={handleSaveSignalSource} onClose={() => setShowSignalSourceModal(false)} + language={language} /> )} @@ -825,12 +830,14 @@ function SignalSourceModal({ coinPoolUrl, oiTopUrl, onSave, - onClose + onClose, + language }: { coinPoolUrl: string; oiTopUrl: string; onSave: (coinPoolUrl: string, oiTopUrl: string) => void; onClose: () => void; + language: Language; }) { const [coinPool, setCoinPool] = useState(coinPoolUrl || ''); const [oiTop, setOiTop] = useState(oiTopUrl || ''); @@ -844,7 +851,7 @@ function SignalSourceModal({