Skip to content

Conversation

@the-dev-z
Copy link
Collaborator

問題描述

Issue #998: Aster 交易所重複止損/止盈掛單問題。

根本原因: AI 在決策時缺少未成交訂單信息,無法判斷止損/止盈單是否已存在,導致重複發送 update_stop_loss 指令,超出交易所訂單數量限制。

解決方案

將未成交訂單信息添加到 AI 決策上下文,使 AI 能夠:

  • 看到已存在的止損/止盈訂單
  • 避免發送重複的訂單指令
  • 識別缺少止損保護的持倉

主要變更

1. 定義 OpenOrderInfo 結構 (decision/engine.go)

  • 包含訂單詳細信息:symbol, orderID, type, side, quantity, stopPrice
  • 放置在 decision 包以避免循環導入

2. 實現 GetOpenOrders() 方法

  • AsterTrader: 完整實現,調用 /fapi/v3/openOrders API
  • BinanceTrader/HyperliquidTrader: 空實現,返回空列表(待後續補充)
  • Trader 接口: 添加方法簽名

3. 更新決策上下文

  • Context.OpenOrders: 添加未成交訂單列表
  • buildTradingContext(): 獲取訂單並添加到上下文
  • 錯誤處理: 獲取失敗時使用空列表,不阻塞主流程

4. 更新 AI Prompt

  • buildUserPrompt(): 在每個持倉下方顯示訂單狀態
    • 🛡️ 止損單
    • 🎯 止盈單
    • ⚠️ 警告(缺少止損保護時)
  • buildSystemPrompt(): 添加「未成交掛單提醒」章節
    • 說明訂單圖標含義
    • 提醒 AI 不要重複下單

技術細節

避免循環依賴

  • OpenOrderInfo 定義在 decision 包(而非 trader 包)
  • 避免 traderdecision 循環導入

錯誤容錯

  • GetOpenOrders 失敗時記錄警告但不中斷流程
  • 使用空列表確保 AI 仍能正常決策

日誌記錄

  • 顯示獲取到的訂單數量,方便調試

測試結果

  • ✅ decision 包測試通過 (0.941s)
  • ✅ trader 包測試通過 (16.649s)
  • ✅ 無循環依賴錯誤
  • ✅ 代碼已使用 gofmt 格式化

預期效果

  • ✅ AI 能看到已有止損/止盈單,避免重複下單
  • ✅ AI 能識別缺少止損的持倉,主動提醒設置
  • ✅ 更智能的交易決策(完整上下文)
  • ✅ 符合「給 AI 完整信息」的設計理念

後續工作

  • 為 Binance Futures 實現完整的 GetOpenOrders()
  • 為 Hyperliquid 實現完整的 GetOpenOrders()
  • 生產環境測試以驗證重複訂單防護效果

Fixes #998

🤖 Generated with Claude Code

Co-Authored-By: Claude [email protected]

SkywalkerJi and others added 30 commits November 4, 2025 13:00
Merge pull request NoFxAiOS#395 from NoFxAiOS/beta
fix:fix the main branch history issue from November 3rd.
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: Claude <[email protected]>
- 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: Claude <[email protected]>
 feat: Add Binance setup guide with tutorial modal
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: Claude <[email protected]>
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.
新增功能:
- update_stop_loss: 调整止损价格(追踪止损)
- update_take_profit: 调整止盈价格(技术位优化)
- partial_close: 部分平仓(分批止盈)

实现细节:
- Decision struct 新增字段:NewStopLoss, NewTakeProfit, ClosePercentage
- 新增执行函数:executeUpdateStopLossWithRecord, executeUpdateTakeProfitWithRecord, executePartialCloseWithRecord
- 修复持仓字段获取 bug(使用 "side" 并转大写)
- 更新 adaptive.txt 文档,包含详细使用示例和策略建议
- 优先级排序:平仓 > 调整止盈止损 > 开仓

命名统一:
- 与社区 PR NoFxAiOS#197 保持一致,使用 update_* 而非 adjust_*
- 独有功能:partial_close(部分平仓)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
問題根因:
- 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 分支,等待測試確認
問題:
- 調整止損/止盈時,直接調用 SetStopLoss/SetTakeProfit 會創建新訂單
- 但舊的止損/止盈單仍然存在,導致多個訂單共存
- 可能造成意外觸發或訂單衝突

解決方案(參考 PR NoFxAiOS#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 NoFxAiOS#197 的實現思路
问题:部分平仓时,历史记录显示的是全仓位盈利,而非实际平仓部分的盈利

根本原因:
- 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: Claude <[email protected]>
- OpenOrder 結構不暴露 trigger 字段
- 改為取消該幣種的所有掛單(安全做法)
- 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)
更新內容:
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,
      因為還有剩餘倉位可能繼續交易
…ve.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: Claude <[email protected]>
## 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
…emplate

