From e674eeb19ed93e5241bc9f58a3f3d1405dca5323 Mon Sep 17 00:00:00 2001 From: ZhouYongyou <128128010+zhouyongyou@users.noreply.github.com> Date: Wed, 5 Nov 2025 03:59:04 +0800 Subject: [PATCH] fix(hyperliquid): correct Spot balance handling - exclude from availableBalance MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 🔴 修復關鍵錯誤: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 --- trader/hyperliquid_trader.go | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/trader/hyperliquid_trader.go b/trader/hyperliquid_trader.go index b0ceaa86..93cd0237 100644 --- a/trader/hyperliquid_trader.go +++ b/trader/hyperliquid_trader.go @@ -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 }