Files
nofx/trader
ZhouYongyou fe8ba6ac34 fix(hyperliquid): query both Spot and Perpetuals balance to resolve "0 balance" false reports
## Problem Analysis

PR #443 fixed Withdrawable field priority, but users still reported "wallet has funds but shows 0".

**Root Cause**: Hyperliquid has TWO separate account systems:
1. **Spot Account** (現貨帳戶) - holds USDC/tokens
2. **Perpetuals Account** (合約帳戶) - for futures trading

Previous implementation ONLY queried Perpetuals (`UserState`), completely missing Spot balance.

## Real-World Scenario

User's actual account state:
- Spot Account: 100 USDC  (not detected before)
- Perpetuals: 0 USDC
- **Old display**: 0.00 USDC 
- **New display**: 100.00 USDC 

## Solution Implemented

### 1. Query Both Accounts
```go
// Step 1: Query Spot balance (SpotUserState)
spotState := exchange.Info().SpotUserState(ctx, walletAddr)
spotUSDCBalance := spotState.Balances[USDC].Total

// Step 2: Query Perpetuals balance (UserState)
accountState := exchange.Info().UserState(ctx, walletAddr)
perpetualsValue := accountState.MarginSummary.AccountValue

// Step 3: Combine both
totalBalance = spotUSDCBalance + perpetualsValue
```

### 2. Enhanced Logging
New log format shows separate breakdowns:
```
✓ Hyperliquid 账户总览:
  • Spot 现货余额: 100.00 USDC
  • Perpetuals 合约净值: 0.00 USDC
  • Perpetuals 可用余额: 0.00 USDC
  • 保证金占用: 0.00 USDC
   总净值: 100.00 USDC | 总可用: 100.00 USDC
```

### 3. Backward Compatibility
- If SpotUserState fails (API error), continues with Perpetuals only
- Logs warning instead of failing completely
- Maintains same return structure for auto_trader.go

## Technical Details

**API Endpoints Used**:
- `Info.SpotUserState(ctx, address)` → returns `SpotUserState{Balances[]}`
- `Info.UserState(ctx, address)` → returns perpetuals state

**Balance Fields**:
- `SpotBalance.Total` - total USDC in spot (includes held + free)
- `SpotBalance.Hold` - amount locked in spot orders
- Combined with existing Perpetuals logic

## Impact

**Before**: Users with Spot-only funds saw 0 balance → couldn't trade
**After**: Correctly shows Spot + Perpetuals combined balance

Closes false "insufficient balance" reports when funds exist in Spot account.

## References

- Hyperliquid API Docs: https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/info-endpoint/spot
- Related: PR #443 (Withdrawable field priority)
- SDK: github.com/sonirico/go-hyperliquid v0.17.0

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-05 03:08:35 +08:00
..