Skip to content

Commit f54631d

Browse files
committed
implement query account balances
1 parent a972a6e commit f54631d

File tree

3 files changed

+91
-12
lines changed

3 files changed

+91
-12
lines changed

pkg/exchange/hyperliquid/exchange.go

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -93,24 +93,39 @@ func (e *Exchange) QueryAccount(ctx context.Context) (*types.Account, error) {
9393
return e.queryFuturesAccount(ctx)
9494
}
9595

96-
spotAccount, err := e.client.NewGetAccountBalanceRequest().User(e.client.UserAddress()).Do(ctx)
96+
balances, err := e.querySpotAccountBalance(ctx)
9797
if err != nil {
9898
return nil, err
9999
}
100100

101-
balances := toGlobalBalance(spotAccount)
102101
account := types.NewAccount()
103-
account.UpdateBalances(balances)
102+
account.UpdateBalances(toGlobalBalance(balances))
104103

105104
return account, nil
106105
}
107106

108107
func (e *Exchange) QueryAccountBalances(ctx context.Context) (types.BalanceMap, error) {
109-
// TODO implement
110-
return nil, fmt.Errorf("not implemented")
108+
balances, err := e.querySpotAccountBalance(ctx)
109+
if err != nil {
110+
return nil, err
111+
}
112+
113+
return toGlobalBalance(balances), nil
114+
}
115+
116+
func (e *Exchange) querySpotAccountBalance(ctx context.Context) (*hyperapi.Account, error) {
117+
if err := restSharedLimiter.Wait(ctx); err != nil {
118+
return nil, fmt.Errorf("account rate limiter wait error: %w", err)
119+
}
120+
121+
return e.client.NewGetAccountBalanceRequest().User(e.client.UserAddress()).Do(ctx)
111122
}
112123

113124
func (e *Exchange) SubmitOrder(ctx context.Context, order types.SubmitOrder) (createdOrder *types.Order, err error) {
125+
if err := restSharedLimiter.Wait(ctx); err != nil {
126+
return nil, fmt.Errorf("submit order rate limiter wait error: %w", err)
127+
}
128+
114129
// TODO implement
115130
return nil, fmt.Errorf("not implemented")
116131
}

pkg/exchange/hyperliquid/exchange_test.go

Lines changed: 66 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"os"
88
"testing"
99