## 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
问题:
- 止损/止盈触发后,交易所返回 positionAmt=0 的持仓记录
- 这些幽灵持仓被传递给 AI,导致 AI 误以为仍持有该币种
- AI 可能基于错误信息做出决策(如尝试调整已不存在的止损)

修复:
- buildTradingContext() 中添加 quantity==0 检查
- 跳过已平仓的持仓,确保只传递真实持仓给 AI
- 触发清理逻辑:撤销孤儿订单、清理内部状态

影响范围:
- trader/auto_trader.go:487-490

测试:
- 编译成功
- 容器重建并启动正常
問題:
- 用戶遇到錯誤:stream error: stream ID 1; INTERNAL_ERROR
- 這是 HTTP/2 連接被服務端關閉的錯誤
- 當前重試機制不包含此類錯誤,導致直接失敗

修復:
- 添加 "stream error" 到可重試列表
- 添加 "INTERNAL_ERROR" 到可重試列表
- 遇到此類錯誤時會自動重試(最多 3 次)

影響:
- 提高 API 調用穩定性
- 自動處理服務端臨時故障
- 減少因網絡波動導致的失敗
問題:
- 用戶首次運行報錯:unable to open database file: is a directory
- 原因:Docker volume 掛載時,如果 config.db 不存在,會創建目錄而非文件
- 影響:新用戶無法正常啟動系統

修復:
- 在 start.sh 啟動前檢查 config.db 是否存在
- 如不存在則創建空文件(touch config.db)
- 確保 Docker 掛載為文件而非目錄

測試:
- 首次運行:./start.sh start → 正常初始化 ✓
- 現有用戶:無影響,向後兼容 ✓
問題:
- 圖表顯示「初始余額 693.15 USDT」(實際應該是 600)
- 原因:使用 validHistory[0].total_equity(當前淨值)
- 導致初始余額隨著盈虧變化,數學邏輯錯誤

修復:
- 優先從 account.initial_balance 讀取真實配置值
- 備選方案:從歷史數據反推(淨值 - 盈虧)
- 默認值使用 1000(與創建交易員時的默認配置一致)

測試:
- 初始余額:600 USDT(固定)
- 當前淨值:693.15 USDT
- 盈虧:+93.15 USDT (+15.52%) ✓
問題:
- 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 ✓
- 模型使用檢查邏輯正確 ✓
- 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: mattn/go-sqlite3#1164
Verified: Builds successfully on golang:1.25-alpine
…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
…tatistics

## 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
```
… 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
```
0xEmberZz and others added 15 commits November 12, 2025 21:54
Remove duplicate password validation logic to ensure consistency.

Changes:
- Remove custom isStrongPassword function (RegisterPage.tsx:569-576)
- Use PasswordChecklist validation result (passwordValid state) instead
- Add comprehensive test suite with 28 test cases
- Configure Vitest with jsdom environment and setup file

