Skip to content

Commit 6d50e11

Browse files
authored
Merge pull request #2029 from anywhy/improve_risk_service
2 parents 65c3686 + f7d7e1a commit 6d50e11

File tree

5 files changed

+143
-15
lines changed

5 files changed

+143
-15
lines changed

pkg/exchange/binance/exchange_test.go

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

9+
"github.com/c9s/bbgo/pkg/testutil"
910
"github.com/stretchr/testify/assert"
1011
)
1112

@@ -32,3 +33,40 @@ func Test_new(t *testing.T) {
3233
assert.NoError(t, err)
3334
}
3435
}
36+
37+
func Test_QueryPositionRisk(t *testing.T) {
38+
key, secret, ok := testutil.IntegrationTestConfigured(t, "BINANCE")
39+
if !ok {
40+
t.SkipNow()
41+
return
42+
}
43+
44+
ex := New(key, secret)
45+
ex.UseFutures()
46+
47+
assert.NotEmpty(t, ex)
48+
ctx := context.Background()
49+
50+
// Test case 1: Query all positions
51+
positions, err := ex.QueryPositionRisk(ctx)
52+
assert.NoError(t, err)
53+
54+
// Test case 2: Query specific symbol position
55+
positions, err = ex.QueryPositionRisk(ctx, "BTCUSDT")
56+
assert.NoError(t, err)
57+
if len(positions) > 0 {
58+
assert.Equal(t, "BTCUSDT", positions[0].Symbol)
59+
}
60+
61+
// Test case 3: Query multiple symbols
62+
positions, err = ex.QueryPositionRisk(ctx, "BTCUSDT", "ETHUSDT")
63+
assert.NoError(t, err)
64+
if len(positions) > 0 {
65+
symbols := make(map[string]bool)
66+
for _, pos := range positions {
67+
symbols[pos.Symbol] = true
68+
}
69+
assert.True(t, symbols["BTCUSDT"] || symbols["ETHUSDT"])
70+
}
71+
72+
}

pkg/exchange/binance/futures.go

Lines changed: 32 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -412,23 +412,43 @@ func (e *Exchange) SetLeverage(ctx context.Context, symbol string, leverage int)
412412
return fmt.Errorf("not supported set leverage")
413413
}
414414