10+
"github.com/c9s/bbgo/pkg/fixedpoint"
1011
"github.com/c9s/bbgo/pkg/testing/httptesting"
1112
"github.com/c9s/bbgo/pkg/types"
1213
"github.com/ethereum/go-ethereum/crypto"
@@ -151,10 +152,10 @@ func TestQueryAccount(t *testing.T) {
151152
futuresInfo := account.FuturesInfo
152153

153154
// Verify futures account summary fields
154-
assert.Equal(t, 121968206.668798998, futuresInfo.TotalMarginBalance.Float64())
155-
assert.Equal(t, 46255052.1990050003, futuresInfo.TotalInitialMargin.Float64())
156-
assert.Equal(t, 12598833.5037019998, futuresInfo.TotalMaintMargin.Float64())
157-
assert.Equal(t, 75713154.4697940052, futuresInfo.AvailableBalance.Float64())
155+
assert.Equal(t, fixedpoint.NewFromFloat(121968206.668798998), futuresInfo.TotalMarginBalance)
156+
assert.Equal(t, fixedpoint.NewFromFloat(46255052.1990050003), futuresInfo.TotalInitialMargin)
157+
assert.Equal(t, fixedpoint.NewFromFloat(12598833.5037019998), futuresInfo.TotalMaintMargin)
158+
assert.Equal(t, fixedpoint.NewFromFloat(75713154.4697940052), futuresInfo.AvailableBalance)
158159

159160
// Verify positions count
160161
assert.Equal(t, 11, len(futuresInfo.Positions))
@@ -173,9 +174,9 @@ func TestQueryAccount(t *testing.T) {
173174
assert.NotNil(t, btcPos.PositionRisk)
174175
assert.Equal(t, "10", btcPos.PositionRisk.Leverage.String())
175176
assert.Equal(t, "111616.8", btcPos.PositionRisk.EntryPrice.String())
176-
assert.Equal(t, 191751.85621501, btcPos.PositionRisk.LiquidationPrice.Float64())
177-
assert.Equal(t, 11962126.6084020007, btcPos.PositionRisk.UnrealizedPnL.Float64())
178-
assert.Equal(t, 120498051.8718400002, btcPos.PositionRisk.Notional.Float64())
177+
assert.Equal(t, fixedpoint.NewFromFloat(191751.8562150183), btcPos.PositionRisk.LiquidationPrice)
178+
assert.Equal(t, fixedpoint.NewFromFloat(11962126.6084020007), btcPos.PositionRisk.UnrealizedPnL)
179+
assert.Equal(t, fixedpoint.NewFromFloat(120498051.8718400002), btcPos.PositionRisk.Notional)
179180

180181
// Verify ETH short position
181182
ethPosKey := types.NewPositionKey("ETHUSDC", types.PositionShort)
@@ -208,3 +209,61 @@ func TestQueryAccount(t *testing.T) {
208209
})
209210

210211
}
212+
213+
func TestQueryAccountBalances(t *testing.T) {
214+
t.Run("succeeds querying spot account balances", func(t *testing.T) {
215+
privateKey, err := crypto.GenerateKey()
216+
require.NoError(t, err)
217+
ex := New(fmt.Sprintf("%x", crypto.FromECDSA(privateKey)), "")
218+
219+
transport := &httptesting.MockTransport{}
220+
ex.client.HttpClient.Transport = transport
221+
222+
spotMeta, err := os.ReadFile("./testdata/spotClearinghouseState.json")
223+
require.NoError(t, err)
224+
225+
transport.POST("/info", func(req *http.Request) (*http.Response, error) {
226+
return httptesting.BuildResponseString(http.StatusOK, string(spotMeta)), nil
227+
})
228+
229+
balances, err := ex.QueryAccountBalances(context.Background())
230+
assert.NoError(t, err)
231+
assert.NotNil(t, balances)
232+
assert.Greater(t, len(balances), 0)
233+
234+
// Verify USDC balance
235+
usdcBalance, exists := balances["USDC"]
236+
assert.True(t, exists, "USDC balance should exist")
237+
assert.Equal(t, "USDC", usdcBalance.Currency)
238+
assert.Equal(t, "1808443.14193129", usdcBalance.NetAsset.String())
239+
assert.Equal(t, "1808443.14193129", usdcBalance.Available.String())
240+
assert.Equal(t, 0.0, usdcBalance.Locked.Float64())
241+
assert.Equal(t, "1808443.14193129", usdcBalance.MaxWithdrawAmount.String())
242+
243+
// Verify HYPE balance
244+
hypeBalance, exists := balances["HYPE"]
245+
assert.True(t, exists, "HYPE balance should exist")
246+
assert.Equal(t, "HYPE", hypeBalance.Currency)
247+
assert.Equal(t, "503808.46025243", hypeBalance.NetAsset.String())
248+
assert.Equal(t, "503778.46025243", hypeBalance.Available.String())
249+
assert.Equal(t, 30.0, hypeBalance.Locked.Float64())
250+
assert.Equal(t, "503778.46025243", hypeBalance.MaxWithdrawAmount.String())
251+
252+
// Verify LATINA balance
253+
latinaBalance, exists := balances["LATINA"]
254+
assert.True(t, exists, "LATINA balance should exist")
255+
assert.Equal(t, "LATINA", latinaBalance.Currency)
256+
assert.Equal(t, "45658.0657", latinaBalance.NetAsset.String())
257+
assert.Equal(t, "45658.0657", latinaBalance.Available.String())
258+
assert.Equal(t, 0.0, latinaBalance.Locked.Float64())
259+
260+
// Verify UBTC balance (zero balance)
261+
ubtcBalance, exists := balances["UBTC"]
262+
assert.True(t, exists, "UBTC balance should exist")
263+
assert.Equal(t, "UBTC", ubtcBalance.Currency)
264+
assert.Equal(t, "0", ubtcBalance.NetAsset.String())
265+
assert.Equal(t, "0", ubtcBalance.Available.String())
266+
assert.Equal(t, 0.0, ubtcBalance.Locked.Float64())
267+
})
268+
269+
}

pkg/exchange/hyperliquid/futures.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package hyperliquid
22

33
import (
44
"context"
5+
"fmt"
56
"math"
67
"strconv"
78

@@ -42,6 +43,10 @@ func (e *Exchange) queryFuturesMarkets(ctx context.Context) (types.MarketMap, er
4243
}
4344

4445
func (e *Exchange) queryFuturesAccount(ctx context.Context) (*types.Account, error) {
46+
if err := restSharedLimiter.Wait(ctx); err != nil {
47+
return nil, fmt.Errorf("account rate limiter wait error: %w", err)
48+
}
49+
4550
futuresAccount, err := e.client.NewFuturesGetAccountBalanceRequest().User(e.client.UserAddress()).Do(ctx)
4651
if err != nil {
4752
return nil, err

0 commit comments

Comments
 (0)