mirror of
https://github.com/NoFxAiOS/nofx.git
synced 2025-12-06 13:54:41 +08:00
dev
75 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
1ea1234c64 |
Feature/custom strategy (#1172)
* feat: add Strategy Studio with multi-timeframe support - Add Strategy Studio page with three-column layout for strategy management - Support multi-timeframe K-line data selection (5m, 15m, 1h, 4h, etc.) - Add GetWithTimeframes() function in market package for fetching multiple timeframes - Add TimeframeSeriesData struct for storing per-timeframe technical indicators - Update formatMarketData() to display all selected timeframes in AI prompt - Add strategy API endpoints for CRUD operations and test run - Integrate real AI test runs with configured AI models - Support custom AI500 and OI Top API URLs from strategy config * docs: add Strategy Studio screenshot to README files * fix: correct strategy-studio.png filename case in README * refactor: remove legacy signal source config and simplify trader creation - Remove signal source configuration from traders page (now handled by strategy) - Remove advanced options (legacy config) from TraderConfigModal - Rename default strategy to "默认山寨策略" with AI500 coin pool URL - Delete SignalSourceModal and SignalSourceWarning components - Clean up related stores, hooks, and page components |
||
|
|
495209a69b |
Refactor/trading actions (#1169)
* refactor: 简化交易动作,移除 update_stop_loss/update_take_profit/partial_close - 移除 Decision 结构体中的 NewStopLoss, NewTakeProfit, ClosePercentage 字段 - 删除 executeUpdateStopLossWithRecord, executeUpdateTakeProfitWithRecord, executePartialCloseWithRecord 函数 - 简化 logger 中的 partial_close 聚合逻辑 - 更新 AI prompt 和验证逻辑,只保留 6 个核心动作 - 清理相关测试代码 保留的交易动作: open_long, open_short, close_long, close_short, hold, wait * refactor: 移除 AI学习与反思 模块 - 删除前端 AILearning.tsx 组件和相关引用 - 删除后端 /performance API 接口 - 删除 logger 中 AnalyzePerformance、calculateSharpeRatio 等函数 - 删除 PerformanceAnalysis、TradeOutcome、SymbolPerformance 等结构体 - 删除 Context 中的 Performance 字段 - 移除 AI prompt 中夏普比率自我进化相关内容 - 清理 i18n 翻译文件中的相关条目 该模块基于磁盘存储计算,经常出错,做减法移除 * refactor: 将数据库操作统一迁移到 store 包 - 新增 store/ 包,统一管理所有数据库操作 - store.go: 主 Store 结构,懒加载各子模块 - user.go, ai_model.go, exchange.go, trader.go 等子模块 - 支持加密/解密函数注入 (SetCryptoFuncs) - 更新 main.go 使用 store.New() 替代 config.NewDatabase() - 更新 api/server.go 使用 *store.Store 替代 *config.Database - 更新 manager/trader_manager.go: - 新增 LoadTradersFromStore, LoadUserTradersFromStore 方法 - 删除旧版 LoadUserTraders, LoadTraderByID, loadSingleTrader 等方法 - 移除 nofx/config 依赖 - 删除 config/database.go 和 config/database_test.go - 更新 api/server_test.go 使用 store.Trader 类型 - 清理 logger/ 包中未使用的 telegram 相关代码 * refactor: unify encryption key management via .env - Remove redundant EncryptionManager and SecureStorage - Simplify CryptoService to load keys from environment variables only - RSA_PRIVATE_KEY: RSA private key for client-server encryption - DATA_ENCRYPTION_KEY: AES-256 key for database encryption - JWT_SECRET: JWT signing key for authentication - Update start.sh to auto-generate missing keys on first run - Remove secrets/ directory and file-based key storage - Delete obsolete encryption setup scripts - Update .env.example with all required keys * refactor: unify logger usage across mcp package - Add MCPLogger adapter in logger package to implement mcp.Logger interface - Update mcp/config.go to use global logger by default - Remove redundant defaultLogger from mcp/logger.go - Keep noopLogger for testing purposes * chore: remove leftover test RSA key file * chore: remove unused bootstrap package * refactor: unify logging to use logger package instead of fmt/log - Replace all fmt.Print/log.Print calls with logger package - Add auto-initialization in logger package init() for test compatibility - Update main.go to initialize logger at startup - Migrate all packages: api, backtest, config, decision, manager, market, store, trader * refactor: rename database file from config.db to data.db - Update main.go, start.sh, docker-compose.yml - Update migration script and documentation - Update .gitignore and translations * fix: add RSA_PRIVATE_KEY to docker-compose environment * fix: add registration_enabled to /api/config response * fix: Fix navigation between login and register pages Use window.location.href instead of react-router's navigate() to fix the issue where URL changes but the page doesn't reload due to App.tsx using custom route state management. * fix: Switch SQLite from WAL to DELETE mode for Docker compatibility WAL mode causes data sync issues with Docker bind mounts on macOS due to incompatible file locking mechanisms between the container and host. DELETE mode (traditional journaling) ensures data is written directly to the main database file. * refactor: Remove default user from database initialization The default user was a legacy placeholder that is no longer needed now that proper user registration is in place. * feat: Add order tracking system with centralized status sync - Add trader_orders table for tracking all order lifecycle - Implement GetOrderStatus interface for all exchanges (Binance, Bybit, Hyperliquid, Aster, Lighter) - Create OrderSyncManager for centralized order status polling - Add trading statistics (Sharpe ratio, win rate, profit factor) to AI context - Include recent completed orders in AI decision input - Remove per-order goroutine polling in favor of global sync manager * feat: Add TradingView K-line chart to dashboard - Create TradingViewChart component with exchange/symbol selectors - Support Binance, Bybit, OKX, Coinbase, Kraken, KuCoin exchanges - Add popular symbols quick selection - Support multiple timeframes (1m to 1W) - Add fullscreen mode - Integrate with Dashboard page below equity chart - Add i18n translations for zh/en * refactor: Replace separate charts with tabbed ChartTabs component - Create ChartTabs component with tab switching between equity curve and K-line - Add embedded mode support for EquityChart and TradingViewChart - User can now switch between account equity and market chart in same area * fix: Use ChartTabs in App.tsx and fix embedded mode in EquityChart - Replace EquityChart with ChartTabs in App.tsx (the actual dashboard renderer) - Fix EquityChart embedded mode for error and empty data states - Rename interval state to timeInterval to avoid shadowing window.setInterval - Add debug logging to ChartTabs component * feat: Add position tracking system for accurate trade history - Add trader_positions table to track complete open/close trades - Add PositionSyncManager to detect manual closes via polling - Record position on open, update on close with PnL calculation - Use positions table for trading stats and recent trades (replacing orders table) - Fix TradingView chart symbol format (add .P suffix for futures) - Fix DecisionCard wait/hold action color (gray instead of red) - Auto-append USDT suffix for custom symbol input * update --------- |
||
|
|
4557f2e657 |
Revert "feat: 添加 OKX 交易所支持 (#1150)"
This reverts commit
|
||
|
|
174f59b907 |
feat: 添加 OKX 交易所支持 (#1150)
* feat: 添加 OKX 交易所支持(USDT Perpetual Swap) ## 新增功能 - 實現完整的 OKX API v5 REST 客戶端(純 Go 標準庫,無外部依賴) - 支持 USDT 永續合約交易(BTC-USDT-SWAP 等) - 實現 Trader 接口的 13 個核心方法 ## 技術細節 ### trader/okx_trader.go (NEW) - HMAC-SHA256 簽名機制(完全符合 OKX API v5 規範) - 餘額和持倉緩存(15秒,參考 Binance 實現) - 支持 Demo Trading(testnet 模式) - Symbol 格式轉換(BTCUSDT ↔ BTC-USDT-SWAP) - 全倉模式(Cross Margin)支持 - 自動槓桿設置 ### 實現的接口方法: - ✅ GetBalance() - 獲取賬戶餘額 - ✅ GetPositions() - 獲取所有持倉 - ✅ OpenLong() / OpenShort() - 開倉 - ✅ CloseLong() / CloseShort() - 平倉 - ✅ SetLeverage() - 設置槓桿 - ✅ SetMarginMode() - 設置保證金模式 - ✅ GetMarketPrice() - 獲取市場價格 - ✅ FormatQuantity() - 格式化數量 - ⚠️ 止盈止損功能標記為 TODO(非核心交易功能) ### config/database.go (MODIFIED) - 添加 "okx" 到預設交易所列表 - 新增 okx_passphrase 字段(OKX 需要 3 個認證參數) - 更新 ExchangeConfig 結構 - 添加數據庫遷移語句(ALTER TABLE) ### api/server.go (MODIFIED) - 在 handleCreateTrader() 添加 OKX 初始化邏輯 - switch case "okx" 分支 ## 代碼品質 - 代碼行數:~450 行 - 外部依賴:0 個 - 編譯狀態:✅ 通過 - 測試覆蓋:待實現(下一步) ## 待完成事項 - [ ] 撰寫單元測試(目標 >80% 覆蓋率) - [ ] 完善數據庫查詢邏輯(GetExchanges 添加 OKX passphrase 掃描) - [ ] 實現止盈止損功能(可選) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * refactor: 完善 OKX passphrase 數據庫和 API 支持 - config/database.go: • GetExchanges() 添加 okx_passphrase 查詢和解密 • UpdateExchange() 函數簽名添加 okxPassphrase 參數 • UpdateExchange() UPDATE 邏輯添加 okx_passphrase SET 子句 • UpdateExchange() INSERT 添加 okx_passphrase 加密和列 - api/server.go: • UpdateExchangeConfigRequest 添加 OKXPassphrase 字段 • UpdateExchange 調用添加 OKXPassphrase 參數 - api/utils.go: • SanitizeExchangeConfigForLog 添加 OKXPassphrase 脫敏 ✅ 編譯測試通過,OKX 完整功能支持完成 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * test: 添加 OKX Trader 完整單元測試套件 📊 測試覆蓋率:92.6% (遠超 80% 目標) ✅ 完成的測試: - 接口兼容性測試 - NewOKXTrader 構造函數測試(5個場景) - 符號格式轉換測試(5個場景) - HMAC-SHA256 簽名一致性測試 - GetBalance 測試(含字段驗證) - GetPositions 測試(含標準化數據驗證) - GetMarketPrice 測試(3個場景) - FormatQuantity 測試(5個場景) - SetLeverage/SetMarginMode 測試 - OpenLong/OpenShort 測試 - CloseLong/CloseShort 測試 - 緩存機制測試 - 錯誤處理測試(API錯誤、網絡錯誤、JSON錯誤) 🔧 測試套件架構: - OKXTraderTestSuite 繼承 TraderTestSuite - Mock HTTP 服務器模擬 OKX API v5 響應 - 完整覆蓋所有公開方法 - 包含邊界條件和錯誤場景測試 📈 方法覆蓋率明細: - request: 90.0% - GetBalance: 97.0% - GetPositions: 83.3% - formatSymbol, OpenLong, OpenShort, CloseLong, CloseShort: 100% - placeOrder, SetMarginMode, FormatQuantity, clearCache: 100% - Cancel* 方法系列: 100% - SetLeverage: 81.8% - GetMarketPrice: 85.7% 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: the-dev-z <the-dev-z@users.noreply.github.com> Co-authored-by: Claude <noreply@anthropic.com> |
||
|
|
adf2d54b85 | fix(bybit): complete Bybit integration by adding API layer support (#1149) | ||
|
|
b71272d48b |
fix: resolve multiple bugs preventing trader creation (#1138)
* fix: resolve multiple bugs preventing trader creation Bug fixes: 1. Fix time.Time scanning error - SQLite stores datetime as TEXT, now parsing manually 2. Fix foreign key mismatch - traders table referenced exchanges(id) but exchanges uses composite primary key (id, user_id) 3. Add missing backtestManager field to Server struct 4. Add missing Shutdown method to Server struct 5. Fix NewFuturesTrader call - pass userId parameter 6. Fix UpdateExchange call - pass all required parameters 7. Add migrateTradersTable() to fix existing databases These issues prevented creating new traders with 500 errors. * fix(api): fix balance extraction field name mismatch Binance API returns 'availableBalance' (camelCase) but code was looking for 'available_balance' (snake_case). Now supports both formats. Also added 'totalWalletBalance' as fallback for total balance extraction. * fix(frontend): add missing ConfirmDialogProvider to App The delete trader button required ConfirmDialogProvider to be wrapped around the App component for the confirmation dialog to work. --------- Co-authored-by: NOFX Trader <nofx@local.dev> |
||
|
|
7eebb4e218 | Dev backtest (#1134) | ||
|
|
8dffff60a2 |
feat(lighter): 完整集成 LIGHTER DEX - SDK + 前端配置 UI (#1085)
* feat(trader): add LIGHTER DEX integration (initial implementation) Add pure Go implementation of LIGHTER DEX trader following NOFX architecture Features: - ✅ Account management with Ethereum wallet authentication - ✅ Order operations: market/limit orders, cancel, query - ✅ Position & balance queries - ✅ Zero-fee trading support (Standard accounts) - ✅ Up to 50x leverage for BTC/ETH Implementation: - Pure Go (no CGO dependencies) for easy deployment - Based on hyperliquid_trader.go architecture - Uses Ethereum ECDSA signatures (like Hyperliquid) - API base URL: https://mainnet.zklighter.elliot.ai Files: - lighter_trader.go: Core trader structure & auth - lighter_orders.go: Order management (create/cancel/query) - lighter_account.go: Balance & position queries Status: ⚠️ Partial implementation - ✅ Core structure complete - ⏸️ Auth token generation needs implementation - ⏸️ Transaction signing logic needs completion - ⏸️ Config integration pending Next steps: 1. Complete auth token generation 2. Add to config/exchange registry 3. Add frontend UI support 4. Create test suite 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: tinkle-community <tinklefund@gmail.com> * feat: Add LIGHTER DEX integration (快速整合階段) ## 🚀 新增功能 - ✅ 添加 LIGHTER DEX 作為第四個支持的交易所 (Binance, Hyperliquid, Aster, LIGHTER) - ✅ 完整的數據庫配置支持(ExchangeConfig 新增 LighterWalletAddr, LighterPrivateKey 字段) - ✅ 交易所註冊與初始化(initDefaultData 註冊 "lighter") - ✅ TraderManager 集成(配置傳遞邏輯完成) - ✅ AutoTrader 支持(NewAutoTrader 添加 "lighter" case) ## 📝 實現細節 ### 後端整合 1. **數據庫層** (config/database.go): - ExchangeConfig 添加 LIGHTER 字段 - 創建表時添加 lighter_wallet_addr, lighter_private_key 欄位 - ALTER TABLE 語句用於向後兼容 - UpdateExchange/CreateExchange/GetExchanges 支持 LIGHTER - migrateExchangesTable 支持 LIGHTER 字段 2. **API 層** (api/server.go, api/utils.go): - UpdateExchangeConfigRequest 添加 LIGHTER 字段 - SanitizeExchangeConfigForLog 添加脫敏處理 3. **Trader 層** (trader/): - lighter_trader.go: 核心結構、認證、初始化 - lighter_account.go: 餘額、持倉、市場價格查詢 - lighter_orders.go: 訂單管理(創建、取消、查詢) - lighter_trading.go: 交易功能實現(開多/空、平倉、止損/盈) - 實現完整 Trader interface (13個方法) 4. **Manager 層** (manager/trader_manager.go): - addTraderFromDB 添加 LIGHTER 配置設置 - AutoTraderConfig 添加 LIGHTER 字段 ### 實現的功能(快速整合階段) ✅ 基礎交易功能 (OpenLong, OpenShort, CloseLong, CloseShort) ✅ 餘額查詢 (GetBalance, GetAccountBalance) ✅ 持倉查詢 (GetPositions, GetPosition) ✅ 訂單管理 (CreateOrder, CancelOrder, CancelAllOrders) ✅ 止損/止盈 (SetStopLoss, SetTakeProfit, CancelStopLossOrders) ✅ 市場數據 (GetMarketPrice) ✅ 格式化工具 (FormatQuantity) ## ⚠️ TODO(完整實現階段) - [ ] 完整認證令牌生成邏輯 (refreshAuthToken) - [ ] 完整交易簽名邏輯(參考 Python SDK) - [ ] 從 API 獲取幣種精度 - [ ] 區分止損/止盈訂單類型 - [ ] 前端 UI 支持 - [ ] 完整測試套件 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: tinkle-community <tinklefund@gmail.com> * feat: 完整集成 LIGHTER DEX with SDK - 集成官方 lighter-go SDK (v0.0.0-20251104171447-78b9b55ebc48) - 集成 Poseidon2 Goldilocks 簽名庫 (poseidon_crypto v0.0.11) - 實現完整的 LighterTraderV2 使用官方 SDK - 實現 17 個 Trader 接口方法(賬戶、交易、訂單管理) - 支持雙密鑰系統(L1 錢包 + API Key) - V1/V2 自動切換機制(向後兼容) - 自動認證令牌管理(8小時有效期) - 添加完整集成文檔 LIGHTER_INTEGRATION.md 新增文件: - trader/lighter_trader_v2.go - V2 核心結構和初始化 - trader/lighter_trader_v2_account.go - 賬戶查詢方法 - trader/lighter_trader_v2_trading.go - 交易操作方法 - trader/lighter_trader_v2_orders.go - 訂單管理方法 - LIGHTER_INTEGRATION.md - 完整文檔 修改文件: - trader/auto_trader.go - 添加 LighterAPIKeyPrivateKey 配置 - config/database.go - 添加 API Key 字段支持 - go.mod, go.sum - 添加 SDK 依賴 🤖 Generated with Claude Code Co-Authored-By: tinkle-community <tinklefund@gmail.com> * feat(lighter): 實現完整 HTTP 調用與動態市場映射 ### 實現的功能 #### 1. submitOrder() - 真實訂單提交 - 使用 POST /api/v1/sendTx 提交已簽名訂單 - tx_type: 14 (CREATE_ORDER) - 價格保護機制 (price_protection) - 完整錯誤處理與響應解析 #### 2. GetActiveOrders() - 查詢活躍訂單 - GET /api/v1/accountActiveOrders - 使用認證令牌 (Authorization header) - 支持按市場索引過濾 #### 3. CancelOrder() - 真實取消訂單 - 使用 SDK 簽名 CancelOrderTxReq - POST /api/v1/sendTx with tx_type: 15 (CANCEL_ORDER) - 自動 nonce 管理 #### 4. getMarketIndex() - 動態市場映射 - 從 GET /api/v1/orderBooks 獲取市場列表 - 內存緩存 (marketIndexMap) 提高性能 - 回退到硬編碼映射(API 失敗時) - 線程安全 (sync.RWMutex) ### 技術實現 **數據結構**: - SendTxRequest/SendTxResponse - sendTx 請求響應 - MarketInfo - 市場信息緩存 **並發安全**: - marketMutex - 保護市場索引緩存 - 讀寫鎖優化性能 **錯誤處理**: - API 失敗回退機制 - 詳細日誌記錄 - HTTP 狀態碼驗證 ### 測試 ✅ 編譯通過 (CGO_ENABLED=1) ✅ 所有 Trader 接口方法實現完整 ✅ HTTP 調用格式符合 LIGHTER API 規範 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: tinkle-community <tinklefund@gmail.com> * feat(lighter): 數據庫遷移與前端類型支持 ### 數據庫變更 #### 新增欄位 - `exchanges.lighter_api_key_private_key` TEXT DEFAULT '' - 支持 LIGHTER V2 的 40 字節 API Key 私鑰 #### 遷移腳本 - 📄 `migrations/002_add_lighter_api_key.sql` - 包含完整的驗證和統計查詢 - 向後兼容現有配置(默認為空,使用 V1) #### Schema 更新 - `config/database.go`: - 更新 CREATE TABLE 語句 - 更新 exchanges_new 表結構 - 新增 ALTER TABLE 遷移命令 ### 前端類型更新 #### types.ts - 新增 `Exchange` 接口字段: - `lighterWalletAddr?: string` - L1 錢包地址 - `lighterPrivateKey?: string` - L1 私鑰 - `lighterApiKeyPrivateKey?: string` - API Key 私鑰(⭐新增) ### 技術細節 **數據庫兼容性**: - 使用 ALTER TABLE ADD COLUMN IF NOT EXISTS - 默認值為空字符串 - 不影響現有數據 **類型安全**: - TypeScript 可選字段 - 與後端 ExchangeConfig 結構對齊 ### 下一步 ⏳ **待完成**: 1. ExchangeConfigModal 組件更新 2. API 調用參數傳遞 3. V1/V2 狀態顯示 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: tinkle-community <tinklefund@gmail.com> * docs(lighter): 更新 LIGHTER_INTEGRATION.md 文檔狀態 * feat(lighter): 前端完整實現 - API Key 配置與 V1/V2 狀態 **英文**: - `lighterWalletAddress`, `lighterPrivateKey`, `lighterApiKeyPrivateKey` - `lighterWalletAddressDesc`, `lighterPrivateKeyDesc`, `lighterApiKeyPrivateKeyDesc` - `lighterApiKeyOptionalNote` - V1 模式提示 - `lighterV1Description`, `lighterV2Description` - 狀態說明 - `lighterPrivateKeyImported` - 導入成功提示 **中文(繁體)**: - 完整的中文翻譯對應 - 專業術語保留原文(L1、API Key、Poseidon2) **Exchange 接口**: - `lighterWalletAddr?: string` - `lighterPrivateKey?: string` - `lighterApiKeyPrivateKey?: string` **UpdateExchangeConfigRequest 接口**: - `lighter_wallet_addr?: string` - `lighter_private_key?: string` - `lighter_api_key_private_key?: string` **狀態管理**: - 添加 3 個 LIGHTER 狀態變量 - 更新 `secureInputTarget` 類型包含 'lighter' **表單字段**: - L1 錢包地址(必填,text input) - L1 私鑰(必填,password + 安全輸入) - API Key 私鑰(可選,password,40 字節) **V1/V2 狀態顯示**: - 動態背景顏色(V1: 橙色 #3F2E0F,V2: 綠色 #0F3F2E) - 圖標指示(V1: ⚠️,V2: ✅) - 狀態說明文字 **驗證邏輯**: - 必填字段:錢包地址 + L1 私鑰 - API Key 為可選字段 - 自動 V1/V2 檢測 **安全輸入**: - 支持通過 TwoStageKeyModal 安全導入私鑰 - 導入成功後顯示 toast 提示 **handleSaveExchange**: - 添加 3 個 LIGHTER 參數 - 更新交易所對象(新增/更新) - 構建 API 請求(snake_case 字段) **V1 模式(無 API Key)**: ``` ┌────────────────────────────────────────┐ │ ⚠️ LIGHTER V1 │ │ 基本模式 - 功能受限,僅用於測試框架 │ └────────────────────────────────────────┘ 背景: #3F2E0F (橙色調) 邊框: #F59E0B (橙色) ``` **V2 模式(有 API Key)**: ``` ┌────────────────────────────────────────┐ │ ✅ LIGHTER V2 │ │ 完整模式 - 支持 Poseidon2 簽名和真實交易 │ └────────────────────────────────────────┘ 背景: #0F3F2E (綠色調) 邊框: #10B981 (綠色) ``` 1. **類型安全** - 完整的 TypeScript 類型定義 - Props 接口正確對齊 - ✅ 無 LIGHTER 相關編譯錯誤 2. **用戶體驗** - 清晰的必填/可選字段區分 - 實時 V1/V2 狀態反饋 - 安全私鑰輸入支持 3. **向後兼容** - 不影響現有交易所配置 - 所有字段為可選(Optional) - API 請求格式統一 ✅ TypeScript 編譯通過(無 LIGHTER 錯誤) ✅ 類型定義完整且正確 ✅ 所有必需文件已更新 ✅ 與後端 API 格式對齊 Modified: - `web/src/i18n/translations.ts` - 中英文翻譯 - `web/src/types.ts` - 類型定義 - `web/src/components/traders/ExchangeConfigModal.tsx` - Modal 組件 - `web/src/hooks/useTraderActions.ts` - Actions hook 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: tinkle-community <tinklefund@gmail.com> * test(lighter): 添加 V1 測試套件與修復 SafeFloat64 缺失 - 新增 trader/helpers.go: 添加 SafeFloat64/SafeString/SafeInt 輔助函數 - 新增 trader/lighter_trader_test.go: LIGHTER V1 測試套件 - ✅ 測試通過 (7/10): - NewTrader 驗證 (無效私鑰, 有效私鑰格式) - FormatQuantity - GetExchangeType - InvalidQuantity 驗證 - InvalidLeverage 驗證 - HelperFunctions (SafeFloat64) - ⚠️ 待改進 (3/10): - GetBalance (需要調整 mock 響應格式) - GetPositions (需要調整 mock 響應格式) - GetMarketPrice (需要調整 mock 響應格式) - 修復 Bug: lighter_account.go 和 lighter_trader_v2_account.go 中未定義的 SafeFloat64 - 測試框架: httptest.Server mock LIGHTER API - 安全: 使用固定測試私鑰 (不含真實資金) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: tinkle-community <tinklefund@gmail.com> --------- Co-authored-by: the-dev-z <the-dev-z@users.noreply.github.com> Co-authored-by: tinkle-community <tinklefund@gmail.com> |
||
|
|
031cc19c99 |
fix(api): use UUID to ensure traderID uniqueness (#893) (#1008)
## Problem
When multiple users create traders with the same exchange + AI model
combination within the same second, they generate identical traderIDs,
causing data conflicts.
Old code (Line 496):
```go
traderID := fmt.Sprintf("%s_%s_%d", req.ExchangeID, req.AIModelID, time.Now().Unix())
```
## Solution
Use UUID to guarantee 100% uniqueness while preserving prefix for debugging:
```go
traderID := fmt.Sprintf("%s_%s_%s", req.ExchangeID, req.AIModelID, uuid.New().String())
```
Example output: `binance_gpt-4_a1b2c3d4-e5f6-7890-abcd-ef1234567890`
## Changes
- `api/server.go:495-497`: Use UUID for traderID generation
- `api/traderid_test.go`: New test file with 3 comprehensive tests
## Tests
✅ All tests passed (0.189s)
✅ TestTraderIDUniqueness - 100 unique IDs generated
✅ TestTraderIDFormat - 3 exchange/model combinations validated
✅ TestTraderIDNoCollision - 1000 iterations without collision
Fixes #893
Co-authored-by: the-dev-z <the-dev-z@users.noreply.github.com>
|
||
|
|
fc8a4d3d63 | fix(stats): fixed the PNL calculation (#963) | ||
|
|
10e6566947 |
feat(dashboard): 在交易者详情页显示系统提示词模板名称 (#775)
* feat(dashboard): display system prompt template and extract color constant * style(api): format server.go with go fmt |
||
|
|
e497898ef1 |
feat: add whether to enable self registration toggle (#760)
* refactor(frontend): extract RegistrationDisabled as reusable component - Create RegistrationDisabled component with i18n support - Add registrationClosed and registrationClosedMessage translations - Replace inline JSX in App.tsx with new component - Improve code maintainability and reusability - Add hover effect to back button for better UX * fix(frontend): add registration toggle to LoginModal component - Add useSystemConfig hook to LoginModal - Conditionally render registration button based on registration_enabled config - Ensures consistency with HeaderBar and LoginPage registration controls - Completes registration toggle feature implementation across all entry points * feat(frontend): add registration toggle UI support - Add registration disabled page in App.tsx when registration is closed - Hide registration link in LoginPage when registration is disabled - Add registration_enabled field to SystemConfig interface - Frontend conditionally shows/hides registration UI based on backend config * feat: add registration toggle feature Add system-level registration enable/disable control: - Add registration_enabled config to system_config table (default: true) - Add registration check in handleRegister API endpoint - Expose registration_enabled status in /api/config endpoint - Frontend can use this config to conditionally show/hide registration UI This allows administrators to control user registration without code changes. * fix(frontend): add registration toggle to HeaderBar and RegisterPage - Add useSystemConfig hook and registrationEnabled check to HeaderBar - Conditionally show/hide signup buttons in both desktop and mobile views - Add registration check to RegisterPage to show RegistrationDisabled component - This completes the registration toggle feature across all UI components * test(frontend): add comprehensive unit tests for registration toggle feature - Add RegistrationDisabled component tests (rendering, navigation, styling) - Add registrationToggle logic tests (config handling, edge cases, multi-location consistency) - Configure Vitest with jsdom environment for React component testing - All 80 tests passing (9 new tests for RegistrationDisabled + 21 for toggle logic) |
||
|
|
2a2aabf729 | merge fix | ||
|
|
db9851b993 |
Merge branch 'dev' into beta
# Conflicts: # .github/workflows/docker-build.yml # .gitignore # api/server.go # config/config.go # config/database.go # decision/engine.go # docker-compose.yml # go.mod # go.sum # logger/telegram_sender.go # main.go # mcp/client.go # prompts/adaptive.txt # prompts/default.txt # prompts/nof1.txt # start.sh # trader/aster_trader.go # trader/auto_trader.go # trader/binance_futures.go # trader/hyperliquid_trader.go # web/package-lock.json # web/package.json # web/src/App.tsx # web/src/components/AILearning.tsx # web/src/components/AITradersPage.tsx # web/src/components/CompetitionPage.tsx # web/src/components/EquityChart.tsx # web/src/components/Header.tsx # web/src/components/LoginPage.tsx # web/src/components/RegisterPage.tsx # web/src/components/TraderConfigModal.tsx # web/src/components/TraderConfigViewModal.tsx # web/src/components/landing/FooterSection.tsx # web/src/components/landing/HeaderBar.tsx # web/src/contexts/AuthContext.tsx # web/src/i18n/translations.ts # web/src/lib/api.ts # web/src/lib/config.ts # web/src/types.ts |
||
|
|
33b46e8092 |
feat: Add decision limit selector with 5/10/20/50 options (#638)
## Summary Allow users to select the number of decision records to display (5/10/20/50) in the Web UI, with persistent storage in localStorage. ## Changes ### Backend - api/server.go: Add 'limit' query parameter support to /api/decisions/latest - Default: 5 (maintains current behavior) - Max: 50 (prevents excessive data loading) - Fully backward compatible ### Frontend - web/src/lib/api.ts: Update getLatestDecisions() to accept limit parameter - web/src/pages/TraderDashboard.tsx: - Add decisionLimit state management with localStorage persistence - Add dropdown selector UI (5/10/20/50 options) - Pass limit to API calls and update SWR cache key ## Time Coverage - 5 records = 15 minutes (default, quick check) - 10 records = 30 minutes (short-term review) - 20 records = 1 hour (medium-term analysis) - 50 records = 2.5 hours (deep pattern analysis) |
||
|
|
6635bc0803 |
feat(decision): auto-reload prompt templates when starting trader (#833)
* feat: 启动交易员时自动重新加载系统提示词模板 ## 改动内容 - 在 handleStartTrader 中调用 decision.ReloadPromptTemplates() - 每次启动交易员时从硬盘重新加载 prompts/ 目录下的所有 .txt 模板文件 - 添加完整的单元测试和端到端集成测试 ## 测试覆盖 - 单元测试:模板加载、获取、重新加载功能 - 集成测试:文件修改 → 重新加载 → 决策引擎使用新内容的完整流程 - 并发测试:验证多 goroutine 场景下的线程安全性 - Race detector 测试通过 ## 用户体验改进 - 修改 prompt 文件后无需重启服务 - 只需停止交易员再启动即可应用新的 prompt - 控制台会输出重新加载成功的日志提示 * feat: 在重新加载日志中显示当前使用的模板名称 * feat: fallback 到 default 模板时明确显示原因 * fix: correct GetTraderConfig return type to get SystemPromptTemplate * refactor: extract reloadPromptTemplatesWithLog as reusable method |
||
|
|
27f438958f |
fix(auth): allow re-fetching OTP for unverified users (#653)
* fix(auth): allow re-fetching OTP for unverified users
**Problem:**
- User registers but interrupts OTP setup
- Re-registration returns "邮箱已被注册" error
- User stuck, cannot retrieve QR code to complete setup
**Root Cause:**
- handleRegister rejects all existing emails without checking OTPVerified status
- No way for users to recover from interrupted registration
**Fix:**
- Check if existing user has OTPVerified=false
- If unverified, return original OTP QR code instead of error
- User can continue completing registration with same user_id
- If verified, still reject with "邮箱已被注册" (existing behavior)
**Code Changes:**
```go
// Before:
_, err := s.database.GetUserByEmail(req.Email)
if err == nil {
c.JSON(http.StatusConflict, gin.H{"error": "邮箱已被注册"})
return
}
// After:
existingUser, err := s.database.GetUserByEmail(req.Email)
if err == nil {
if !existingUser.OTPVerified {
// Return OTP to complete registration
qrCodeURL := auth.GetOTPQRCodeURL(existingUser.OTPSecret, req.Email)
c.JSON(http.StatusOK, gin.H{
"user_id": existingUser.ID,
"otp_secret": existingUser.OTPSecret,
"qr_code_url": qrCodeURL,
"message": "检测到未完成的注册,请继续完成OTP设置",
})
return
}
c.JSON(http.StatusConflict, gin.H{"error": "邮箱已被注册"})
return
}
```
**Testing Scenario:**
1. User POST /api/register with email + password
2. User receives OTP QR code but closes browser (interrupts)
3. User POST /api/register again with same email + password
4. ✅ Now returns original OTP instead of error
5. User can complete registration via /api/complete-registration
**Security:**
✅ No security issue - still requires OTP verification
✅ Only returns OTP for unverified accounts
✅ Password not validated on re-fetch (same as initial registration)
**Impact:**
✅ Users can recover from interrupted registration
✅ Better UX for registration flow
✅ No breaking changes to existing verified users
**API Changes:**
- POST /api/register response for unverified users:
- Status: 200 OK (was: 409 Conflict)
- Body includes: user_id, otp_secret, qr_code_url, message
Fixes #615
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: tinkle-community <tinklefund@gmail.com>
* test(api): add comprehensive unit tests for OTP re-fetch logic
- Test OTP re-fetch logic for unverified users
- Test OTP verification state handling
- Test complete registration flow scenarios
- Test edge cases (ID=0, empty OTPSecret, verified users)
All 11 test cases passed, covering:
1. OTPRefetchLogic (3 cases): new user, unverified refetch, verified rejection
2. OTPVerificationStates (2 cases): verified/unverified states
3. RegistrationFlow (3 cases): first registration, interrupted resume, duplicate attempt
4. EdgeCases (3 cases): validates behavior with edge conditions
Related to PR #653 - ensures proper OTP re-fetch behavior for unverified users.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: tinkle-community <tinklefund@gmail.com>
* style: apply go fmt after rebase
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: tinkle-community <tinklefund@gmail.com>
---------
Co-authored-by: ZhouYongyou <128128010+zhouyongyou@users.noreply.github.com>
Co-authored-by: tinkle-community <tinklefund@gmail.com>
|
||
|
|
ce1f698016 | should not load all user traders when create/update trader (#854) | ||
|
|
c7c70262af |
fix(trader): 修复编辑交易员时系统提示词模板无法更新和回显的问题 (#841)
## 问题描述 1. ⚠️ **无法更新**(最严重):用户修改系统提示词模板并保存后,更新被忽略,仍保持旧值 2. 编辑时显示错误的默认值:打开编辑对话框时该字段显示为 Default 而非实际保存的值(如 nof1) ## 根本原因 1. UpdateTraderRequest 结构体缺少 SystemPromptTemplate 字段 - 后端无法接收更新请求 2. handleGetTraderConfig 返回值中缺少 system_prompt_template 字段 - 前端无法获取实际值 3. handleUpdateTrader 强制使用原值,不接受请求中的更新 - 即使前端发送也被忽略 ## 修复内容 1. 在 UpdateTraderRequest 中添加 SystemPromptTemplate 字段 - 现在可以接收更新 2. 在 handleUpdateTrader 中支持从请求读取并更新该字段 - 用户可以修改了 3. 在 handleGetTraderConfig 返回值中添加 system_prompt_template 字段 - 前端可以正确显示 ## 测试 - 添加 3 个单元测试验证修复 - 所有测试通过,无回归 - 覆盖 nof1, default, custom 等不同模板场景 ## 影响范围 - api/server.go: UpdateTraderRequest, handleUpdateTrader, handleGetTraderConfig - 新增 api/server_test.go: 3 个单元测试 Closes #838 |
||
|
|
0188ffb778 |
fix(database): prevent data loss on Docker restart with WAL mode and graceful shutdown (#817)
* fix(database): prevent data loss on Docker restart with WAL mode and graceful shutdown Fixes #816 ## Problem Exchange API keys and private keys were being lost after `docker compose restart`. This P0 bug posed critical security and operational risks. ### Root Cause 1. **SQLite journal_mode=delete**: Traditional rollback journal doesn't protect against data loss during non-graceful shutdowns 2. **Incomplete graceful shutdown**: Application relied on `defer database.Close()` which may not execute before process termination 3. **Docker grace period**: Default 10s may not be sufficient for cleanup ### Data Loss Scenario ``` User updates exchange config → Backend writes to SQLite → Data in buffer (not fsynced) → Docker restart (SIGTERM) → App exits → SQLite never flushes → Data lost ``` ## Solution ### 1. Enable WAL Mode (Primary Fix) - **Before**: `journal_mode=delete` (rollback journal) - **After**: `journal_mode=WAL` (Write-Ahead Logging) **Benefits:** - ✅ Crash-safe even during power loss - ✅ Better concurrent write performance - ✅ Atomic commits with durability guarantees ### 2. Improve Graceful Shutdown **Before:** ```go <-sigChan traderManager.StopAll() // defer database.Close() may not execute in time ``` **After:** ```go <-sigChan traderManager.StopAll() // Step 1: Stop traders server.Shutdown() // Step 2: Stop HTTP server (new) database.Close() // Step 3: Explicit database close (new) ``` ### 3. Increase Docker Grace Period ```yaml stop_grace_period: 30s # Allow 30s for graceful shutdown ``` ## Changes ### config/database.go - Enable `PRAGMA journal_mode=WAL` on database initialization - Set `PRAGMA synchronous=FULL` for data durability - Add log message confirming WAL mode activation ### api/server.go - Add `httpServer *http.Server` field to Server struct - Implement `Shutdown()` method with 5s timeout - Replace `router.Run()` with `httpServer.ListenAndServe()` for graceful shutdown support - Add `context` import for shutdown context ### main.go - Add explicit shutdown sequence: 1. Stop all traders 2. Shutdown HTTP server (new) 3. Close database connection (new) - Add detailed logging for each shutdown step ### docker-compose.yml - Add `stop_grace_period: 30s` to backend service ### config/database_test.go (TDD) - `TestWALModeEnabled`: Verify WAL mode is active - `TestSynchronousMode`: Verify synchronous=FULL setting - `TestDataPersistenceAcrossReopen`: Simulate Docker restart scenario - `TestConcurrentWritesWithWAL`: Verify concurrent write handling ## Test Results ```bash $ go test -v ./config === RUN TestWALModeEnabled --- PASS: TestWALModeEnabled (0.25s) === RUN TestSynchronousMode --- PASS: TestSynchronousMode (0.06s) === RUN TestDataPersistenceAcrossReopen --- PASS: TestDataPersistenceAcrossReopen (0.05s) === RUN TestConcurrentWritesWithWAL --- PASS: TestConcurrentWritesWithWAL (0.09s) PASS ``` All 16 tests pass (including 9 existing + 4 new WAL tests + 3 concurrent tests). ## Impact **Before:** - 🔴 Exchange credentials lost on restart - 🔴 Trading operations disrupted - 🔴 Security risk from credential re-entry **After:** - ✅ Data persistence guaranteed - ✅ No credential loss after restart - ✅ Safe graceful shutdown in all scenarios - ✅ Better concurrent performance ## Acceptance Criteria - [x] WAL mode enabled in database initialization - [x] Graceful shutdown explicitly closes database - [x] Unit tests verify data persistence across restarts - [x] Docker grace period increased to 30s - [x] All tests pass ## Deployment Notes After deploying this fix: 1. Rebuild Docker image: `./start.sh start --build` 2. Existing `config.db` will be automatically converted to WAL mode 3. WAL files (`config.db-wal`, `config.db-shm`) will be created 4. No manual intervention required ## References - SQLite WAL Mode: https://www.sqlite.org/wal.html - Go http.Server Graceful Shutdown: https://pkg.go.dev/net/http#Server.Shutdown * Add config.db* to gitignore |
||
|
|
631fb62d21 | feat(hook): Add hook module to help decouple some specific logic (#784) | ||
|
|
fa8df5f5ce |
fix(security): 脱敏后台日志中的敏感信息 (#761)
## 问题
后台日志在打印配置更新时会暴露完整的 API Key、Secret Key 和私钥等敏感信息(Issue #758)。
## 解决方案
### 1. 新增脱敏工具库 (api/utils.go)
- `MaskSensitiveString()`: 脱敏敏感字符串(保留前4位和后4位,中间用****替代)
- `SanitizeModelConfigForLog()`: 脱敏 AI 模型配置用于日志输出
- `SanitizeExchangeConfigForLog()`: 脱敏交易所配置用于日志输出
- `MaskEmail()`: 脱敏邮箱地址
### 2. 修复日志打印 (api/server.go)
- Line 1106: 脱敏 AI 模型配置更新日志
- Line 1203: 脱敏交易所配置更新日志
### 3. 完善单元测试 (api/utils_test.go)
- 4个测试函数,9个子测试,全部通过
- 工具函数测试覆盖率: 91%+
## 脱敏效果示例
**修复前**:
```
✓ 交易所配置已更新: map[binance:{api_key:sk-1234567890abcdef secret_key:binance_secret_1234567890abcdef}]
```
**修复后**:
```
✓ 交易所配置已更新: map[binance:{api_key:sk-1****cdef secret_key:bina****cdef}]
```
## 测试结果
```
PASS
ok nofx/api 0.012s
coverage: 91.2% of statements in utils.go
```
## 安全影响
- 防止日志泄露 API Key、Secret Key、私钥等敏感信息
- 保护用户隐私和账户安全
- 符合安全最佳实践
Closes #758
|
||
|
|
ddb33c7f87 | Fix(encryption)/aiconfig, exchange config and the encryption setup (#735) | ||
|
|
57af6c00a3 |
Dev Crypto (#730)
* feat: remove admin mode * feat: bugfix * feat(crypto): 添加RSA-OAEP + AES-GCM混合加密服务 - 实现CryptoService加密服务,支持RSA-OAEP-2048 + AES-256-GCM混合加密 - 集成数据库层加密,自动加密存储敏感字段(API密钥、私钥等) - 支持环境变量DATA_ENCRYPTION_KEY配置数据加密密钥 - 适配SQLite数据库加密存储(从PostgreSQL移植) - 保持Hyperliquid代理钱包处理兼容性 - 更新.gitignore以正确处理crypto模块代码 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: tinkle-community <tinklefund@gmail.com> * feat(scripts): 添加加密环境一键设置脚本 - setup_encryption.sh: 一键生成RSA密钥对+数据加密密钥+JWT密钥 - generate_rsa_keys.sh: 专业的RSA-2048密钥对生成工具 - generate_data_key.sh: 生成AES-256数据加密密钥和JWT认证密钥 - ENCRYPTION_README.md: 详细的加密系统说明文档 - 支持自动检测现有密钥并只生成缺失的密钥 - 完善的权限管理和安全验证 - 兼容macOS和Linux的跨平台支持 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: tinkle-community <tinklefund@gmail.com> * feat(api): 添加加密API端点和Gin框架集成 - 新增CryptoHandler处理加密相关API请求 - 提供/api/crypto/public-key端点获取RSA公钥 - 提供/api/crypto/decrypt端点解密敏感数据 - 适配Gin框架的HTTP处理器格式 - 集成CryptoService到API服务器 - 支持前端加密数据传输和解密 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: tinkle-community <tinklefund@gmail.com> * feat(web): 添加前端加密服务和两阶段密钥输入组件 - CryptoService: Web Crypto API集成,支持RSA-OAEP加密 - TwoStageKeyModal: 安全的两阶段私钥输入组件,支持剪贴板混淆 - 完善国际化翻译支持加密相关UI文本 - 修复TypeScript类型错误和编译问题 - 支持前端敏感数据加密传输到后端 - 增强用户隐私保护和数据安全 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: tinkle-community <tinklefund@gmail.com> * feat(auth): 增强JWT认证安全性 - 优先使用环境变量JWT_SECRET而不是数据库配置 - 支持通过.env文件安全配置JWT认证密钥 - 保留数据库配置作为回退机制 - 改进JWT密钥来源日志显示 - 增强系统启动时的安全配置检查 - 支持运行时动态JWT密钥切换 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: tinkle-community <tinklefund@gmail.com> * feat(docker): 集成加密环境变量到Docker部署 - 添加DATA_ENCRYPTION_KEY环境变量传递到容器 - 添加JWT_SECRET环境变量支持 - 挂载secrets目录使容器可访问RSA密钥文件 - 确保容器内加密服务正常工作 - 解决容器启动失败和加密初始化问题 - 完善Docker Compose加密环境配置 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: tinkle-community <tinklefund@gmail.com> * feat(start): 集成自动加密环境检测和设置 - 增强check_encryption()函数检测JWT_SECRET和DATA_ENCRYPTION_KEY - 自动运行setup_encryption.sh当检测到缺失密钥时 - 改进加密状态显示,包含RSA+AES+JWT全套加密信息 - 优化用户体验,提供清晰的加密配置反馈 - 支持一键设置完整加密环境 - 确保容器启动前加密环境就绪 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: tinkle-community <tinklefund@gmail.com> * feat: format fix * fix(security): 修复前端模型和交易所配置敏感数据明文传输 - 在handleSaveModelConfig中对API密钥进行RSA-OAEP加密 - 在handleSaveExchangeConfig中对API密钥、Secret密钥和Aster私钥进行加密 - 只有非空敏感数据才进行加密处理 - 添加加密失败错误处理和用户友好提示 - 增加encryptionFailed翻译键的中英文支持 - 使用用户ID和会话ID作为加密上下文增强安全性 这修复了之前敏感数据在网络传输中以明文形式发送的安全漏洞。 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: tinkle-community <tinklefund@gmail.com> * fix(crypto): 修复后端加密服务集成和缺失的加密端点 - 添加Server结构体缺少的cryptoService字段 - 实现handleUpdateModelConfigsEncrypted处理器用于模型配置加密传输 - 修复handleUpdateExchangeConfigsEncrypted中的函数调用 - 在前端API中添加updateModelConfigsEncrypted方法 - 统一RSA密钥路径从secrets/rsa_key改为keys/rsa_private.key - 确保前端可以使用加密端点安全传输敏感数据 - 兼容原有加密通信模式和二段输入私钥功能 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: tinkle-community <tinklefund@gmail.com> --------- Co-authored-by: icy <icyoung520@gmail.com> Co-authored-by: tinkle-community <tinklefund@gmail.com> |
||
|
|
f270bc3fee |
Dev remove admin mode (#723)
* feat: remove admin mode * feat: bugfix --------- Co-authored-by: icy <icyoung520@gmail.com> |
||
|
|
e2d05639a7 |
fix:完善aster账户净值和盈亏计算|Improve the calculation of the net value and profit/loss of the aster account (#695)
Co-authored-by: LindenWang <linden@Lindens-MacBookPro-2.local> |
||
|
|
4caf34d329 |
feat(security): add end-to-end encryption for sensitive data
## Summary
Add comprehensive encryption system to protect private keys and API secrets.
## Core Components
- `crypto/encryption.go`: RSA-4096 + AES-256-GCM encryption manager
- `crypto/secure_storage.go`: Database encryption layer + audit logs
- `crypto/aliyun_kms.go`: Optional Aliyun KMS integration
- `api/crypto_handler.go`: Encryption API endpoints
- `web/src/lib/crypto.ts`: Frontend two-stage encryption
- `scripts/migrate_encryption.go`: Data migration tool
- `deploy_encryption.sh`: One-click deployment
## Security Architecture
```
Frontend: Two-stage input + clipboard obfuscation
↓
Transport: RSA-4096 + AES-256-GCM hybrid encryption
↓
Storage: Database encryption + audit logs
```
## Features
✅ Zero breaking changes (backward compatible)
✅ Automatic migration of existing data
✅ <25ms overhead per operation
✅ Complete audit trail
✅ Optional cloud KMS support
## Migration
```bash
./deploy_encryption.sh # 5 minutes, zero downtime
```
## Testing
```bash
go test ./crypto -v
```
Related-To: security-enhancement
|
||
|
|
fce3441aff |
Fix: 提示词, 竞赛数据接口在管理员模式下转为公开 (#607)
* 提示词, 竞赛数据接口在管理员模式下转为公开 * Fix "go vet" error |
||
|
|
a2eb03ede9 | Add public routes for supported models and exchanges (#554) | ||
|
|
5f98e09920 |
Feat: Enable admin password in admin mode (#540)
* WIP: save local changes before merging * Enable admin password in admin mode #374 |
||
|
|
87a834c4f5 |
feat(auth): implement password reset with Google Authenticator verification (#537)
实现忘记密码功能,用户可以通过邮箱和Google Authenticator验证码重置密码。 **后端改动:** - 添加 `/api/reset-password` 接口 - 实现 `UpdateUserPassword` 数据库方法 - 验证邮箱、OTP和新密码 **前端改动:** - 新增 `ResetPasswordPage` 组件 - 在登录页面添加"忘记密码"链接 - 实现密码重置表单(新密码、确认密码、OTP验证) - 添加密码可见性切换功能 - 支持中英文国际化 **安全特性:** - 要求Google Authenticator验证 - 密码强度验证(最少6位) - 密码确认匹配检查 - 密码哈希存储 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: tinkle-community <tinklefund@gmail.com> |
||
|
|
d8cb1e6e47 |
Beta merge from dev (#535)
* fix: GetTraderConfig missing critical fields in SELECT/Scan **Problem**: - GetTraderConfig was missing 9 critical fields in SELECT statement - Missing corresponding Scan variables - Caused trader edit UI to show 0 for leverage and empty trading_symbols **Root Cause**: Database query only selected basic fields (id, name, balance, etc.) but missed leverage, trading_symbols, prompts, and all custom configs **Fix**: - Added missing fields to SELECT: * btc_eth_leverage, altcoin_leverage * trading_symbols * use_coin_pool, use_oi_top * custom_prompt, override_base_prompt * system_prompt_template * is_cross_margin * AI model custom_api_url, custom_model_name - Added corresponding Scan variables to match SELECT order **Impact**: ✅ Trader edit modal now displays correct leverage values ✅ Trading symbols list properly populated ✅ All custom configurations preserved and displayed ✅ API endpoint /traders/:id/config returns complete data **Testing**: - ✅ Go compilation successful - ✅ All fields aligned (31 SELECT = 31 Scan) - ✅ API layer verified (api/server.go:887-904) Reported by: 寒江孤影 Issue: Trader config edit modal showing 0 leverage and empty symbols 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: tinkle-community <tinklefund@gmail.com> * Fix PR check * fix(readme): update readme and pr reviewer * fix owner * Fix owner * feat(hyperliquid): Auto-generate wallet address from private key Enable automatic wallet address generation from private key for Hyperliquid exchange, simplifying user onboarding and reducing configuration errors. Backend Changes (trader/hyperliquid_trader.go): - Import crypto/ecdsa package for ECDSA public key operations - Enable wallet address auto-generation when walletAddr is empty - Use crypto.PubkeyToAddress() to derive address from private key - Add logging for both auto-generated and manually provided addresses Frontend Changes (web/src/components/AITradersPage.tsx): - Remove wallet address required validation (only private key required) - Update button disabled state to only check private key - Add "Optional" label to wallet address field - Add dynamic placeholder with bilingual hint - Show context-aware helper text based on input state - Remove HTML required attribute from input field Translation Updates (web/src/i18n/translations.ts): - Add 'optional' translation (EN: "Optional", ZH: "可选") - Add 'hyperliquidWalletAddressAutoGenerate' translation EN: "Leave blank to automatically generate wallet address from private key" ZH: "留空将自动从私钥生成钱包地址" Benefits: ✅ Simplified UX - Users only need to provide private key ✅ Error prevention - Auto-generated address always matches private key ✅ Backward compatible - Manual address input still supported ✅ Better UX - Clear visual indicators for optional fields Technical Details: - Uses Ethereum standard ECDSA public key to address conversion - Implementation was already present but commented out (lines 37-43) - No database schema changes required (hyperliquid_wallet_addr already nullable) - Fallback behavior: manual input > auto-generation 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: tinkle-community <tinklefund@gmail.com> * fix * fix pk prefix handle * fix go vet check * fix print * feat: Add Binance setup guide with tutorial modal - Add Binance configuration tutorial image (guide.png) - Implement "View Guide" button in exchange configuration modal - Add tutorial display modal with image viewer - Add i18n support for guide-related text (EN/ZH) - Button only appears when configuring Binance exchange 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: tinkle-community <tinklefund@gmail.com> * feat: add PostgreSQL data viewing utility script - Create view_pg_data.sh for easy database data inspection - Display table record counts, AI models, exchanges, and system config - Include beta codes and user statistics - Auto-detect docker-compose vs docker compose commands 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: tinkle-community <tinklefund@gmail.com> * fix(api): query actual exchange balance when creating trader Problem: - Users could input arbitrary initial balance when creating traders - This didn't reflect the actual available balance in exchange account - Could lead to incorrect position sizing and risk calculations Solution: - Before creating trader, query exchange API for actual balance - Use GetBalance() from respective trader implementation: * Binance: NewFuturesTrader + GetBalance() * Hyperliquid: NewHyperliquidTrader + GetBalance() * Aster: NewAsterTrader + GetBalance() - Extract 'available_balance' or 'balance' from response - Override user input with actual balance - Fallback to user input if query fails Changes: - Added 'nofx/trader' import - Query GetExchanges() to find matching exchange config - Create temporary trader instance based on exchange type - Call GetBalance() to fetch actual available balance - Use actualBalance instead of req.InitialBalance - Comprehensive error handling with fallback logic Benefits: - ✅ Ensures accurate initial balance matches exchange account - ✅ Prevents user errors in balance input - ✅ Improves position sizing accuracy - ✅ Maintains data integrity between system and exchange Example logs: ✓ 查询到交易所实际余额: 150.00 USDT (用户输入: 100.00 USDT) ⚠️ 查询交易所余额失败,使用用户输入的初始资金: connection timeout 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: tinkle-community <tinklefund@gmail.com> * fix(api): correct variable name from traderRecord to trader Fixed compilation error caused by variable name mismatch: - Line 404: defined as 'trader' - Line 425: was using 'traderRecord' (undefined) This aligns with upstream dev branch naming convention. * feat: 添加部分平仓和动态止盈止损功能 新增功能: - update_stop_loss: 调整止损价格(追踪止损) - update_take_profit: 调整止盈价格(技术位优化) - partial_close: 部分平仓(分批止盈) 实现细节: - Decision struct 新增字段:NewStopLoss, NewTakeProfit, ClosePercentage - 新增执行函数:executeUpdateStopLossWithRecord, executeUpdateTakeProfitWithRecord, executePartialCloseWithRecord - 修复持仓字段获取 bug(使用 "side" 并转大写) - 更新 adaptive.txt 文档,包含详细使用示例和策略建议 - 优先级排序:平仓 > 调整止盈止损 > 开仓 命名统一: - 与社区 PR #197 保持一致,使用 update_* 而非 adjust_* - 独有功能:partial_close(部分平仓) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: tinkle-community <tinklefund@gmail.com> * 修復關鍵 BUG:validActions 缺少新動作導致驗證失敗 問題根因: - auto_trader.go 已實現 update_stop_loss/update_take_profit/partial_close 處理 - adaptive.txt 已描述這些功能 - 但 validateDecision 的 validActions map 缺少這三個動作 - 導致 AI 生成的決策在驗證階段被拒絕:「无效的action:update_stop_loss」 修復內容: 1. validActions 添加三個新動作 2. 為每個新動作添加參數驗證: - update_stop_loss: 驗證 NewStopLoss > 0 - update_take_profit: 驗證 NewTakeProfit > 0 - partial_close: 驗證 ClosePercentage 在 0-100 之間 3. 修正註釋:adjust_* → update_* 測試狀態:feature 分支,等待測試確認 * 修復關鍵缺陷:添加 CancelStopOrders 方法避免多個止損單共存 問題: - 調整止損/止盈時,直接調用 SetStopLoss/SetTakeProfit 會創建新訂單 - 但舊的止損/止盈單仍然存在,導致多個訂單共存 - 可能造成意外觸發或訂單衝突 解決方案(參考 PR #197): 1. 在 Trader 接口添加 CancelStopOrders 方法 2. 為三個交易所實現: - binance_futures.go: 過濾 STOP_MARKET/TAKE_PROFIT_MARKET 類型 - aster_trader.go: 同樣邏輯 - hyperliquid_trader.go: 過濾 trigger 訂單(有 triggerPx) 3. 在 executeUpdateStopLossWithRecord 和 executeUpdateTakeProfitWithRecord 中: - 先調用 CancelStopOrders 取消舊單 - 然後設置新止損/止盈 - 取消失敗不中斷執行(記錄警告) 優勢: - ✅ 避免多個止損單同時存在 - ✅ 保留我們的價格驗證邏輯 - ✅ 保留執行價格記錄 - ✅ 詳細錯誤信息 - ✅ 取消失敗時繼續執行(更健壯) 測試建議: - 開倉後調整止損,檢查舊止損單是否被取消 - 連續調整兩次,確認只有最新止損單存在 致謝:參考 PR #197 的實現思路 * fix: 修复部分平仓盈利计算错误 问题:部分平仓时,历史记录显示的是全仓位盈利,而非实际平仓部分的盈利 根本原因: - AnalyzePerformance 使用开仓总数量计算部分平仓的盈利 - 应该使用 action.Quantity(实际平仓数量)而非 openPos["quantity"](总数量) 修复: - 添加 actualQuantity 变量区分完整平仓和部分平仓 - partial_close 使用 action.Quantity - 所有相关计算(PnL、PositionValue、MarginUsed)都使用 actualQuantity 影响范围:logger/decision_logger.go:428-465 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: tinkle-community <tinklefund@gmail.com> * fix: 修復 Hyperliquid CancelStopOrders 編譯錯誤 - OpenOrder 結構不暴露 trigger 字段 - 改為取消該幣種的所有掛單(安全做法) * fix: remove unnecessary prompts/adaptive.txt changes - This PR should only contain backend core functionality - prompts/adaptive.txt v2.0 is already in upstream - Prompt enhancements will be in separate PR (Batch 3) * 更新 logger:支持新增的三個動作類型 更新內容: 1. DecisionAction 註釋:添加 update_stop_loss, update_take_profit, partial_close 2. GetStatistics:partial_close 計入 TotalClosePositions 3. AnalyzePerformance 預填充邏輯:處理 partial_close(不刪除持倉記錄) 4. AnalyzePerformance 分析邏輯: - partial_close 正確判斷持倉方向 - 記錄部分平倉的盈虧統計 - 保留持倉記錄(因為還有剩餘倉位) 說明:partial_close 會記錄盈虧,但不刪除 openPositions, 因為還有剩餘倉位可能繼續交易 * refactor(prompts): add comprehensive partial_close guidance to adaptive.txt Add detailed guidance chapter for dynamic TP/SL management and partial close operations. ## Changes - New chapter: "动态止盈止损与部分平仓指引" (Dynamic TP/SL & Partial Close Guidance) - Inserted between "可用动作" (Actions) and "决策流程" (Decision Flow) sections - 4 key guidance points covering: 1. Partial close best practices (use clear percentages like 25%/50%/75%) 2. Reassessing remaining position after partial exit 3. Proper use cases for update_stop_loss / update_take_profit 4. Multi-stage exit strategy requirements ## Benefits - ✅ Provides concrete operational guidelines for AI decision-making - ✅ Clarifies when and how to use partial_close effectively - ✅ Emphasizes remaining position management (prevents "orphan" positions) - ✅ Aligns with existing backend support for partial_close action ## Background While adaptive.txt already lists partial_close as an available action, it lacked detailed operational guidance. This enhancement fills that gap by providing specific percentages, use cases, and multi-stage exit examples. Backend (decision/engine.go) already validates partial_close with close_percentage field, so this is purely a prompt enhancement with no code changes required. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: tinkle-community <tinklefund@gmail.com> * fix(market): resolve price staleness issue in GetCurrentKlines ## Problem GetCurrentKlines had two critical bugs causing price data to become stale: 1. Incorrect return logic: returned error even when data fetch succeeded 2. Race condition: returned slice reference instead of deep copy, causing concurrent data corruption ## Impact - BTC price stuck at 106xxx while actual market price was 107xxx+ - LLM calculated take-profit based on stale prices → orders failed validation - Statistics showed incorrect P&L (0.00%) due to corrupted historical data - Alt-coins filtered out due to failed market data fetch ## Solution 1. Fixed return logic: only return error when actual failure occurs 2. Return deep copy instead of reference to prevent race conditions 3. Downgrade subscription errors to warnings (non-blocking) ## Test Results ✅ Price updates in real-time ✅ Take-profit orders execute successfully ✅ P&L calculations accurate ✅ Alt-coins now tradeable Related: Price feed mechanism, concurrent data access * feat(decision): make OI threshold configurable + add relaxed prompt template ## Changes ### 1. decision/engine.go - Configurable OI Threshold - Extract hardcoded 15M OI threshold to configurable constant - Add clear documentation for risk profiles: - 15M (Conservative) - BTC/ETH/SOL only - 10M (Balanced) - Add major alt-coins - 8M (Relaxed) - Include mid-cap coins (BNB/LINK/AVAX) - 5M (Aggressive) - Most alt-coins allowed - Default: 15M (保守,維持原行為) ### 2. prompts/adaptive_relaxed.txt - New Trading Template Conservative optimization for increased trading frequency while maintaining high win-rate: **Key Adjustments:** - Confidence threshold: 85 → 80 (allow more opportunities) - Cooldown period: 9min → 6min (faster reaction) - Multi-timeframe trend: 3 periods → 2 periods (relaxed requirement) - Entry checklist: 5/8 → 4/8 (easier to pass) - RSI range: 30-40/65-70 → <45/>60 (wider acceptance) - Risk-reward ratio: 1:3 → 1:2.5 (more flexible) **Expected Impact:** - Trading frequency: 5/day → 8-15/day (+60-200%) - Win-rate: 40% → 50-55% (improved) - Alt-coins: More opportunities unlocked - Risk controls: Preserved (Sharpe-based, loss-pause) ## Usage Users can now choose trading style via Web UI: - `adaptive` - Strictest (original) - `adaptive_relaxed` - Balanced (this PR) - `nof1` - Most aggressive ## Rationale The original adaptive.txt uses 5-layer filtering (confidence/cooldown/trend/checklist/RSI) that filters out ~95% of opportunities. This template provides a middle-ground option for users who want higher frequency without sacrificing core risk management. Related: #trading-frequency #alt-coin-support * fix: 过滤幽灵持仓 - 跳过 quantity=0 的持仓防止 AI 误判 问题: - 止损/止盈触发后,交易所返回 positionAmt=0 的持仓记录 - 这些幽灵持仓被传递给 AI,导致 AI 误以为仍持有该币种 - AI 可能基于错误信息做出决策(如尝试调整已不存在的止损) 修复: - buildTradingContext() 中添加 quantity==0 检查 - 跳过已平仓的持仓,确保只传递真实持仓给 AI - 触发清理逻辑:撤销孤儿订单、清理内部状态 影响范围: - trader/auto_trader.go:487-490 测试: - 编译成功 - 容器重建并启动正常 * fix: 添加 HTTP/2 stream error 到可重試錯誤列表 問題: - 用戶遇到錯誤:stream error: stream ID 1; INTERNAL_ERROR - 這是 HTTP/2 連接被服務端關閉的錯誤 - 當前重試機制不包含此類錯誤,導致直接失敗 修復: - 添加 "stream error" 到可重試列表 - 添加 "INTERNAL_ERROR" 到可重試列表 - 遇到此類錯誤時會自動重試(最多 3 次) 影響: - 提高 API 調用穩定性 - 自動處理服務端臨時故障 - 減少因網絡波動導致的失敗 * fix: 修復首次運行時數據庫初始化失敗問題 問題: - 用戶首次運行報錯:unable to open database file: is a directory - 原因:Docker volume 掛載時,如果 config.db 不存在,會創建目錄而非文件 - 影響:新用戶無法正常啟動系統 修復: - 在 start.sh 啟動前檢查 config.db 是否存在 - 如不存在則創建空文件(touch config.db) - 確保 Docker 掛載為文件而非目錄 測試: - 首次運行:./start.sh start → 正常初始化 ✓ - 現有用戶:無影響,向後兼容 ✓ * fix: 修復初始余額顯示錯誤(使用當前淨值而非配置值) 問題: - 圖表顯示「初始余額 693.15 USDT」(實際應該是 600) - 原因:使用 validHistory[0].total_equity(當前淨值) - 導致初始余額隨著盈虧變化,數學邏輯錯誤 修復: - 優先從 account.initial_balance 讀取真實配置值 - 備選方案:從歷史數據反推(淨值 - 盈虧) - 默認值使用 1000(與創建交易員時的默認配置一致) 測試: - 初始余額:600 USDT(固定) - 當前淨值:693.15 USDT - 盈虧:+93.15 USDT (+15.52%) ✓ * fix: 統一 handleTraderList 返回完整 AI model ID(保持與 handleGetTraderConfig 一致) 問題: - handleTraderList 仍在截斷 AI model ID (admin_deepseek → deepseek) - 與 handleGetTraderConfig 返回的完整 ID 不一致 - 導致前端 isModelInUse 檢查失效 修復: - 移除 handleTraderList 中的截斷邏輯 - 返回完整 AIModelID (admin_deepseek) - 與其他 API 端點保持一致 測試: - GET /api/traders → ai_model: admin_deepseek ✓ - GET /api/traders/:id → ai_model: admin_deepseek ✓ - 模型使用檢查邏輯正確 ✓ * chore: upgrade sqlite3 to v1.14.22 for Alpine Linux compatibility - Fix compilation error on Alpine: off64_t type not defined in v1.14.16 - Remove unused pure-Go sqlite implementation (modernc.org/sqlite) and its dependencies - v1.14.22 is the first version fixing Alpine/musl build issues (2024-02-02) - Minimizes version jump (v1.14.16 → v1.14.22, 18 commits) to reduce risk Reference: https://github.com/mattn/go-sqlite3/issues/1164 Verified: Builds successfully on golang:1.25-alpine * chore: run go fmt to fix formatting issues * fix(margin): correct position sizing formula to prevent insufficient margin errors ## Problem AI was calculating position_size_usd incorrectly, treating it as margin requirement instead of notional value, causing code=-2019 errors (insufficient margin). ## Solution ### 1. Updated AI prompts with correct formula - **prompts/adaptive.txt**: Added clear position sizing calculation steps - **prompts/nof1.txt**: Added English version with example - **prompts/default.txt**: Added Chinese version with example **Correct formula:** 1. Available Margin = Available Cash × 0.95 × Allocation % (reserve 5% for fees) 2. Notional Value = Available Margin × Leverage 3. position_size_usd = Notional Value (this is the value for JSON) **Example:** $500 cash, 5x leverage → position_size_usd = $2,375 (not $500) ### 2. Added code-level validation - **trader/auto_trader.go**: Added margin checks in executeOpenLong/ShortWithRecord - Validates required margin + fees ≤ available balance before opening position - Returns clear error message if insufficient ## Impact - Prevents code=-2019 errors - AI now understands the difference between notional value and margin requirement - Double validation: AI prompt + code check ## Testing - ✅ Compiles successfully - ⚠️ Requires live trading environment testing * fix(stats): aggregate partial closes into single trade for accurate statistics ## Problem Multiple partial_close actions on the same position were being counted as separate trades, inflating TotalTrades count and distorting win rate/profit factor statistics. **Example of bug:** - Open 1 BTC @ $100,000 - Partial close 30% @ $101,000 → Counted as trade #1 ❌ - Partial close 50% @ $102,000 → Counted as trade #2 ❌ - Close remaining 20% @ $103,000 → Counted as trade #3 ❌ - **Result:** 3 trades instead of 1 ❌ ## Solution ### 1. Added tracking fields to openPositions map - `remainingQuantity`: Tracks remaining position size - `accumulatedPnL`: Accumulates PnL from all partial closes - `partialCloseCount`: Counts number of partial close operations - `partialCloseVolume`: Total volume closed partially ### 2. Modified partial_close handling logic - Each partial_close: - Accumulates PnL into `accumulatedPnL` - Reduces `remainingQuantity` - **Does NOT increment TotalTrades++** - Keeps position in openPositions map - Only when `remainingQuantity <= 0.0001`: - Records ONE TradeOutcome with aggregated PnL - Increments TotalTrades++ once - Removes from openPositions map ### 3. Updated full close handling - If position had prior partial closes: - Adds `accumulatedPnL` to final close PnL - Reports total PnL in TradeOutcome ### 4. Fixed GetStatistics() - Removed `partial_close` from TotalClosePositions count - Only `close_long/close_short/auto_close` count as close operations ## Impact - ✅ Statistics now accurate: multiple partial closes = 1 trade - ✅ Win rate calculated correctly - ✅ Profit factor reflects true performance - ✅ Backward compatible: handles positions without tracking fields ## Testing - ✅ Compiles successfully - ⚠️ Requires validation with live partial_close scenarios ## Code Changes ``` logger/decision_logger.go: - Lines 420-430: Add tracking fields to openPositions - Lines 441-534: Implement partial_close aggregation logic - Lines 536-593: Update full close to include accumulated PnL - Lines 246-250: Fix GetStatistics() to exclude partial_close ``` * fix(ui): prevent system_prompt_template overwrite when value is empty string ## Problem When editing trader configuration, if `system_prompt_template` was set to an empty string (""), the UI would incorrectly treat it as falsy and overwrite it with 'default', losing the user's selection. **Root cause:** ```tsx if (traderData && !traderData.system_prompt_template) { // ❌ This triggers for both undefined AND empty string "" setFormData({ system_prompt_template: 'default' }); } ``` JavaScript falsy values that trigger `!` operator: - `undefined` ✅ Should trigger default - `null` ✅ Should trigger default - `""` ❌ Should NOT trigger (user explicitly chose empty) - `false`, `0`, `NaN` (less relevant here) ## Solution Change condition to explicitly check for `undefined`: ```tsx if (traderData && traderData.system_prompt_template === undefined) { // ✅ Only triggers for truly missing field setFormData({ system_prompt_template: 'default' }); } ``` ## Impact - ✅ Empty string selections are preserved - ✅ Legacy data (undefined) still gets default value - ✅ User's explicit choices are respected - ✅ No breaking changes to existing functionality ## Testing - ✅ Code compiles - ⚠️ Requires manual UI testing: - [ ] Edit trader with empty system_prompt_template - [ ] Verify it doesn't reset to 'default' - [ ] Create new trader → should default to 'default' - [ ] Edit old trader (undefined field) → should default to 'default' ## Code Changes ``` web/src/components/TraderConfigModal.tsx: - Line 99: Changed !traderData.system_prompt_template → === undefined ``` * fix(trader): add missing HyperliquidTestnet configuration in loadSingleTrader 修复了 loadSingleTrader 函数中缺失的 HyperliquidTestnet 配置项, 确保 Hyperliquid 交易所的测试网配置能够正确传递到 trader 实例。 Changes: - 在 loadSingleTrader 中添加 HyperliquidTestnet 字段配置 - 代码格式优化(空格对齐) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: tinkle-community <tinklefund@gmail.com> * fix(trader): separate stop-loss and take-profit order cancellation to prevent accidental deletions ## Problem When adjusting stop-loss or take-profit levels, `CancelStopOrders()` deleted BOTH stop-loss AND take-profit orders simultaneously, causing: - **Adjusting stop-loss** → Take-profit order deleted → Position has no exit plan ❌ - **Adjusting take-profit** → Stop-loss order deleted → Position unprotected ❌ **Root cause:** ```go CancelStopOrders(symbol) { // Cancelled ALL orders with type STOP_MARKET or TAKE_PROFIT_MARKET // No distinction between stop-loss and take-profit } ``` ## Solution ### 1. Added new interface methods (trader/interface.go) ```go CancelStopLossOrders(symbol string) error // Only cancel stop-loss orders CancelTakeProfitOrders(symbol string) error // Only cancel take-profit orders CancelStopOrders(symbol string) error // Deprecated (cancels both) ``` ### 2. Implemented for all 3 exchanges **Binance (trader/binance_futures.go)**: - `CancelStopLossOrders`: Filters `OrderTypeStopMarket | OrderTypeStop` - `CancelTakeProfitOrders`: Filters `OrderTypeTakeProfitMarket | OrderTypeTakeProfit` - Full order type differentiation ✅ **Hyperliquid (trader/hyperliquid_trader.go)**: - ⚠️ Limitation: SDK's OpenOrder struct doesn't expose trigger field - Both methods call `CancelStopOrders` (cancels all pending orders) - Trade-off: Safe but less precise **Aster (trader/aster_trader.go)**: - `CancelStopLossOrders`: Filters `STOP_MARKET | STOP` - `CancelTakeProfitOrders`: Filters `TAKE_PROFIT_MARKET | TAKE_PROFIT` - Full order type differentiation ✅ ### 3. Usage in auto_trader.go When `update_stop_loss` or `update_take_profit` actions are implemented, they will use: ```go // update_stop_loss: at.trader.CancelStopLossOrders(symbol) // Only cancel SL, keep TP at.trader.SetStopLoss(...) // update_take_profit: at.trader.CancelTakeProfitOrders(symbol) // Only cancel TP, keep SL at.trader.SetTakeProfit(...) ``` ## Impact - ✅ Adjusting stop-loss no longer deletes take-profit - ✅ Adjusting take-profit no longer deletes stop-loss - ✅ Backward compatible: `CancelStopOrders` still exists (deprecated) - ⚠️ Hyperliquid limitation: still cancels all orders (SDK constraint) ## Testing - ✅ Compiles successfully across all 3 exchanges - ⚠️ Requires live testing: - [ ] Binance: Adjust SL → verify TP remains - [ ] Binance: Adjust TP → verify SL remains - [ ] Hyperliquid: Verify behavior with limitation - [ ] Aster: Verify order filtering works correctly ## Code Changes ``` trader/interface.go: +9 lines (new interface methods) trader/binance_futures.go: +133 lines (3 new functions) trader/hyperliquid_trader.go: +56 lines (3 new functions) trader/aster_trader.go: +157 lines (3 new functions) Total: +355 lines ``` * fix(binance): initialize dual-side position mode to prevent code=-4061 errors ## Problem When opening positions with explicit `PositionSide` parameter (LONG/SHORT), Binance API returned **code=-4061** error: ``` "No need to change position side." "code":-4061 ``` **Root cause:** - Binance accounts default to **single-side position mode** ("One-Way Mode") - In this mode, `PositionSide` parameter is **not allowed** - Code使用了 `PositionSide` 參數 (LONG/SHORT),但帳戶未啟用雙向持倉模式 **Position Mode Comparison:** | Mode | PositionSide Required | Can Hold Long+Short Simultaneously | |------|----------------------|------------------------------------| | One-Way (default) | ❌ No | ❌ No | | Hedge Mode | ✅ **Required** | ✅ Yes | ## Solution ### 1. Added setDualSidePosition() function Automatically enables Hedge Mode during trader initialization: ```go func (t *FuturesTrader) setDualSidePosition() error { err := t.client.NewChangePositionModeService(). DualSide(true). // Enable Hedge Mode Do(context.Background()) if err != nil { // Ignore "No need to change" error (already in Hedge Mode) if strings.Contains(err.Error(), "No need to change position side") { log.Printf("✓ Account already in Hedge Mode") return nil } return err } log.Printf("✓ Switched to Hedge Mode") return nil } ``` ### 2. Called in NewFuturesTrader() Runs automatically when creating trader instance: ```go func NewFuturesTrader(apiKey, secretKey string) *FuturesTrader { trader := &FuturesTrader{...} // Initialize Hedge Mode if err := trader.setDualSidePosition(); err != nil { log.Printf("⚠️ Failed to set Hedge Mode: %v", err) } return trader } ``` ## Impact - ✅ Prevents code=-4061 errors when opening positions - ✅ Enables simultaneous long+short positions (if needed) - ✅ Fails gracefully if account already in Hedge Mode - ⚠️ **One-time change**: Once enabled, cannot revert to One-Way Mode with open positions ## Testing - ✅ Compiles successfully - ⚠️ Requires Binance testnet/mainnet validation: - [ ] First initialization → switches to Hedge Mode - [ ] Subsequent initializations → ignores "No need to change" error - [ ] Open long position with PositionSide=LONG → succeeds - [ ] Open short position with PositionSide=SHORT → succeeds ## Code Changes ``` trader/binance_futures.go: - Line 3-12: Added strings import - Line 33-47: Modified NewFuturesTrader() to call setDualSidePosition() - Line 49-69: New function setDualSidePosition() Total: +25 lines ``` ## References - Binance Futures API: https://binance-docs.github.io/apidocs/futures/en/#change-position-mode-trade - Error code=-4061: "No need to change position side." - PositionSide ENUM: BOTH (One-Way) | LONG | SHORT (Hedge Mode) * fix(prompts): rename actions to match backend implementation ## Problem Backend code expects these action names: - `open_long`, `open_short`, `close_long`, `close_short` But prompts use outdated names: - `buy_to_enter`, `sell_to_enter`, `close` This causes all trading decisions to fail with unknown action errors. ## Solution Minimal changes to fix action name compatibility: ### prompts/nof1.txt - ✅ `buy_to_enter` → `open_long` - ✅ `sell_to_enter` → `open_short` - ✅ `close` → `close_long` / `close_short` - ✅ Explicitly list `wait` action - +18 lines, -6 lines (only action definitions section) ### prompts/adaptive.txt - ✅ `buy_to_enter` → `open_long` - ✅ `sell_to_enter` → `open_short` - ✅ `close` → `close_long` / `close_short` - +15 lines, -6 lines (only action definitions section) ## Impact - ✅ Trading decisions now execute successfully - ✅ Maintains all existing functionality - ✅ No new features added (minimal diff) ## Verification ```bash # Backend expects these actions: grep 'Action string' decision/engine.go # "open_long", "open_short", "close_long", "close_short", ... # Old names removed: grep -r "buy_to_enter\|sell_to_enter" prompts/ # (no results) ``` 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: tinkle-community <tinklefund@gmail.com> * fix(api): add balance sync endpoint with smart detection ## Summary - Add POST /traders/:id/sync-balance endpoint (Option B) - Add smart detection showing balance change percentage (Option C) - Fix balance display bug caused by commit |
||
|
|
5425f6a4ea |
feat(api): add server IP display for exchange whitelist configuration (#520)
Added functionality to display server public IP address for users to configure exchange API whitelists, specifically for Binance integration. Backend changes (api/server.go): - Add GET /api/server-ip endpoint requiring authentication - Implement getPublicIPFromAPI() with fallback to multiple IP services - Implement getPublicIPFromInterface() for local network interface detection - Add isPrivateIP() helper to filter private IP addresses - Import net package for IP address handling Frontend changes (web/): - Add getServerIP() API method in api.ts - Display server IP in ExchangeConfigModal for Binance - Add IP copy-to-clipboard functionality - Load and display server IP when Binance exchange is selected - Add i18n translations (en/zh) for whitelist IP messages: - whitelistIP, whitelistIPDesc, serverIPAddresses - copyIP, ipCopied, loadingServerIP User benefits: - Simplifies Binance API whitelist configuration - Shows exact server IP to add to exchange whitelist - One-click IP copy for convenience 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: tinkle-community <tinklefund@gmail.com> |
||
|
|
f96e8899c6 |
Merge pull request #493 from simonjiang99/fix/3-minutes-minimum
fix(api):enforce minimum scan interval of three minutes |
||
|
|
10c9b678bd |
Merge pull request #428 from zhouyongyou/fix/initial-balance-sync
fix(api): add balance sync endpoint with smart detection |
||
|
|
6f3fb71ac7 | Merge branch 'dev' into fix/bug-fixes-collection-v2 | ||
|
|
fd12a36c01 | Enforce minimum scan interval of three minutes | ||
|
|
c5a4f927a0 | Revert "Beta feat: migrate from SQLite to PostgreSQL + Redis architecture" | ||
|
|
70a6ca777e |
fix(api): add balance sync endpoint with smart detection
## Summary - Add POST /traders/:id/sync-balance endpoint (Option B) - Add smart detection showing balance change percentage (Option C) - Fix balance display bug caused by commit |
||
|
|
b92a1d68ac | chore: run go fmt to fix formatting issues | ||
|
|
02a7eeaffe |
fix: 統一 handleTraderList 返回完整 AI model ID(保持與 handleGetTraderConfig 一致)
問題: - handleTraderList 仍在截斷 AI model ID (admin_deepseek → deepseek) - 與 handleGetTraderConfig 返回的完整 ID 不一致 - 導致前端 isModelInUse 檢查失效 修復: - 移除 handleTraderList 中的截斷邏輯 - 返回完整 AIModelID (admin_deepseek) - 與其他 API 端點保持一致 測試: - GET /api/traders → ai_model: admin_deepseek ✓ - GET /api/traders/:id → ai_model: admin_deepseek ✓ - 模型使用檢查邏輯正確 ✓ |
||
|
|
88d1619036 |
fix(api): correct variable name from traderRecord to trader
Fixed compilation error caused by variable name mismatch: - Line 404: defined as 'trader' - Line 425: was using 'traderRecord' (undefined) This aligns with upstream dev branch naming convention. |
||
|
|
4e86db2e50 |
fix(api): query actual exchange balance when creating trader
Problem: - Users could input arbitrary initial balance when creating traders - This didn't reflect the actual available balance in exchange account - Could lead to incorrect position sizing and risk calculations Solution: - Before creating trader, query exchange API for actual balance - Use GetBalance() from respective trader implementation: * Binance: NewFuturesTrader + GetBalance() * Hyperliquid: NewHyperliquidTrader + GetBalance() * Aster: NewAsterTrader + GetBalance() - Extract 'available_balance' or 'balance' from response - Override user input with actual balance - Fallback to user input if query fails Changes: - Added 'nofx/trader' import - Query GetExchanges() to find matching exchange config - Create temporary trader instance based on exchange type - Call GetBalance() to fetch actual available balance - Use actualBalance instead of req.InitialBalance - Comprehensive error handling with fallback logic Benefits: - ✅ Ensures accurate initial balance matches exchange account - ✅ Prevents user errors in balance input - ✅ Improves position sizing accuracy - ✅ Maintains data integrity between system and exchange Example logs: ✓ 查询到交易所实际余额: 150.00 USDT (用户输入: 100.00 USDT) ⚠️ 查询交易所余额失败,使用用户输入的初始资金: connection timeout 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: tinkle-community <tinklefund@gmail.com> |
||
|
|
22c2cfdede |
feat: migrate from SQLite to PostgreSQL + Redis architecture
Major database migration to modernize the AI trading system:
• **Database Migration**:
- Add PostgreSQL 15 and Redis 7 services to docker-compose
- Create comprehensive PostgreSQL schema with proper indexes and triggers
- Implement DatabaseInterface for multi-database support
- Add automatic environment-based database selection
• **Infrastructure**:
- PostgreSQL: ACID transactions, better concurrency, JSON support
- Redis: High-performance caching layer (prepared for future use)
- Docker services with health checks and dependency management
- Persistent volumes for data safety
• **Code Refactoring**:
- Abstract database operations through DatabaseInterface
- Implement PostgreSQL-specific operations with proper syntax
- Update all SQL queries to support both SQLite and PostgreSQL
- Fix foreign key constraints and data type conversions
• **Migration Tools**:
- Automated data migration script from SQLite to PostgreSQL
- Complete backup and restore procedures
- One-click migration script with validation
• **Compatibility**:
- Backward compatible with existing SQLite deployments
- Environment variable driven database selection
- Preserved all existing functionality and data
🎯 Benefits: Better performance, scalability, and reliability for production deployments
|
||
|
|
0887f0abd1 |
Resolve merge conflicts with dev branch
Resolved conflicts in: - api/server.go: Preserved beta_mode config and user permission checks - manager/trader_manager.go: Kept optimized concurrent competition data with caching Maintained all performance optimizations while merging new features from dev. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: tinkle-community <tinklefund@gmail.com> |
||
|
|
815c71b2a2 |
Merge branch 'dev' of https://github.com/tinkle-community/nofx into dev
# Conflicts: # api/server.go |
||
|
|
febf7f5f33 | style(backend): go fmt code | ||
|
|
5dbcfeb132 |
Optimize /api/competition endpoint performance with concurrent data fetching and caching
## Performance Improvements: - **Concurrent Processing**: Replace serial GetAccountInfo() calls with parallel goroutines - **Timeout Control**: Add 3-second timeout per trader to prevent blocking - **30-second Cache**: Implement competition data cache to reduce API calls - **Error Handling**: Graceful degradation when API calls fail or timeout ## API Changes: - Reduce top traders from 10 to 5 for better chart performance - Update /api/equity-history-batch to use top 5 traders by default - Add detailed logging for cache hits and performance monitoring ## Expected Performance Gains: - First request: ~85% faster (from 25s to 3s for 50 traders) - Cached requests: ~99.96% faster (from 25s to 10ms) - Better user experience with consistent response times 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: tinkle-community <tinklefund@gmail.com> |
||
|
|
9130f439f8 |
Fix equity-history-batch API to support POST JSON requests
- Change route from GET to POST for equity-history-batch endpoint - Update handleEquityHistoryBatch to parse JSON body from POST requests - Maintain backward compatibility with GET query parameters - Ensure public access without authentication as required 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: tinkle-community <tinklefund@gmail.com> |
||
|
|
0690233b7f |
Merge dev branch with conflict resolution
- Resolve TypeScript interface formatting conflict in CommunitySection.tsx - Include updates from dev branch 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: tinkle-community <tinklefund@gmail.com> |