Commit Graph

568 Commits

Author SHA1 Message Date
ZhouYongyou
c8f72bcc78 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 2b9c4d2
## Changes
### api/server.go
- Add handleSyncBalance() handler
- Query actual exchange balance via trader.GetBalance()
- Calculate change percentage for smart detection
- Update initial_balance in database
- Reload trader into memory after update
### config/database.go
- Add UpdateTraderInitialBalance() method
- Update traders.initial_balance field
## Root Cause
Commit 2b9c4d2 auto-queries exchange balance at trader creation time,
but never updates after user deposits more funds, causing:
- Wrong initial_balance (400 USDT vs actual 3000 USDT)
- Wrong P&L calculations (-2598.55 USDT instead of actual)
## Solution
Provides manual sync API + smart detection to update initial_balance
when user deposits funds after trader creation.
Co-Authored-By: tinkle-community <tinklefund@gmail.com>
2025-11-04 19:55:16 +08:00
ZhouYongyou
f99052e780 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)
```
Co-Authored-By: tinkle-community <tinklefund@gmail.com>
2025-11-04 19:41:23 +08:00
ZhouYongyou
324ed50b92 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)
2025-11-04 19:07:58 +08:00
ZhouYongyou
c9d5aed1b6 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
```
2025-11-04 19:05:54 +08:00
sue
616c350835 fix(trader): add missing HyperliquidTestnet configuration in loadSingleTrader
修复了 loadSingleTrader 函数中缺失的 HyperliquidTestnet 配置项,
确保 Hyperliquid 交易所的测试网配置能够正确传递到 trader 实例。
Changes:
- 在 loadSingleTrader 中添加 HyperliquidTestnet 字段配置
- 代码格式优化(空格对齐)
Co-Authored-By: tinkle-community <tinklefund@gmail.com>
2025-11-04 19:02:39 +08:00
ZhouYongyou
841cd2d277 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
```
2025-11-04 19:00:23 +08:00
ZhouYongyou
21ae77e7cc 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
```
2025-11-04 18:58:20 +08:00
ZhouYongyou
4e6b868531 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
2025-11-04 18:44:07 +08:00
ZhouYongyou
1e8746e692 chore: run go fmt to fix formatting issues 2025-11-04 17:39:00 +08:00
ZhouYongyou
dc44bc9a1b 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
2025-11-04 17:35:53 +08:00
ZhouYongyou
4d54a4704c 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 ✓
- 模型使用檢查邏輯正確 ✓
2025-11-04 17:35:34 +08:00
ZhouYongyou
96d59e6241 fix: 修復初始余額顯示錯誤(使用當前淨值而非配置值)
問題:
- 圖表顯示「初始余額 693.15 USDT」(實際應該是 600)
- 原因:使用 validHistory[0].total_equity(當前淨值)
- 導致初始余額隨著盈虧變化,數學邏輯錯誤
修復:
- 優先從 account.initial_balance 讀取真實配置值
- 備選方案:從歷史數據反推(淨值 - 盈虧)
- 默認值使用 1000(與創建交易員時的默認配置一致)
測試:
- 初始余額:600 USDT(固定)
- 當前淨值:693.15 USDT
- 盈虧:+93.15 USDT (+15.52%) ✓
2025-11-04 17:35:26 +08:00
ZhouYongyou
7b43fc4072 fix: 修復首次運行時數據庫初始化失敗問題
問題:
- 用戶首次運行報錯:unable to open database file: is a directory
- 原因:Docker volume 掛載時,如果 config.db 不存在,會創建目錄而非文件
- 影響:新用戶無法正常啟動系統
修復:
- 在 start.sh 啟動前檢查 config.db 是否存在
- 如不存在則創建空文件(touch config.db)
- 確保 Docker 掛載為文件而非目錄
測試:
- 首次運行:./start.sh start → 正常初始化 ✓
- 現有用戶:無影響,向後兼容 ✓
2025-11-04 17:35:26 +08:00
ZhouYongyou
98b5b20043 fix: 添加 HTTP/2 stream error 到可重試錯誤列表
問題:
- 用戶遇到錯誤:stream error: stream ID 1; INTERNAL_ERROR
- 這是 HTTP/2 連接被服務端關閉的錯誤
- 當前重試機制不包含此類錯誤,導致直接失敗
修復:
- 添加 "stream error" 到可重試列表
- 添加 "INTERNAL_ERROR" 到可重試列表
- 遇到此類錯誤時會自動重試(最多 3 次)
影響:
- 提高 API 調用穩定性
- 自動處理服務端臨時故障
- 減少因網絡波動導致的失敗
2025-11-04 17:35:26 +08:00
ZhouYongyou
b7a1a60c6f fix: 过滤幽灵持仓 - 跳过 quantity=0 的持仓防止 AI 误判
问题:
- 止损/止盈触发后,交易所返回 positionAmt=0 的持仓记录
- 这些幽灵持仓被传递给 AI,导致 AI 误以为仍持有该币种
- AI 可能基于错误信息做出决策(如尝试调整已不存在的止损)
修复:
- buildTradingContext() 中添加 quantity==0 检查
- 跳过已平仓的持仓,确保只传递真实持仓给 AI
- 触发清理逻辑:撤销孤儿订单、清理内部状态
影响范围:
- trader/auto_trader.go:487-490
测试:
- 编译成功
- 容器重建并启动正常
2025-11-04 17:35:19 +08:00
ZhouYongyou
b8eea8eaad 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
2025-11-04 17:22:14 +08:00
ZhouYongyou
3f5bb5ca84 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
2025-11-04 17:21:47 +08:00
ZhouYongyou
5d2d849226 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.
Co-Authored-By: tinkle-community <tinklefund@gmail.com>
2025-11-04 17:20:57 +08:00
ZhouYongyou
c0c0688805 更新 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,
      因為還有剩餘倉位可能繼續交易
