Skip to content

Commit

Permalink
Merge pull request #1892 from c9s/c9s/okx/margin
Browse files Browse the repository at this point in the history
IMPROVE: [okx] add / improve okx margin api
  • Loading branch information
c9s authored Jan 22, 2025
2 parents 5ea5769 + 275c33c commit 7586dad
Show file tree
Hide file tree
Showing 20 changed files with 1,286 additions and 55 deletions.
56 changes: 55 additions & 1 deletion pkg/exchange/okex/exchange.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"os"
"regexp"
"strconv"
"strings"
"time"

"github.com/pkg/errors"
Expand Down Expand Up @@ -224,7 +225,7 @@ func (e *Exchange) QueryAccountBalances(ctx context.Context) (types.BalanceMap,
return nil, fmt.Errorf("account rate limiter wait error: %w", err)
}

accountBalances, err := e.client.NewGetAccountInfoRequest().Do(ctx)
accountBalances, err := e.client.NewGetAccountBalanceRequest().Do(ctx)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -560,6 +561,59 @@ func (e *Exchange) QueryClosedOrders(
return types.SortOrdersAscending(orders), nil
}

func (e *Exchange) RepayMarginAsset(ctx context.Context, asset string, amount fixedpoint.Value) error {
req := e.client.NewSpotManualBorrowRepayRequest()
req.Currency(strings.ToUpper(asset))
req.Amount(amount.String())
req.Side(okexapi.MarginSideRepay)
resp, err := req.Do(ctx)
if err != nil {
return err
}

log.Infof("spot repay response: %+v", resp)
return nil
}

func (e *Exchange) BorrowMarginAsset(ctx context.Context, asset string, amount fixedpoint.Value) error {
req := e.client.NewSpotManualBorrowRepayRequest()
req.Currency(strings.ToUpper(asset))
req.Amount(amount.String())
req.Side(okexapi.MarginSideBorrow)

resp, err := req.Do(ctx)
if err != nil {
return err
}

log.Infof("spot borrow response: %+v", resp)
return nil
}

func (e *Exchange) QueryMarginAssetMaxBorrowable(ctx context.Context, asset string) (fixedpoint.Value, error) {
req := e.client.NewGetAccountInterestLimitsRequest()
req.Currency(asset)

resp, err := req.Do(ctx)
if err != nil {
return fixedpoint.Zero, err
}

log.Infof("%+v", resp)

if len(resp) == 0 || len(resp[0].Records) == 0 {
return fixedpoint.Zero, nil
}

for _, record := range resp[0].Records {
if strings.ToUpper(record.Currency) == asset {
return record.LoanQuota, nil
}
}

return fixedpoint.Zero, nil
}

/*
QueryTrades can query trades in last 3 months, there are no time interval limitations, as long as end_time >= start_time.
okx does not provide an API to query by trade ID, so we use the bill ID to do it. The trades result is ordered by timestamp.
Expand Down
20 changes: 19 additions & 1 deletion pkg/exchange/okex/exchange_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,6 @@ func TestExchange_SubmitOrder(t *testing.T) {
assert.NoError(t, err)
t.Logf("createdOrder: %+v", createdOrder)
}

}

func TestExchange_QueryTrades(t *testing.T) {
Expand Down Expand Up @@ -420,3 +419,22 @@ func TestExchange_QueryTrades(t *testing.T) {
assert.ErrorContains(err, ErrSymbolRequired.Error())
})
}

func TestExchange_Margin(t *testing.T) {
key, secret, passphrase, ok := testutil.IntegrationTestWithPassphraseConfigured(t, "OKEX")
if !ok {
t.SkipNow()
return
}

ctx := context.Background()
ex := New(key, secret, passphrase)

t.Run("QueryMarginAssetMaxBorrowable", func(t *testing.T) {
maxBorrowable, err := ex.QueryMarginAssetMaxBorrowable(ctx, "BTC")
if assert.NoError(t, err) {
assert.NotZero(t, maxBorrowable.Float64())
t.Logf("max borrowable: %f", maxBorrowable.Float64())
}
})
}
139 changes: 116 additions & 23 deletions pkg/exchange/okex/okexapi/client_test.go

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,13 @@ type Account struct {
Details []BalanceDetail `json:"details"`
}

//go:generate GetRequest -url "/api/v5/account/balance" -type GetAccountInfoRequest -responseDataType []Account
type GetAccountInfoRequest struct {
//go:generate GetRequest -url "/api/v5/account/balance" -type GetAccountBalanceRequest -responseDataType []Account
type GetAccountBalanceRequest struct {
client requestgen.AuthenticatedAPIClient
}

func (c *RestClient) NewGetAccountInfoRequest() *GetAccountInfoRequest {
return &GetAccountInfoRequest{
func (c *RestClient) NewGetAccountBalanceRequest() *GetAccountBalanceRequest {
return &GetAccountBalanceRequest{
client: c,
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

51 changes: 51 additions & 0 deletions pkg/exchange/okex/okexapi/get_account_config_request.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package okexapi

import (
"github.com/c9s/requestgen"

"github.com/c9s/bbgo/pkg/types"
)

//go:generate -command GetRequest requestgen -method GET -responseType .APIResponse -responseDataField Data
//go:generate -command PostRequest requestgen -method POST -responseType .APIResponse -responseDataField Data

type AccountConfig struct {
AccountLevel types.StrInt64 `json:"acctLv"`

AccountSelfTradePreventionMode string `json:"acctStpMode"`

AutoLoan bool `json:"autoLoan"`
ContractIsolationMode string `json:"ctIsoMode"`
EnableSpotBorrow bool `json:"enableSpotBorrow"`
GreeksType string `json:"greeksType"`
Ip string `json:"ip"`
Type string `json:"type"`
KycLv types.StrInt64 `json:"kycLv"`
Label string `json:"label"`
Level string `json:"level"`
LevelTmp string `json:"levelTmp"`
LiquidationGear string `json:"liquidationGear"`
MainUid string `json:"mainUid"`
MgnIsoMode string `json:"mgnIsoMode"`
OpAuth string `json:"opAuth"`
Perm string `json:"perm"`
PosMode string `json:"posMode"`
RoleType types.StrInt64 `json:"roleType"`
SpotBorrowAutoRepay bool `json:"spotBorrowAutoRepay"`
SpotOffsetType string `json:"spotOffsetType"`
SpotRoleType string `json:"spotRoleType"`
SpotTraderInsts []interface{} `json:"spotTraderInsts"`
TraderInsts []interface{} `json:"traderInsts"`
Uid string `json:"uid"`
}

//go:generate GetRequest -url "/api/v5/account/config" -type GetAccountConfigRequest -responseDataType []AccountConfig
type GetAccountConfigRequest struct {
client requestgen.AuthenticatedAPIClient
}

func (c *RestClient) NewGetAccountConfigRequest() *GetAccountConfigRequest {
return &GetAccountConfigRequest{
client: c,
}
}
Loading

0 comments on commit 7586dad

Please sign in to comment.