415-
func (e *Exchange) QueryPositionRisk(ctx context.Context, symbol string) ([]types.PositionRisk, error) {
416-
var (
417-
positions []binanceapi.FuturesPositionRisk
418-
err error
419-
)
415+
func (e *Exchange) QueryPositionRisk(ctx context.Context, symbol ...string) ([]types.PositionRisk, error) {
416+
if !e.IsFutures {
417+
return nil, fmt.Errorf("not supported for non-futures exchange")
418+
}
420419

421-
if e.IsFutures {
422-
req := e.futuresClient2.NewFuturesGetPositionRisksRequest()
423-
if len(symbol) > 0 {
424-
req.Symbol(symbol)
425-
}
426-
if positions, err = req.Do(ctx); err != nil {
420+
req := e.futuresClient2.NewFuturesGetPositionRisksRequest()
421+
if len(symbol) == 1 {
422+
req.Symbol(symbol[0])
423+
positions, err := req.Do(ctx)
424+
if err != nil {
427425
return nil, err
428426
}
427+
return toGlobalPositionRisk(positions), nil
428+
}
429+
430+
positions, err := req.Do(ctx)
431+
if err != nil {
432+
return nil, err
433+
}
434+
435+
if len(symbol) == 0 {
436+
return toGlobalPositionRisk(positions), nil
437+
}
438+
439+
symbolSet := make(map[string]struct{}, len(symbol))
440+
for _, s := range symbol {
441+
symbolSet[s] = struct{}{}
442+
}
443+
444+
filteredPositions := make([]binanceapi.FuturesPositionRisk, 0, len(symbol))
445+
for _, pos := range positions {
446+
if _, ok := symbolSet[pos.Symbol]; ok {
447+
filteredPositions = append(filteredPositions, pos)
448+
}
429449
}
430450

431-
return toGlobalPositionRisk(positions), nil
451+
return toGlobalPositionRisk(filteredPositions), nil
432452
}
433453

434454
func setDualSidePosition(req *futures.CreateOrderService, order types.SubmitOrder) {

pkg/exchange/okex/exchange_test.go

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -693,3 +693,68 @@ func TestExchange_QueryMarkets_SymbolCache(t *testing.T) {
693693
assert.NotContains(t, spotSymbolMap, "ETHUSDT")
694694
})
695695
}
696+
697+
func TestExchange_QueryPositionRisk(t *testing.T) {
698+
key, secret, passphrase, ok := testutil.IntegrationTestWithPassphraseConfigured(t, "OKEX")
699+
if !ok {
700+
t.SkipNow()
701+
return
702+
}
703+
704+
ex := New(key, secret, passphrase)
705+
ex.UseFutures()
706+
707+
ctx := context.Background()
708+
709+
t.Run("query all positions", func(t *testing.T) {
710+
// Test querying all positions
711+
positions, err := ex.QueryPositionRisk(ctx)
712+
assert.NoError(t, err)
713+
assert.NotNil(t, positions)
714+
715+
// Verify position data structure
716+
for _, pos := range positions {
717+
assert.NotEmpty(t, pos.Symbol)
718+
assert.NotEmpty(t, pos.EntryPrice)
719+
assert.NotEmpty(t, pos.PositionAmount)
720+
assert.NotEmpty(t, pos.Leverage)
721+
assert.NotEmpty(t, pos.MarkPrice)
722+
assert.NotEmpty(t, pos.LiquidationPrice)
723+
}
724+
})
725+
726+
t.Run("query specific symbol position", func(t *testing.T) {
727+
// Test querying specific symbol position
728+
symbol := "BTCUSDT"
729+
positions, err := ex.QueryPositionRisk(ctx, symbol)
730+
assert.NoError(t, err)
731+
assert.NotNil(t, positions)
732+
733+
// If there are positions, verify the symbol matches
734+
if len(positions) > 0 {
735+
for _, pos := range positions {
736+
assert.Equal(t, symbol, pos.Symbol)
737+
}
738+
}
739+
})
740+
741+
t.Run("query multiple symbols", func(t *testing.T) {
742+
// Test querying multiple symbols
743+
symbols := []string{"BTCUSDT", "ETHUSDT"}
744+
positions, err := ex.QueryPositionRisk(ctx, symbols...)
745+
assert.NoError(t, err)
746+
assert.NotNil(t, positions)
747+
748+
// If there are positions, verify they belong to requested symbols
749+
if len(positions) > 0 {
750+
symbolSet := make(map[string]bool)
751+
for _, symbol := range symbols {
752+
symbolSet[symbol] = true
753+
}
754+
755+
for _, pos := range positions {
756+
assert.True(t, symbolSet[pos.Symbol], "Position symbol should be one of the requested symbols")
757+
}
758+
}
759+
})
760+
}

pkg/exchange/okex/futures.go

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package okex
33
import (
44
"context"
55
"fmt"
6+
"strings"
67

78
"github.com/c9s/bbgo/pkg/exchange/okex/okexapi"
89
"github.com/c9s/bbgo/pkg/types"
@@ -51,7 +52,7 @@ func (e *Exchange) SetLeverage(ctx context.Context, symbol string, leverage int)
5152
return fmt.Errorf("not supported set leverage")
5253
}
5354

54-
func (e *Exchange) QueryPositionRisk(ctx context.Context, symbol string) ([]types.PositionRisk, error) {
55+
func (e *Exchange) QueryPositionRisk(ctx context.Context, symbol ...string) ([]types.PositionRisk, error) {
5556
var (
5657
positions []okexapi.Position
5758
err error
@@ -61,7 +62,11 @@ func (e *Exchange) QueryPositionRisk(ctx context.Context, symbol string) ([]type
6162
req := e.client.NewGetAccountPositionsRequest().
6263
InstType(okexapi.InstrumentTypeSwap)
6364
if len(symbol) > 0 {
64-
req.InstId(toLocalSymbol(symbol, okexapi.InstrumentTypeSwap))
65+
symbols := make([]string, len(symbol))
66+
for i, s := range symbol {
67+
symbols[i] = toLocalSymbol(s, okexapi.InstrumentTypeSwap)
68+
}
69+
req.InstId(strings.Join(symbols, ","))
6570
}
6671
if positions, err = req.Do(ctx); err != nil {
6772
return nil, err

pkg/types/exchange.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ type ExchangeRewardService interface {
179179

180180
type ExchangeRiskService interface {
181181
SetLeverage(ctx context.Context, symbol string, leverage int) error
182-
QueryPositionRisk(ctx context.Context, symbol string) ([]PositionRisk, error)
182+
QueryPositionRisk(ctx context.Context, symbol ...string) ([]PositionRisk, error)
183183
}
184184

185185
type TradeQueryOptions struct {

0 commit comments

Comments
 (0)