Skip to content

Conversation

@the-dev-z
Copy link
Collaborator

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.

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 ✅
// 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

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
  • If SpotUserState fails (API error), continues with Perpetuals only
  • Logs warning instead of failing completely
  • Maintains same return structure for auto_trader.go

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

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.

…0 balance" false reports

PR NoFxAiOS#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.

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 ✅

```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
```

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
```

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

**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

**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.

- Hyperliquid API Docs: https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/info-endpoint/spot
- Related: PR NoFxAiOS#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 <[email protected]>
@github-actions
Copy link

github-actions bot commented Nov 4, 2025

🤖 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 (70 lines: +59 -11)

🔧 Backend Checks

Go Formatting: ⚠️ Needs formatting

Files needing formatting
api/server.go
config/database.go
manager/trader_manager.go

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.

@hzb1115
Copy link
Member

hzb1115 commented Nov 5, 2025

@hzb1115 hzb1115 closed this Nov 5, 2025
@the-dev-z the-dev-z deleted the fix/hyperliquid-spot-balance branch November 12, 2025 10:22
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.

2 participants