Test Coverage:
- Password validation rules (length, uppercase, lowercase, number, special chars)
- Special character consistency (/[@#$%!&*?]/)
- Edge cases and boundary conditions
- Refactoring consistency verification

All 78 tests passing (25 + 25 + 28).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude <[email protected]>
* 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)
* feat(dashboard): display system prompt template and extract color constant

* style(api): format server.go with go fmt
* fix(trader): get peakPnlPct using posKey

* fix(docs): keep readme at the same page

---------

Co-authored-by: zbhan <[email protected]>
…OS#879)

* fix(api): market/combined_streams: Get Proxy form Environment

issues:
❌ 批量订阅流失败: 组合流WebSocket连接失败: dial tcp xxxxxx:443: i/o timeout

Make environment variables effective for
dialer.Dial("wss://fstream.binance.com/stream", nil):

export HTTPS_PROXY=http://ip:port
export HTTP_PROXY=http://ip:port

Signed-off-by: MarsDoge <[email protected]>

* docs(WebSocket): add proxy usage guidance for combined streams (NoFxAiOS#475)

Signed-off-by: MarsDoge <[email protected]>

---------

Signed-off-by: MarsDoge <[email protected]>
…ons (NoFxAiOS#989)

## Problem
When creating/editing/deleting traders, AI models, or exchanges, the UI
takes 3-4 seconds to show results, causing users to think the system is frozen.

## Root Cause
Although mutateTraders() was called after operations, it was not awaited,
causing the function to continue immediately without waiting for data refresh.
The UI relied on the refreshInterval: 5000 automatic refresh, resulting in
up to 5 seconds of delay.

## Solution
Added await before all mutateTraders() calls to ensure data is refreshed
before closing modals or showing success messages.

Changes:
- handleCreateTrader: Added await before mutateTraders()
- handleSaveEditTrader: Added await before mutateTraders()
- handleDeleteTrader: Added await before mutateTraders()
- handleToggleTrader: Added await before mutateTraders()

Impact:
- From 3-4s delay to immediate display (< 500ms)
- Significantly improved UX
- Consistent with AI model and exchange config behavior

Testing:
- Frontend build successful
- No TypeScript errors
- Ready for manual UI testing

Co-authored-by: the-dev-z <[email protected]>
…oFxAiOS#994)

* fix(trader): get peakPnlPct using posKey

* fix(docs): keep readme at the same page

* improve(interface): replace with interface

* refactor mcp

---------

Co-authored-by: zbhan <[email protected]>
…S#997)

修复了token过期后页面一直遇到401错误、无法自动跳转登录页的问题

主要改动:
1. httpClient.ts
   - 去掉延迟跳转的setTimeout,改为立即跳转
   - 返回pending promise阻止SWR捕获401错误
   - 保存from401标记到sessionStorage,由登录页显示提示

2. LoginPage.tsx
   - 检测from401标记,显示"登录已过期"提示(永久显示)
   - 在登录成功时手动关闭过期提示toast
   - 支持管理员登录、普通登录、OTP验证三种场景

3. TraderConfigModal.tsx
   - 修复3处直接使用fetch()的问题,改为httpClient.get()
   - 确保所有API请求都经过统一的401拦截器

4. translations.ts
   - 添加sessionExpired的中英文翻译

修复效果:
- token过期时立即跳转登录页(无延迟)
- 登录页持续显示过期提示,直到用户登录成功或手动关闭
- 不会再看到401错误页面或重复的错误提示

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude <[email protected]>
…ders (NoFxAiOS#998)

## Problem

Issue NoFxAiOS#998: Aster exchange duplicate stop-loss/take-profit orders.
Root cause: AI lacks context about existing orders, causing repeated
`update_stop_loss` commands that exceed exchange order limits.

## Solution

Add open order information to AI decision context, enabling the AI to:
- See existing stop-loss/take-profit orders
- Avoid sending duplicate order commands
- Identify positions missing stop-loss protection

## Changes

1. **Define OpenOrderInfo struct** (decision/engine.go)
   - Contains order details: symbol, orderID, type, side, quantity, stopPrice
   - Placed in decision package to avoid circular imports

2. **Implement GetOpenOrders() method**
   - AsterTrader: Full implementation calling /fapi/v3/openOrders API
   - BinanceTrader/HyperliquidTrader: Stub implementations returning empty list
   - Trader interface: Added method signature

3. **Update decision context**
   - Context.OpenOrders: Added open orders list
   - buildTradingContext(): Fetches orders and adds to context
   - Error handling: Uses empty list on failure, doesn't block main flow

4. **Update AI prompts**
   - buildUserPrompt(): Displays orders under each position
     - 🛡️ for stop-loss orders
     - 🎯 for take-profit orders
     - ⚠️ warning if no stop-loss protection
   - buildSystemPrompt(): Added "Open Orders Reminder" section
     - Explains order status icons
     - Warns AI not to duplicate orders

## Testing

- ✅ decision package tests pass (0.941s)
- ✅ trader package tests pass (16.649s)
- ✅ No circular import errors
- ✅ Code formatted with gofmt

## Follow-up

- [ ] Implement full GetOpenOrders() for Binance Futures
- [ ] Implement full GetOpenOrders() for Hyperliquid
- [ ] Production testing to verify duplicate order prevention

Fixes NoFxAiOS#998

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
@github-actions
Copy link

🤖 Advisory Check Results

These are advisory checks to help improve code quality. They won't block your PR from being merged.

📋 PR Information

Title Format: ✅ Good - Follows Conventional Commits
PR Size: 🟢 Small (142 lines: +141 -1)

🔧 Backend Checks

Go Formatting: ✅ Good
Go Vet: ✅ Good
Tests: ✅ Passed

Fix locally:

go fmt ./...      # Format code
go vet ./...      # Check for issues
go test ./...     # Run tests

⚛️ Frontend Checks

Build & Type Check: ✅ Success

Fix locally:

cd web
npm run build  # Test build (includes type checking)

📖 Resources

Questions? Feel free to ask in the comments! 🙏


These checks are advisory and won't block your PR from being merged. This comment is automatically generated from pr-checks-run.yml.

@cla-assistant
Copy link

cla-assistant bot commented Dec 22, 2025

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you all sign our Contributor License Agreement before we can accept your contribution.
1 out of 13 committers have signed the CLA.

✅ tinkle-community
❌ tinkle
❌ CoderMageFox
❌ deloz
❌ xqliu
❌ Im-Sue
❌ the-dev-z
❌ hzb1115
❌ 0xEmberZz
❌ tangmengqiu
❌ ljh740
❌ zpng
❌ MarsDoge


tinkle seems not to be a GitHub user. You need a GitHub account to be able to sign the CLA. If you have already a GitHub account, please add the email address used for this commit to your account.
You have signed the CLA already but the status is still pending? Let us recheck it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

aster 移动止损 bug