fix(hyperliquid): correct Spot balance handling - exclude from availableBalance

## 🔴 修復關鍵錯誤:Spot 餘額不應加入可用餘額

### 問題分析

之前的修復錯誤地將 Spot 餘額加入 `availableBalance`:

```go
//  錯誤:把 Spot 加到可用餘額
totalAvailableBalance := spotUSDCBalance + availableBalance
result["availableBalance"] = totalAvailableBalance
```

**問題**:
- Hyperliquid 的 Spot 和 Perpetuals 是**兩個獨立帳戶**
- Spot 的錢**不能直接用於開倉**
- 需要手動調用 `ClassTransfer` API 才能轉帳
- 如果包含 Spot,`auto_trader` 會誤以為有錢可以開倉 → 實際開倉失敗

### SDK 確認

經查詢 `github.com/sonirico/go-hyperliquid` v0.17.0:
-  SDK 支援 `ClassTransfer` 方法(Perpetuals ↔ Spot 轉帳)
-  我們的系統**沒有實現自動轉帳**
- 結論:Spot 餘額不能算入可用餘額

### 修復方案

```go
//  正確:Spot 只加到總資產,不加到可用餘額
totalWalletBalance := walletBalanceWithoutUnrealized + spotUSDCBalance

result["totalWalletBalance"] = totalWalletBalance    // 總資產(Perp + Spot)
result["availableBalance"] = availableBalance        // 可用餘額(僅 Perpetuals)
result["totalUnrealizedProfit"] = totalUnrealizedPnl
result["spotBalance"] = spotUSDCBalance              // 單獨返回 Spot 餘額
```

### 修復前後對比

| 場景 | 修復前 | 修復後 | 影響 |
|------|--------|--------|------|
| Spot 100, Perp 0 | availableBalance=100 | availableBalance=0 |  避免開倉失敗 |
| Spot 100, Perp 50 | availableBalance=150 | availableBalance=50 |  避免誤判 |
| totalWalletBalance | 僅 Perp | Perp + Spot |  正確顯示總資產 |

### 日誌改善

```
✓ Hyperliquid 账户总览:
  • Spot 现货余额: 100.00 USDC (需手动转账到 Perpetuals 才能开仓)
  • Perpetuals 可用余额: 50.00 USDC (可直接用於開倉)
  • 總資產 (Perp+Spot): 150.00 USDC
   总资产: 150.00 USDC | Perp 可用: 50.00 USDC | Spot 余额: 100.00 USDC
```

## 相關

- 修復了 fe8ba6a 引入的錯誤邏輯
- 與 2f9a7b0 (動態保證金摘要) 獨立

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

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
ZhouYongyou
2025-11-05 03:59:04 +08:00
parent 2f9a7b08de
commit e674eeb19e

View File

@@ -167,22 +167,27 @@ func (t *HyperliquidTrader) GetBalance() (map[string]interface{}, error) {
}
}
// ✅ 可用余额 = Spot 现货余额 + Perpetuals 可用余额
totalAvailableBalance := spotUSDCBalance + availableBalance
// ✅ 正確邏輯Spot 只加到總資產,不加到可用餘額
// 原因Spot 和 Perpetuals 是獨立帳戶Spot 的錢不能直接用於開倉
// 需要手動調用 ClassTransfer 才能轉帳
totalWalletBalance := walletBalanceWithoutUnrealized + spotUSDCBalance
result["totalWalletBalance"] = walletBalanceWithoutUnrealized // 钱包余额(不含未实现盈亏
result["availableBalance"] = totalAvailableBalance // 可用余额Spot + Perpetuals
result["totalUnrealizedProfit"] = totalUnrealizedPnl // 未实现盈亏
result["totalWalletBalance"] = totalWalletBalance // 總資產Perp錢包 + Spot
result["availableBalance"] = availableBalance // 可用餘額(僅 Perpetuals,不含 Spot
result["totalUnrealizedProfit"] = totalUnrealizedPnl // 未實現盈虧
result["spotBalance"] = spotUSDCBalance // Spot 現貨餘額(單獨返回)
log.Printf("✓ Hyperliquid 账户总览:")
log.Printf(" • Spot 现货余额: %.2f USDC", spotUSDCBalance)
log.Printf(" • Spot 现货余额: %.2f USDC (需手动转账到 Perpetuals 才能开仓)", spotUSDCBalance)
log.Printf(" • Perpetuals 合约净值: %.2f USDC (钱包%.2f + 未实现%.2f)",
accountValue-spotUSDCBalance,
walletBalanceWithoutUnrealized-spotUSDCBalance,
accountValue,
walletBalanceWithoutUnrealized,
totalUnrealizedPnl)
log.Printf(" • Perpetuals 可用余额: %.2f USDC", availableBalance)
log.Printf(" • Perpetuals 可用余额: %.2f USDC (可直接用於開倉)", availableBalance)
log.Printf(" • 保证金占用: %.2f USDC", totalMarginUsed)
log.Printf(" ⭐ 总净值: %.2f USDC | 总可用: %.2f USDC", accountValue, totalAvailableBalance)
log.Printf(" • 總資產 (Perp+Spot): %.2f USDC", totalWalletBalance)
log.Printf(" ⭐ 总资产: %.2f USDC | Perp 可用: %.2f USDC | Spot 余额: %.2f USDC",
totalWalletBalance, availableBalance, spotUSDCBalance)
return result, nil
}