2025-11-04 17:19:58 +08:00
ZhouYongyou
c26463c4c4 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)
2025-11-04 16:58:28 +08:00
ZhouYongyou
c4e72b124f fix: 修復 Hyperliquid CancelStopOrders 編譯錯誤
- OpenOrder 結構不暴露 trigger 字段
- 改為取消該幣種的所有掛單(安全做法)
2025-11-04 16:45:20 +08:00
ZhouYongyou
b9a4bfceca fix: 修复部分平仓盈利计算错误
问题:部分平仓时,历史记录显示的是全仓位盈利,而非实际平仓部分的盈利
根本原因:
- AnalyzePerformance 使用开仓总数量计算部分平仓的盈利
- 应该使用 action.Quantity(实际平仓数量)而非 openPos["quantity"](总数量)
修复:
- 添加 actualQuantity 变量区分完整平仓和部分平仓
- partial_close 使用 action.Quantity
- 所有相关计算(PnL、PositionValue、MarginUsed)都使用 actualQuantity
影响范围:logger/decision_logger.go:428-465
Co-Authored-By: tinkle-community <tinklefund@gmail.com>
2025-11-04 16:40:28 +08:00
ZhouYongyou
9884605c75 修復關鍵缺陷:添加 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 的實現思路
2025-11-04 16:40:23 +08:00
ZhouYongyou
c2aed38785 修復關鍵 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 分支,等待測試確認
2025-11-04 16:40:18 +08:00
ZhouYongyou
8344e6b68f 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(部分平仓)
Co-Authored-By: tinkle-community <tinklefund@gmail.com>
2025-11-04 16:40:12 +08:00
ZhouYongyou
2ca627ff72 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.
2025-11-04 16:28:43 +08:00
ZhouYongyou
93e9b505cf 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
Co-Authored-By: tinkle-community <tinklefund@gmail.com>
2025-11-04 16:28:38 +08:00
tinkle-community
4f7d21c581 Merge pull request #404 from 0xEmberZz/feature/binance-guide
feat: Add Binance setup guide with tutorial modal
2025-11-04 15:35:19 +08:00
Ember
76abf1ee6e 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
Co-Authored-By: tinkle-community <tinklefund@gmail.com>
2025-11-04 14:50:38 +08:00
tangmengqiu
bc27dde073 fix print 2025-11-04 00:29:37 -05:00
tangmengqiu
70a95ca752 fix go vet check 2025-11-04 00:24:34 -05:00
tangmengqiu
3bb6404fc0 fix pk prefix handle 2025-11-04 00:03:56 -05:00
tangmengqiu
781c7ddeee fix 2025-11-03 23:43:06 -05:00
tangmengqiu
045834dcbe 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
Co-Authored-By: tinkle-community <tinklefund@gmail.com>
2025-11-03 23:15:38 -05:00
SkywalkerJi
272e830707 fix the main branch history issue from November 3rd.
Merge pull request #395 from NoFxAiOS/beta
fix:fix the main branch history issue from November 3rd.
2025-11-04 13:00:05 +09:00
tinkle-community
21f263990d Merge pull request #389 from NoFxAiOS/beta
Fix:fix the main branch history issue from November 3rd.
2025-11-04 11:22:10 +08:00
Shui
3972868ff1 Merge pull request #354 from zhouyongyou/fix/trader-config-missing-fields
fix(database): GetTraderConfig missing critical fields causes edit to fail
2025-11-03 21:57:48 -05:00
Shui
a0d2650a4f Merge pull request #373 from hzb1115/dev
fix(readme): update readme and pr reviewer
2025-11-03 21:07:31 -05:00
zbhan
8b004bf4dc Fix owner 2025-11-03 21:06:25 -05:00
zbhan
fb88cc8926 fix owner 2025-11-03 20:56:16 -05:00
zbhan
52295c69ad fix(readme): update readme and pr reviewer 2025-11-03 20:50:56 -05:00
Luna Martinez
68bbd37810 Merge pull request #362 from hzb1115/dev
Fix(workflow): add title and size validation comments
2025-11-03 13:20:02 -05:00
Luna Martinez
35b328bee7 Merge branch 'NoFxAiOS:dev' into dev 2025-11-03 13:16:11 -05:00
Icyoung
2affa0ae62 Merge pull request #361 from Icyoung/beta
Beta bugfix
2025-11-04 02:14:54 +08:00
zbhan
fd95021c25 Fix PR check 2025-11-03 13:12:47 -05:00
icy
4c74465075 Add NOFX watermarks to charts and fix empty state internationalization
- Add NOFX watermark to ComparisonChart (competition page)
- Add NOFX watermark to EquityChart (dashboard page)
- Fix empty state handling and internationalization in CompetitionPage
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: tinkle-community <tinklefund@gmail.com>
2025-11-04 02:08:38 +08:00
icy
da1ac71828 Fix ComparisonChart data display issue
The chart was not showing data because the API response format changed.
Fixed the calculation of PnL percentage by computing it from total_pnl
and balance values (initial_balance = balance - total_pnl).
Now the AI competition chart should properly display performance comparison data.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: tinkle-community <tinklefund@gmail.com>
2025-11-04 01:54:21 +08:00
Icyoung
ea374d2311 Merge pull request #359 from Icyoung/beta
Beta Merge dev、Bug fix
2025-11-04 01:50:34 +08:00
icy
c28ca79d7a Merge branch 'dev' into beta 2025-11-04 01:45:21 +08:00
icy
3a38c1bf56 Merge branch 'dev' of https://github.com/tinkle-community/nofx into dev 2025-11-04 01:45:15 +08:00