mirror of
https://github.com/d0zingcat/gocryptotrader.git
synced 2026-05-13 15:09:42 +00:00
exchanges: Kucoin Update (#1438)
* types and orderbook handling fix * Minor types and endpoints update * Minor fixes on Kucoin * Add benchmarking test * Unit tests update and minor endpoints update * Adding updates and newly added endpoints * Add and correct funding, withdrawal, and deposit endpoints * linter and codespell fix * Adding and correcting spot trading endpoints * Completed Spot HF endpoints * Minor fix * Added OCO and Margin HF trade and other endpoints * Adding missing endpoints * Updating Isolated margin, margin v3, and v3market lending endpoints * minor codespell fix * Completed adding and fixing futures endpoints * wrapper update and fix unit tests * Updating endpoint ratelimits * Complete ratelimiter setup and endpoint functions update * Unit test configuration and update * fix linter issue * Added a ratelimiter test and heavy update on unit tests * Adding websocket update based on ChangeLog * Added newly added Earn General, Kucoin Earn and Staking endpoints * Added VIP lending endpoints * Minor linter and endpoints fix * Added unit tests, publicised functions, and minor updates * Update on wrapper funcs, unit tests, and other methods * Enexport exchange specific websocket methods * remove deprecated topic * Update wrapper based on Type, add and fix unit tests * Added a margin configuration endpoint and unit test * Update methods, types, and unit tests * Update error declaration and handling unit tests * Update method parameters and error handling * Updating unit tests and error handling * Update methods arguments, added and update unit tests * Fix unit tests and wrapper methods * Resolving unit test issues and fix faulty endpoints * Fix on unit tests and working on passphrase errors * Minor fixed on websocket and endpoint url * comment and wrapper filters issue fix * Unit tests and other minor updates * Update wrapper functions, endpoint methods, and unit tests * change require to change on two unit tests * Update unit tests, types, and endpoints * Refine and update wrapper tempo for minor adjustments * Remove code that enabled logging * Update wrapper functions, missing endpoints, response and parameter values, and unit tests * removed High-frequency orders from wrapper functions, and updated unit tests and types * Added missing fields and minor update on wrapper * Update types * Update tests and websocket channels * Update unit tests and methods error returns
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -50,3 +50,4 @@ __debug_bin
|
||||
# Coverage reports
|
||||
coverage.txt
|
||||
wrapperconfig.json
|
||||
.history/
|
||||
@@ -64,6 +64,7 @@ var (
|
||||
ErrStartEqualsEnd = errors.New("start date equals end date")
|
||||
ErrStartAfterTimeNow = errors.New("start date is after current time")
|
||||
ErrNilPointer = errors.New("nil pointer")
|
||||
ErrEmptyParams = errors.New("empty parameters")
|
||||
ErrCannotCalculateOffline = errors.New("cannot calculate offline, unsupported")
|
||||
ErrNoResponse = errors.New("no response")
|
||||
ErrTypeAssertFailure = errors.New("type assert failure")
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -16,89 +16,43 @@ import (
|
||||
"github.com/thrasher-corp/gocryptotrader/currency"
|
||||
exchange "github.com/thrasher-corp/gocryptotrader/exchanges"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/asset"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/kline"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/order"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/orderbook"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/ticker"
|
||||
"github.com/thrasher-corp/gocryptotrader/types"
|
||||
)
|
||||
|
||||
const (
|
||||
kucoinFuturesAPIURL = "https://api-futures.kucoin.com/api"
|
||||
kucoinWebsocketURL = "wss://ws-api.kucoin.com/endpoint"
|
||||
|
||||
// Public market endpoints
|
||||
kucoinFuturesOpenContracts = "/v1/contracts/active"
|
||||
kucoinFuturesContract = "/v1/contracts/"
|
||||
kucoinFuturesTicker = "/v1/ticker"
|
||||
kucoinFuturesFullOrderbook = "/v1/level2/snapshot"
|
||||
kucoinFuturesPartOrderbook20 = "/v1/level2/depth20"
|
||||
kucoinFuturesPartOrderbook100 = "/v1/level2/depth100"
|
||||
kucoinFuturesTradeHistory = "/v1/trade/history"
|
||||
kucoinFuturesInterestRate = "/v1/interest/query"
|
||||
kucoinFuturesIndex = "/v1/index/query"
|
||||
kucoinFuturesMarkPrice = "/v1/mark-price/%s/current"
|
||||
kucoinFuturesPremiumIndex = "/v1/premium/query"
|
||||
kucoinFuturesFundingRate = "/v1/funding-rate/%s/current"
|
||||
kucoinFuturesServerTime = "/v1/timestamp"
|
||||
kucoinFuturesServiceStatus = "/v1/status"
|
||||
kucoinFuturesKline = "/v1/kline/query"
|
||||
|
||||
// Authenticated endpoints
|
||||
kucoinFuturesOrder = "/v1/orders"
|
||||
kucoinFuturesCancelOrder = "/v1/orders/"
|
||||
kucoinFuturesStopOrder = "/v1/stopOrders"
|
||||
kucoinFuturesRecentCompletedOrder = "/v1/recentDoneOrders"
|
||||
kucoinFuturesGetOrderDetails = "/v1/orders/"
|
||||
kucoinFuturesGetOrderDetailsByClientID = "/v1/orders/byClientOid"
|
||||
|
||||
kucoinFuturesFills = "/v1/fills"
|
||||
kucoinFuturesRecentFills = "/v1/recentFills"
|
||||
kucoinFuturesOpenOrderStats = "/v1/openOrderStatistics"
|
||||
kucoinFuturesPosition = "/v1/position"
|
||||
kucoinFuturesPositionList = "/v1/positions"
|
||||
kucoinFuturesSetAutoDeposit = "/v1/position/margin/auto-deposit-status"
|
||||
kucoinFuturesAddMargin = "/v1/position/margin/deposit-margin"
|
||||
kucoinFuturesRiskLimitLevel = "/v1/contracts/risk-limit/"
|
||||
kucoinFuturesUpdateRiskLmitLevel = "/v1/position/risk-limit-level/change"
|
||||
kucoinFuturesFundingHistory = "/v1/funding-history"
|
||||
|
||||
kucoinFuturesAccountOverview = "/v1/account-overview"
|
||||
kucoinFuturesTransactionHistory = "/v1/transaction-history"
|
||||
kucoinFuturesSubAccountAPI = "/v1/sub/api-key"
|
||||
kucoinFuturesDepositAddress = "/v1/deposit-address"
|
||||
kucoinFuturesDepositsList = "/v1/deposit-list"
|
||||
kucoinFuturesWithdrawalLimit = "/v1/withdrawals/quotas"
|
||||
kucoinFuturesWithdrawalList = "/v1/withdrawal-list"
|
||||
kucoinFuturesCancelWithdrawal = "/v1/withdrawals/"
|
||||
kucoinFuturesTransferFundtoMainAccount = "/v3/transfer-out"
|
||||
kucoinFuturesTransferFundtoFuturesAccount = "/v1/transfer-in"
|
||||
kucoinFuturesTransferOutList = "/v1/transfer-list"
|
||||
kucoinFuturesCancelTransferOut = "/v1/cancel/transfer-out"
|
||||
kucoinFuturesOrder = "/v1/orders"
|
||||
kucoinFuturesStopOrder = "/v1/stopOrders"
|
||||
)
|
||||
|
||||
// GetFuturesOpenContracts gets all open futures contract with its details
|
||||
func (ku *Kucoin) GetFuturesOpenContracts(ctx context.Context) ([]Contract, error) {
|
||||
var resp []Contract
|
||||
return resp, ku.SendHTTPRequest(ctx, exchange.RestFutures, defaultFuturesEPL, kucoinFuturesOpenContracts, &resp)
|
||||
return resp, ku.SendHTTPRequest(ctx, exchange.RestFutures, futuresOpenContractsEPL, "/v1/contracts/active", &resp)
|
||||
}
|
||||
|
||||
// GetFuturesContract get contract details
|
||||
func (ku *Kucoin) GetFuturesContract(ctx context.Context, symbol string) (*Contract, error) {
|
||||
if symbol == "" {
|
||||
return nil, errors.New("symbol can't be empty")
|
||||
return nil, currency.ErrSymbolStringEmpty
|
||||
}
|
||||
var resp *Contract
|
||||
return resp, ku.SendHTTPRequest(ctx, exchange.RestFutures, defaultFuturesEPL, kucoinFuturesContract+symbol, &resp)
|
||||
return resp, ku.SendHTTPRequest(ctx, exchange.RestFutures, futuresContractEPL, "/v1/contracts/"+symbol, &resp)
|
||||
}
|
||||
|
||||
// GetFuturesTicker get real time ticker
|
||||
func (ku *Kucoin) GetFuturesTicker(ctx context.Context, symbol string) (*FuturesTicker, error) {
|
||||
if symbol == "" {
|
||||
return nil, errors.New("symbol can't be empty")
|
||||
return nil, currency.ErrSymbolStringEmpty
|
||||
}
|
||||
params := url.Values{}
|
||||
params.Set("symbol", symbol)
|
||||
var resp *FuturesTicker
|
||||
return resp, ku.SendHTTPRequest(ctx, exchange.RestFutures, defaultFuturesEPL, common.EncodeURLValues(kucoinFuturesTicker, params), &resp)
|
||||
return resp, ku.SendHTTPRequest(ctx, exchange.RestFutures, futuresTickerEPL, "/v1/ticker?symbol="+symbol, &resp)
|
||||
}
|
||||
|
||||
// GetFuturesTickers does n * REST requests based on enabled pairs of the futures asset type
|
||||
@@ -162,12 +116,12 @@ func (ku *Kucoin) GetFuturesTickers(ctx context.Context) ([]*ticker.Price, error
|
||||
// GetFuturesOrderbook gets full orderbook for a specified symbol
|
||||
func (ku *Kucoin) GetFuturesOrderbook(ctx context.Context, symbol string) (*Orderbook, error) {
|
||||
if symbol == "" {
|
||||
return nil, errors.New("symbol can't be empty")
|
||||
return nil, currency.ErrSymbolStringEmpty
|
||||
}
|
||||
params := url.Values{}
|
||||
params.Set("symbol", symbol)
|
||||
var o futuresOrderbookResponse
|
||||
err := ku.SendHTTPRequest(ctx, exchange.RestFutures, futuresRetrieveFullOrderbookLevel2EPL, common.EncodeURLValues(kucoinFuturesFullOrderbook, params), &o)
|
||||
err := ku.SendHTTPRequest(ctx, exchange.RestFutures, futuresOrderbookEPL, common.EncodeURLValues("/v1/level2/snapshot", params), &o)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -177,12 +131,12 @@ func (ku *Kucoin) GetFuturesOrderbook(ctx context.Context, symbol string) (*Orde
|
||||
// GetFuturesPartOrderbook20 gets orderbook for a specified symbol with depth 20
|
||||
func (ku *Kucoin) GetFuturesPartOrderbook20(ctx context.Context, symbol string) (*Orderbook, error) {
|
||||
if symbol == "" {
|
||||
return nil, errors.New("symbol can't be empty")
|
||||
return nil, currency.ErrSymbolStringEmpty
|
||||
}
|
||||
params := url.Values{}
|
||||
params.Set("symbol", symbol)
|
||||
var o futuresOrderbookResponse
|
||||
err := ku.SendHTTPRequest(ctx, exchange.RestFutures, defaultFuturesEPL, common.EncodeURLValues(kucoinFuturesPartOrderbook20, params), &o)
|
||||
err := ku.SendHTTPRequest(ctx, exchange.RestFutures, futuresPartOrderbookDepth20EPL, common.EncodeURLValues("/v1/level2/depth20", params), &o)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -192,12 +146,12 @@ func (ku *Kucoin) GetFuturesPartOrderbook20(ctx context.Context, symbol string)
|
||||
// GetFuturesPartOrderbook100 gets orderbook for a specified symbol with depth 100
|
||||
func (ku *Kucoin) GetFuturesPartOrderbook100(ctx context.Context, symbol string) (*Orderbook, error) {
|
||||
if symbol == "" {
|
||||
return nil, errors.New("symbol can't be empty")
|
||||
return nil, currency.ErrSymbolStringEmpty
|
||||
}
|
||||
params := url.Values{}
|
||||
params.Set("symbol", symbol)
|
||||
var o futuresOrderbookResponse
|
||||
err := ku.SendHTTPRequest(ctx, exchange.RestFutures, defaultFuturesEPL, common.EncodeURLValues(kucoinFuturesPartOrderbook100, params), &o)
|
||||
err := ku.SendHTTPRequest(ctx, exchange.RestFutures, futuresPartOrderbookDepth100EPL, common.EncodeURLValues("/v1/level2/depth100", params), &o)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -207,22 +161,19 @@ func (ku *Kucoin) GetFuturesPartOrderbook100(ctx context.Context, symbol string)
|
||||
// GetFuturesTradeHistory get last 100 trades for symbol
|
||||
func (ku *Kucoin) GetFuturesTradeHistory(ctx context.Context, symbol string) ([]FuturesTrade, error) {
|
||||
if symbol == "" {
|
||||
return nil, errors.New("symbol can't be empty")
|
||||
return nil, currency.ErrSymbolStringEmpty
|
||||
}
|
||||
params := url.Values{}
|
||||
params.Set("symbol", symbol)
|
||||
var resp []FuturesTrade
|
||||
return resp, ku.SendHTTPRequest(ctx, exchange.RestFutures, defaultFuturesEPL, common.EncodeURLValues(kucoinFuturesTradeHistory, params), &resp)
|
||||
return resp, ku.SendHTTPRequest(ctx, exchange.RestFutures, futuresTransactionHistoryEPL, "/v1/trade/history?symbol="+symbol, &resp)
|
||||
}
|
||||
|
||||
// GetFuturesInterestRate get interest rate
|
||||
func (ku *Kucoin) GetFuturesInterestRate(ctx context.Context, symbol string, startAt, endAt time.Time, reverse, forward bool, offset, maxCount int64) (*FundingInterestRateResponse, error) {
|
||||
if symbol == "" {
|
||||
return nil, errors.New("symbol can't be empty")
|
||||
return nil, currency.ErrSymbolStringEmpty
|
||||
}
|
||||
params := url.Values{}
|
||||
params.Set("symbol", symbol)
|
||||
|
||||
if !startAt.IsZero() {
|
||||
params.Set("startAt", strconv.FormatInt(startAt.UnixMilli(), 10))
|
||||
}
|
||||
@@ -238,13 +189,13 @@ func (ku *Kucoin) GetFuturesInterestRate(ctx context.Context, symbol string, sta
|
||||
params.Set("maxCount", strconv.FormatInt(maxCount, 10))
|
||||
}
|
||||
var resp *FundingInterestRateResponse
|
||||
return resp, ku.SendHTTPRequest(ctx, exchange.RestFutures, defaultFuturesEPL, common.EncodeURLValues(kucoinFuturesInterestRate, params), &resp)
|
||||
return resp, ku.SendHTTPRequest(ctx, exchange.RestFutures, futuresInterestRateEPL, common.EncodeURLValues("/v1/interest/query", params), &resp)
|
||||
}
|
||||
|
||||
// GetFuturesIndexList retrieves futures index information for a symbol
|
||||
func (ku *Kucoin) GetFuturesIndexList(ctx context.Context, symbol string, startAt, endAt time.Time, reverse, forward bool, offset, maxCount int64) (*FuturesIndexResponse, error) {
|
||||
if symbol == "" {
|
||||
return nil, errors.New("symbol can't be empty")
|
||||
return nil, currency.ErrSymbolStringEmpty
|
||||
}
|
||||
params := url.Values{}
|
||||
params.Set("symbol", symbol)
|
||||
@@ -263,22 +214,22 @@ func (ku *Kucoin) GetFuturesIndexList(ctx context.Context, symbol string, startA
|
||||
params.Set("maxCount", strconv.FormatInt(maxCount, 10))
|
||||
}
|
||||
var resp *FuturesIndexResponse
|
||||
return resp, ku.SendHTTPRequest(ctx, exchange.RestFutures, defaultFuturesEPL, common.EncodeURLValues(kucoinFuturesIndex, params), &resp)
|
||||
return resp, ku.SendHTTPRequest(ctx, exchange.RestFutures, futuresIndexListEPL, common.EncodeURLValues("/v1/index/query", params), &resp)
|
||||
}
|
||||
|
||||
// GetFuturesCurrentMarkPrice get current mark price
|
||||
func (ku *Kucoin) GetFuturesCurrentMarkPrice(ctx context.Context, symbol string) (*FuturesMarkPrice, error) {
|
||||
if symbol == "" {
|
||||
return nil, errors.New("symbol can't be empty")
|
||||
return nil, currency.ErrSymbolStringEmpty
|
||||
}
|
||||
var resp *FuturesMarkPrice
|
||||
return resp, ku.SendHTTPRequest(ctx, exchange.RestFutures, defaultFuturesEPL, fmt.Sprintf(kucoinFuturesMarkPrice, symbol), &resp)
|
||||
return resp, ku.SendHTTPRequest(ctx, exchange.RestFutures, futuresCurrentMarkPriceEPL, "/v1/mark-price/"+symbol+"/current", &resp)
|
||||
}
|
||||
|
||||
// GetFuturesPremiumIndex get premium index
|
||||
func (ku *Kucoin) GetFuturesPremiumIndex(ctx context.Context, symbol string, startAt, endAt time.Time, reverse, forward bool, offset, maxCount int64) (*FuturesInterestRateResponse, error) {
|
||||
if symbol == "" {
|
||||
return nil, errors.New("symbol can't be empty")
|
||||
return nil, currency.ErrSymbolStringEmpty
|
||||
}
|
||||
params := url.Values{}
|
||||
params.Set("symbol", symbol)
|
||||
@@ -297,16 +248,39 @@ func (ku *Kucoin) GetFuturesPremiumIndex(ctx context.Context, symbol string, sta
|
||||
params.Set("maxCount", strconv.FormatInt(maxCount, 10))
|
||||
}
|
||||
var resp *FuturesInterestRateResponse
|
||||
return resp, ku.SendHTTPRequest(ctx, exchange.RestFutures, defaultFuturesEPL, common.EncodeURLValues(kucoinFuturesPremiumIndex, params), &resp)
|
||||
return resp, ku.SendHTTPRequest(ctx, exchange.RestFutures, futuresPremiumIndexEPL, common.EncodeURLValues("/v1/premium/query", params), &resp)
|
||||
}
|
||||
|
||||
// Get24HourFuturesTransactionVolume retrieves a 24 hour transaction volume
|
||||
func (ku *Kucoin) Get24HourFuturesTransactionVolume(ctx context.Context) (*TransactionVolume, error) {
|
||||
var resp *TransactionVolume
|
||||
return resp, ku.SendAuthHTTPRequest(ctx, exchange.RestFutures, futuresTransactionVolumeEPL, http.MethodGet, "/v1/trade-statistics", nil, &resp)
|
||||
}
|
||||
|
||||
// GetFuturesCurrentFundingRate get current funding rate
|
||||
func (ku *Kucoin) GetFuturesCurrentFundingRate(ctx context.Context, symbol string) (*FuturesFundingRate, error) {
|
||||
if symbol == "" {
|
||||
return nil, errors.New("symbol can't be empty")
|
||||
return nil, currency.ErrSymbolStringEmpty
|
||||
}
|
||||
var resp *FuturesFundingRate
|
||||
return resp, ku.SendHTTPRequest(ctx, exchange.RestFutures, defaultFuturesEPL, fmt.Sprintf(kucoinFuturesFundingRate, symbol), &resp)
|
||||
return resp, ku.SendHTTPRequest(ctx, exchange.RestFutures, futuresCurrentFundingRateEPL, "/v1/funding-rate/"+symbol+"/current", &resp)
|
||||
}
|
||||
|
||||
// GetPublicFundingRate query the funding rate at each settlement time point within a certain time range of the corresponding contract
|
||||
func (ku *Kucoin) GetPublicFundingRate(ctx context.Context, symbol string, from, to time.Time) ([]FundingHistoryItem, error) {
|
||||
if symbol == "" {
|
||||
return nil, currency.ErrSymbolStringEmpty
|
||||
}
|
||||
err := common.StartEndTimeCheck(from, to)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
params := url.Values{}
|
||||
params.Set("symbol", symbol)
|
||||
params.Set("from", strconv.FormatInt(from.UnixMilli(), 10))
|
||||
params.Set("to", strconv.FormatInt(to.UnixMilli(), 10))
|
||||
var resp []FundingHistoryItem
|
||||
return resp, ku.SendHTTPRequest(ctx, exchange.RestFutures, futuresPublicFundingRateEPL, common.EncodeURLValues("/v1/contract/funding-rates", params), &resp)
|
||||
}
|
||||
|
||||
// GetFuturesServerTime get server time
|
||||
@@ -315,7 +289,7 @@ func (ku *Kucoin) GetFuturesServerTime(ctx context.Context) (time.Time, error) {
|
||||
Data convert.ExchangeTime `json:"data"`
|
||||
Error
|
||||
}{}
|
||||
err := ku.SendHTTPRequest(ctx, exchange.RestFutures, defaultFuturesEPL, kucoinFuturesServerTime, &resp)
|
||||
err := ku.SendHTTPRequest(ctx, exchange.RestFutures, futuresServerTimeEPL, "/v1/timestamp", &resp)
|
||||
if err != nil {
|
||||
return time.Time{}, err
|
||||
}
|
||||
@@ -325,23 +299,23 @@ func (ku *Kucoin) GetFuturesServerTime(ctx context.Context) (time.Time, error) {
|
||||
// GetFuturesServiceStatus get service status
|
||||
func (ku *Kucoin) GetFuturesServiceStatus(ctx context.Context) (*FuturesServiceStatus, error) {
|
||||
var resp *FuturesServiceStatus
|
||||
return resp, ku.SendHTTPRequest(ctx, exchange.RestFutures, defaultFuturesEPL, kucoinFuturesServiceStatus, &resp)
|
||||
return resp, ku.SendHTTPRequest(ctx, exchange.RestFutures, futuresServiceStatusEPL, "/v1/status", &resp)
|
||||
}
|
||||
|
||||
// GetFuturesKline get contract's kline data
|
||||
func (ku *Kucoin) GetFuturesKline(ctx context.Context, granularity int64, symbol string, from, to time.Time) ([]FuturesKline, error) {
|
||||
if granularity == 0 {
|
||||
return nil, errors.New("granularity can not be empty")
|
||||
return nil, kline.ErrInvalidInterval
|
||||
}
|
||||
if !slices.Contains(validGranularity, strconv.FormatInt(granularity, 10)) {
|
||||
return nil, errors.New("invalid granularity")
|
||||
return nil, fmt.Errorf("%w, invalid granularity", kline.ErrUnsupportedInterval)
|
||||
}
|
||||
if symbol == "" {
|
||||
return nil, currency.ErrSymbolStringEmpty
|
||||
}
|
||||
params := url.Values{}
|
||||
// The granularity (granularity parameter of K-line) represents the number of minutes, the available granularity scope is: 1,5,15,30,60,120,240,480,720,1440,10080. Requests beyond the above range will be rejected.
|
||||
// The granularity (granularity parameter of K-line) represents the number of minutes, the available granularity scope is: 1,5,15,30,60,120,240,480,720,1440,10080. Requests beyond the above range will be rejected
|
||||
params.Set("granularity", strconv.FormatInt(granularity, 10))
|
||||
if symbol == "" {
|
||||
return nil, errors.New("symbol can't be empty")
|
||||
}
|
||||
params.Set("symbol", symbol)
|
||||
if !from.IsZero() {
|
||||
params.Set("from", strconv.FormatInt(from.UnixMilli(), 10))
|
||||
@@ -350,7 +324,7 @@ func (ku *Kucoin) GetFuturesKline(ctx context.Context, granularity int64, symbol
|
||||
params.Set("to", strconv.FormatInt(to.UnixMilli(), 10))
|
||||
}
|
||||
var resp [][6]float64
|
||||
err := ku.SendHTTPRequest(ctx, exchange.RestFutures, defaultFuturesEPL, common.EncodeURLValues(kucoinFuturesKline, params), &resp)
|
||||
err := ku.SendHTTPRequest(ctx, exchange.RestFutures, futuresKlineEPL, common.EncodeURLValues("/v1/kline/query", params), &resp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -370,43 +344,9 @@ func (ku *Kucoin) GetFuturesKline(ctx context.Context, granularity int64, symbol
|
||||
|
||||
// PostFuturesOrder used to place two types of futures orders: limit and market
|
||||
func (ku *Kucoin) PostFuturesOrder(ctx context.Context, arg *FuturesOrderParam) (string, error) {
|
||||
if arg.Leverage < 0.01 {
|
||||
return "", fmt.Errorf("%w must be greater than 0.01", errInvalidLeverage)
|
||||
}
|
||||
if arg.ClientOrderID == "" {
|
||||
return "", errInvalidClientOrderID
|
||||
}
|
||||
if arg.Side == "" {
|
||||
return "", fmt.Errorf("%w, empty order side", order.ErrSideIsInvalid)
|
||||
}
|
||||
if arg.Symbol.IsEmpty() {
|
||||
return "", currency.ErrCurrencyPairEmpty
|
||||
}
|
||||
if arg.Stop != "" {
|
||||
if arg.StopPriceType == "" {
|
||||
return "", errInvalidStopPriceType
|
||||
}
|
||||
if arg.StopPrice <= 0 {
|
||||
return "", fmt.Errorf("%w, stopPrice is required", errInvalidPrice)
|
||||
}
|
||||
}
|
||||
switch arg.OrderType {
|
||||
case "limit", "":
|
||||
if arg.Price <= 0 {
|
||||
return "", fmt.Errorf("%w %f", errInvalidPrice, arg.Price)
|
||||
}
|
||||
if arg.Size <= 0 {
|
||||
return "", fmt.Errorf("%w, must be non-zero positive value", errInvalidSize)
|
||||
}
|
||||
if arg.VisibleSize < 0 {
|
||||
return "", fmt.Errorf("%w, visible size must be non-zero positive value", errInvalidSize)
|
||||
}
|
||||
case "market":
|
||||
if arg.Size <= 0 {
|
||||
return "", fmt.Errorf("%w, market size must be > 0", errInvalidSize)
|
||||
}
|
||||
default:
|
||||
return "", fmt.Errorf("%w, order type= %s", order.ErrTypeIsInvalid, arg.OrderType)
|
||||
err := ku.FillFuturesPostOrderArgumentFilter(arg)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
resp := struct {
|
||||
OrderID string `json:"orderId"`
|
||||
@@ -414,20 +354,110 @@ func (ku *Kucoin) PostFuturesOrder(ctx context.Context, arg *FuturesOrderParam)
|
||||
return resp.OrderID, ku.SendAuthHTTPRequest(ctx, exchange.RestFutures, futuresPlaceOrderEPL, http.MethodPost, kucoinFuturesOrder, &arg, &resp)
|
||||
}
|
||||
|
||||
// CancelFuturesOrder used to cancel single order previously placed including a stop order
|
||||
func (ku *Kucoin) CancelFuturesOrder(ctx context.Context, orderID string) ([]string, error) {
|
||||
// PostFuturesOrderTest a test endpoint to place a single futures order
|
||||
func (ku *Kucoin) PostFuturesOrderTest(ctx context.Context, arg *FuturesOrderParam) (string, error) {
|
||||
err := ku.FillFuturesPostOrderArgumentFilter(arg)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
resp := struct {
|
||||
OrderID string `json:"orderId"`
|
||||
}{}
|
||||
return resp.OrderID, ku.SendAuthHTTPRequest(ctx, exchange.RestFutures, futuresPlaceOrderEPL, http.MethodPost, kucoinFuturesOrder+"/test", &arg, &resp)
|
||||
}
|
||||
|
||||
// FillFuturesPostOrderArgumentFilter verifies futures order request parameters
|
||||
func (ku *Kucoin) FillFuturesPostOrderArgumentFilter(arg *FuturesOrderParam) error {
|
||||
if *arg == (FuturesOrderParam{}) {
|
||||
return common.ErrNilPointer
|
||||
}
|
||||
if arg.Leverage <= 0 {
|
||||
return errInvalidLeverage
|
||||
}
|
||||
if arg.ClientOrderID == "" {
|
||||
return order.ErrClientOrderIDMustBeSet
|
||||
}
|
||||
if arg.Side == "" {
|
||||
return fmt.Errorf("%w, empty order side", order.ErrSideIsInvalid)
|
||||
}
|
||||
if arg.Symbol.IsEmpty() {
|
||||
return currency.ErrCurrencyPairEmpty
|
||||
}
|
||||
if arg.Stop != "" {
|
||||
if arg.StopPriceType == "" {
|
||||
return errInvalidStopPriceType
|
||||
}
|
||||
if arg.StopPrice <= 0 {
|
||||
return fmt.Errorf("%w, stopPrice is required", order.ErrPriceBelowMin)
|
||||
}
|
||||
}
|
||||
switch arg.OrderType {
|
||||
case "limit", "":
|
||||
if arg.Price <= 0 {
|
||||
return fmt.Errorf("%w %f", order.ErrPriceBelowMin, arg.Price)
|
||||
}
|
||||
if arg.Size <= 0 {
|
||||
return fmt.Errorf("%w, must be non-zero positive value", order.ErrAmountBelowMin)
|
||||
}
|
||||
if arg.VisibleSize < 0 {
|
||||
return fmt.Errorf("%w, visible size must be non-zero positive value", order.ErrAmountBelowMin)
|
||||
}
|
||||
case "market":
|
||||
if arg.Size <= 0 {
|
||||
return fmt.Errorf("%w, market size must be > 0", order.ErrAmountBelowMin)
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("%w, order type= %s", order.ErrTypeIsInvalid, arg.OrderType)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// PlaceMultipleFuturesOrders used to place multiple futures orders
|
||||
// The maximum limit orders for a single contract is 100 per account, and the maximum stop orders for a single contract is 50 per account
|
||||
func (ku *Kucoin) PlaceMultipleFuturesOrders(ctx context.Context, args []FuturesOrderParam) ([]FuturesOrderRespItem, error) {
|
||||
if len(args) == 0 {
|
||||
return nil, fmt.Errorf("%w, not order to place", common.ErrEmptyParams)
|
||||
}
|
||||
var err error
|
||||
for x := range args {
|
||||
err = ku.FillFuturesPostOrderArgumentFilter(&args[x])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
var resp []FuturesOrderRespItem
|
||||
return resp, ku.SendAuthHTTPRequest(ctx, exchange.RestFutures, multipleFuturesOrdersEPL, http.MethodPost, "/v1/orders/multi", args, &resp)
|
||||
}
|
||||
|
||||
// CancelFuturesOrderByOrderID used to cancel single order previously placed including a stop order
|
||||
func (ku *Kucoin) CancelFuturesOrderByOrderID(ctx context.Context, orderID string) ([]string, error) {
|
||||
return ku.cancelFuturesOrderByID(ctx, orderID, "/v1/orders/", "")
|
||||
}
|
||||
|
||||
// CancelFuturesOrderByClientOrderID cancels a futures order by using client order ID
|
||||
func (ku *Kucoin) CancelFuturesOrderByClientOrderID(ctx context.Context, symbol, clientOrderID string) ([]string, error) {
|
||||
if symbol == "" {
|
||||
return nil, currency.ErrSymbolStringEmpty
|
||||
}
|
||||
return ku.cancelFuturesOrderByID(ctx, clientOrderID, "/v1/orders/client-order/", symbol)
|
||||
}
|
||||
|
||||
func (ku *Kucoin) cancelFuturesOrderByID(ctx context.Context, id, path, symbol string) ([]string, error) {
|
||||
if id == "" {
|
||||
return nil, order.ErrOrderIDNotSet
|
||||
}
|
||||
params := url.Values{}
|
||||
if symbol != "" {
|
||||
params.Set("symbol", symbol)
|
||||
}
|
||||
resp := struct {
|
||||
CancelledOrderIDs []string `json:"cancelledOrderIds"`
|
||||
}{}
|
||||
|
||||
if orderID == "" {
|
||||
return resp.CancelledOrderIDs, errors.New("orderID can't be empty")
|
||||
}
|
||||
return resp.CancelledOrderIDs, ku.SendAuthHTTPRequest(ctx, exchange.RestFutures, futuresCancelAnOrderEPL, http.MethodDelete, kucoinFuturesCancelOrder+orderID, nil, &resp)
|
||||
return resp.CancelledOrderIDs, ku.SendAuthHTTPRequest(ctx, exchange.RestFutures, futuresCancelAnOrderEPL, http.MethodDelete, common.EncodeURLValues(path+id, params), nil, &resp)
|
||||
}
|
||||
|
||||
// CancelAllFuturesOpenOrders used to cancel all futures order excluding stop orders
|
||||
func (ku *Kucoin) CancelAllFuturesOpenOrders(ctx context.Context, symbol string) ([]string, error) {
|
||||
// CancelMultipleFuturesLimitOrders used to cancel all futures order excluding stop orders
|
||||
func (ku *Kucoin) CancelMultipleFuturesLimitOrders(ctx context.Context, symbol string) ([]string, error) {
|
||||
params := url.Values{}
|
||||
if symbol != "" {
|
||||
params.Set("symbol", symbol)
|
||||
@@ -447,7 +477,7 @@ func (ku *Kucoin) CancelAllFuturesStopOrders(ctx context.Context, symbol string)
|
||||
resp := struct {
|
||||
CancelledOrderIDs []string `json:"cancelledOrderIds"`
|
||||
}{}
|
||||
return resp.CancelledOrderIDs, ku.SendAuthHTTPRequest(ctx, exchange.RestFutures, defaultFuturesEPL, http.MethodDelete, common.EncodeURLValues(kucoinFuturesStopOrder, params), nil, &resp)
|
||||
return resp.CancelledOrderIDs, ku.SendAuthHTTPRequest(ctx, exchange.RestFutures, futuresCancelMultipleLimitOrdersEPL, http.MethodDelete, common.EncodeURLValues(kucoinFuturesStopOrder, params), nil, &resp)
|
||||
}
|
||||
|
||||
// GetFuturesOrders gets the user current futures order list
|
||||
@@ -494,30 +524,43 @@ func (ku *Kucoin) GetUntriggeredFuturesStopOrders(ctx context.Context, symbol, s
|
||||
params.Set("endAt", strconv.FormatInt(endAt.UnixMilli(), 10))
|
||||
}
|
||||
var resp *FutureOrdersResponse
|
||||
return resp, ku.SendAuthHTTPRequest(ctx, exchange.RestFutures, defaultFuturesEPL, http.MethodGet, common.EncodeURLValues(kucoinFuturesStopOrder, params), nil, &resp)
|
||||
return resp, ku.SendAuthHTTPRequest(ctx, exchange.RestFutures, cancelUntriggeredFuturesStopOrdersEPL, http.MethodGet, common.EncodeURLValues(kucoinFuturesStopOrder, params), nil, &resp)
|
||||
}
|
||||
|
||||
// GetFuturesRecentCompletedOrders gets list of recent 1000 orders in the last 24 hours
|
||||
func (ku *Kucoin) GetFuturesRecentCompletedOrders(ctx context.Context) ([]FuturesOrder, error) {
|
||||
func (ku *Kucoin) GetFuturesRecentCompletedOrders(ctx context.Context, symbol string) ([]FuturesOrder, error) {
|
||||
params := url.Values{}
|
||||
if symbol != "" {
|
||||
params.Set("symbol", symbol)
|
||||
}
|
||||
var resp []FuturesOrder
|
||||
return resp, ku.SendAuthHTTPRequest(ctx, exchange.RestFutures, defaultFuturesEPL, http.MethodGet, kucoinFuturesRecentCompletedOrder, nil, &resp)
|
||||
return resp, ku.SendAuthHTTPRequest(ctx, exchange.RestFutures, futuresRecentCompletedOrdersEPL, http.MethodGet, common.EncodeURLValues("/v1/recentDoneOrders", params), nil, &resp)
|
||||
}
|
||||
|
||||
// GetFuturesOrderDetails gets single order details by order ID
|
||||
func (ku *Kucoin) GetFuturesOrderDetails(ctx context.Context, orderID string) (*FuturesOrder, error) {
|
||||
var resp *FuturesOrder
|
||||
return resp, ku.SendAuthHTTPRequest(ctx, exchange.RestFutures, defaultFuturesEPL, http.MethodGet, kucoinFuturesGetOrderDetails+orderID, nil, &resp)
|
||||
}
|
||||
|
||||
// GetFuturesOrderDetailsByClientID gets single order details by client ID
|
||||
func (ku *Kucoin) GetFuturesOrderDetailsByClientID(ctx context.Context, clientID string) (*FuturesOrder, error) {
|
||||
if clientID == "" {
|
||||
return nil, errors.New("clientID can't be empty")
|
||||
func (ku *Kucoin) GetFuturesOrderDetails(ctx context.Context, orderID, clientOrderID string) (*FuturesOrder, error) {
|
||||
path := "/v1/orders/"
|
||||
if orderID == "" && clientOrderID == "" {
|
||||
return nil, fmt.Errorf("%w either client order ID or order id required", order.ErrOrderIDNotSet)
|
||||
}
|
||||
if orderID == "" {
|
||||
path = "/v1/orders/byClientOid"
|
||||
}
|
||||
params := url.Values{}
|
||||
params.Set("clientOid", clientID)
|
||||
if clientOrderID != "" {
|
||||
params.Set("clientOid", clientOrderID)
|
||||
}
|
||||
var resp *FuturesOrder
|
||||
return resp, ku.SendAuthHTTPRequest(ctx, exchange.RestFutures, defaultFuturesEPL, http.MethodGet, common.EncodeURLValues(kucoinFuturesGetOrderDetailsByClientID, params), nil, &resp)
|
||||
return resp, ku.SendAuthHTTPRequest(ctx, exchange.RestFutures, futuresOrdersByIDEPL, http.MethodGet, common.EncodeURLValues(path+orderID, params), nil, &resp)
|
||||
}
|
||||
|
||||
// GetFuturesOrderDetailsByClientOrderID gets single order details by client ID
|
||||
func (ku *Kucoin) GetFuturesOrderDetailsByClientOrderID(ctx context.Context, clientOrderID string) (*FuturesOrder, error) {
|
||||
if clientOrderID == "" {
|
||||
return nil, order.ErrClientOrderIDMustBeSet
|
||||
}
|
||||
var resp *FuturesOrder
|
||||
return resp, ku.SendAuthHTTPRequest(ctx, exchange.RestFutures, futuresOrderDetailsByClientOrderIDEPL, http.MethodGet, "/v1/orders/byClientOid?clientOid="+clientOrderID, nil, &resp)
|
||||
}
|
||||
|
||||
// GetFuturesFills gets list of recent fills
|
||||
@@ -542,96 +585,119 @@ func (ku *Kucoin) GetFuturesFills(ctx context.Context, orderID, symbol, side, or
|
||||
params.Set("endAt", strconv.FormatInt(endAt.UnixMilli(), 10))
|
||||
}
|
||||
var resp *FutureFillsResponse
|
||||
return resp, ku.SendAuthHTTPRequest(ctx, exchange.RestFutures, futuresRetrieveFillsEPL, http.MethodGet, common.EncodeURLValues(kucoinFuturesFills, params), nil, &resp)
|
||||
return resp, ku.SendAuthHTTPRequest(ctx, exchange.RestFutures, futuresRetrieveFillsEPL, http.MethodGet, common.EncodeURLValues("/v1/fills", params), nil, &resp)
|
||||
}
|
||||
|
||||
// GetFuturesRecentFills gets list of 1000 recent fills in the last 24 hrs
|
||||
func (ku *Kucoin) GetFuturesRecentFills(ctx context.Context) ([]FuturesFill, error) {
|
||||
var resp []FuturesFill
|
||||
return resp, ku.SendAuthHTTPRequest(ctx, exchange.RestFutures, futuresRecentFillsEPL, http.MethodGet, kucoinFuturesRecentFills, nil, &resp)
|
||||
return resp, ku.SendAuthHTTPRequest(ctx, exchange.RestFutures, futuresRecentFillsEPL, http.MethodGet, "/v1/recentFills", nil, &resp)
|
||||
}
|
||||
|
||||
// GetFuturesOpenOrderStats gets the total number and value of the all your active orders
|
||||
func (ku *Kucoin) GetFuturesOpenOrderStats(ctx context.Context, symbol string) (*FuturesOpenOrderStats, error) {
|
||||
if symbol == "" {
|
||||
return nil, errors.New("symbol can't be empty")
|
||||
return nil, currency.ErrSymbolStringEmpty
|
||||
}
|
||||
params := url.Values{}
|
||||
params.Set("symbol", symbol)
|
||||
var resp *FuturesOpenOrderStats
|
||||
return resp, ku.SendAuthHTTPRequest(ctx, exchange.RestFutures, defaultFuturesEPL, http.MethodGet, common.EncodeURLValues(kucoinFuturesOpenOrderStats, params), nil, &resp)
|
||||
return resp, ku.SendAuthHTTPRequest(ctx, exchange.RestFutures, futuresOpenOrderStatsEPL, http.MethodGet, "/v1/openOrderStatistics?symbol="+symbol, nil, &resp)
|
||||
}
|
||||
|
||||
// GetFuturesPosition gets the position details of a specified position
|
||||
func (ku *Kucoin) GetFuturesPosition(ctx context.Context, symbol string) (*FuturesPosition, error) {
|
||||
if symbol == "" {
|
||||
return nil, errors.New("symbol can't be empty")
|
||||
return nil, currency.ErrSymbolStringEmpty
|
||||
}
|
||||
params := url.Values{}
|
||||
params.Set("symbol", symbol)
|
||||
var resp *FuturesPosition
|
||||
return resp, ku.SendAuthHTTPRequest(ctx, exchange.RestFutures, defaultFuturesEPL, http.MethodGet, common.EncodeURLValues(kucoinFuturesPosition, params), nil, &resp)
|
||||
return resp, ku.SendAuthHTTPRequest(ctx, exchange.RestFutures, futuresPositionEPL, http.MethodGet, "/v1/position?symbol="+symbol, nil, &resp)
|
||||
}
|
||||
|
||||
// GetFuturesPositionList gets the list of position with details
|
||||
func (ku *Kucoin) GetFuturesPositionList(ctx context.Context) ([]FuturesPosition, error) {
|
||||
var resp []FuturesPosition
|
||||
return resp, ku.SendAuthHTTPRequest(ctx, exchange.RestFutures, futuresRetrievePositionListEPL, http.MethodGet, kucoinFuturesPositionList, nil, &resp)
|
||||
return resp, ku.SendAuthHTTPRequest(ctx, exchange.RestFutures, futuresPositionListEPL, http.MethodGet, "/v1/positions", nil, &resp)
|
||||
}
|
||||
|
||||
// SetAutoDepositMargin enable/disable of auto-deposit margin
|
||||
func (ku *Kucoin) SetAutoDepositMargin(ctx context.Context, symbol string, status bool) (bool, error) {
|
||||
params := make(map[string]interface{})
|
||||
if symbol == "" {
|
||||
return false, errors.New("symbol can't be empty")
|
||||
return false, currency.ErrSymbolStringEmpty
|
||||
}
|
||||
params := make(map[string]interface{})
|
||||
params["symbol"] = symbol
|
||||
params["status"] = status
|
||||
var resp bool
|
||||
return resp, ku.SendAuthHTTPRequest(ctx, exchange.RestFutures, defaultFuturesEPL, http.MethodPost, kucoinFuturesSetAutoDeposit, params, &resp)
|
||||
return resp, ku.SendAuthHTTPRequest(ctx, exchange.RestFutures, setAutoDepositMarginEPL, http.MethodPost, "/v1/position/margin/auto-deposit-status", params, &resp)
|
||||
}
|
||||
|
||||
// GetMaxWithdrawMargin query the maximum amount of margin that the current position supports withdrawal
|
||||
func (ku *Kucoin) GetMaxWithdrawMargin(ctx context.Context, symbol string) (float64, error) {
|
||||
if symbol == "" {
|
||||
return 0, currency.ErrSymbolStringEmpty
|
||||
}
|
||||
var resp types.Number
|
||||
return resp.Float64(), ku.SendAuthHTTPRequest(ctx, exchange.RestFutures, maxWithdrawMarginEPL, http.MethodGet, "/v1/margin/maxWithdrawMargin?symbol="+symbol, nil, &resp)
|
||||
}
|
||||
|
||||
// RemoveMarginManually removes a margin manually
|
||||
func (ku *Kucoin) RemoveMarginManually(ctx context.Context, arg *WithdrawMarginResponse) (*MarginRemovingResponse, error) {
|
||||
if *arg == (WithdrawMarginResponse{}) {
|
||||
return nil, common.ErrNilPointer
|
||||
}
|
||||
if arg.Symbol == "" {
|
||||
return nil, currency.ErrSymbolStringEmpty
|
||||
}
|
||||
if arg.WithdrawAmount <= 0 {
|
||||
return nil, fmt.Errorf("%w, withdrawAmount must be greater than 0", order.ErrAmountBelowMin)
|
||||
}
|
||||
var resp *MarginRemovingResponse
|
||||
return resp, ku.SendAuthHTTPRequest(ctx, exchange.RestSpot, removeMarginManuallyEPL, http.MethodPost, "/v1/margin/withdrawMargin", arg, &resp)
|
||||
}
|
||||
|
||||
// AddMargin is used to add margin manually
|
||||
func (ku *Kucoin) AddMargin(ctx context.Context, symbol, uniqueID string, margin float64) (*FuturesPosition, error) {
|
||||
params := make(map[string]interface{})
|
||||
if symbol == "" {
|
||||
return nil, errors.New("symbol can't be empty")
|
||||
return nil, currency.ErrSymbolStringEmpty
|
||||
}
|
||||
params := make(map[string]interface{})
|
||||
params["symbol"] = symbol
|
||||
if uniqueID == "" {
|
||||
return nil, errors.New("uniqueID can't be empty")
|
||||
return nil, errors.New("uniqueID cannot be empty")
|
||||
}
|
||||
params["bizNo"] = uniqueID
|
||||
if margin <= 0 {
|
||||
return nil, errors.New("margin can't be zero or negative")
|
||||
return nil, errors.New("margin cannot be zero or negative")
|
||||
}
|
||||
params["margin"] = strconv.FormatFloat(margin, 'f', -1, 64)
|
||||
var resp *FuturesPosition
|
||||
return resp, ku.SendAuthHTTPRequest(ctx, exchange.RestFutures, defaultFuturesEPL, http.MethodPost, kucoinFuturesAddMargin, params, &resp)
|
||||
return resp, ku.SendAuthHTTPRequest(ctx, exchange.RestFutures, futuresAddMarginManuallyEPL, http.MethodPost, "/v1/position/margin/deposit-margin", params, &resp)
|
||||
}
|
||||
|
||||
// GetFuturesRiskLimitLevel gets information about risk limit level of a specific contract
|
||||
func (ku *Kucoin) GetFuturesRiskLimitLevel(ctx context.Context, symbol string) ([]FuturesRiskLimitLevel, error) {
|
||||
if symbol == "" {
|
||||
return nil, currency.ErrSymbolStringEmpty
|
||||
}
|
||||
var resp []FuturesRiskLimitLevel
|
||||
return resp, ku.SendAuthHTTPRequest(ctx, exchange.RestFutures, defaultFuturesEPL, http.MethodGet, kucoinFuturesRiskLimitLevel+symbol, nil, &resp)
|
||||
return resp, ku.SendAuthHTTPRequest(ctx, exchange.RestFutures, futuresRiskLimitLevelEPL, http.MethodGet, "/v1/contracts/risk-limit/"+symbol, nil, &resp)
|
||||
}
|
||||
|
||||
// FuturesUpdateRiskLmitLevel is used to adjustment the risk limit level
|
||||
func (ku *Kucoin) FuturesUpdateRiskLmitLevel(ctx context.Context, symbol string, level int64) (bool, error) {
|
||||
params := make(map[string]interface{})
|
||||
if symbol == "" {
|
||||
return false, errors.New("symbol can't be empty")
|
||||
return false, currency.ErrSymbolStringEmpty
|
||||
}
|
||||
params := make(map[string]interface{})
|
||||
params["symbol"] = symbol
|
||||
params["level"] = strconv.FormatInt(level, 10)
|
||||
var resp bool
|
||||
return resp, ku.SendAuthHTTPRequest(ctx, exchange.RestFutures, defaultFuturesEPL, http.MethodPost, kucoinFuturesUpdateRiskLmitLevel, params, &resp)
|
||||
return resp, ku.SendAuthHTTPRequest(ctx, exchange.RestFutures, futuresUpdateRiskLimitLevelEPL, http.MethodPost, "/v1/position/risk-limit-level/change", params, &resp)
|
||||
}
|
||||
|
||||
// GetFuturesFundingHistory gets information about funding history
|
||||
func (ku *Kucoin) GetFuturesFundingHistory(ctx context.Context, symbol string, offset, maxCount int64, reverse, forward bool, startAt, endAt time.Time) (*FuturesFundingHistoryResponse, error) {
|
||||
if symbol == "" {
|
||||
return nil, errors.New("symbol can't be empty")
|
||||
return nil, currency.ErrSymbolStringEmpty
|
||||
}
|
||||
params := url.Values{}
|
||||
params.Set("symbol", symbol)
|
||||
@@ -650,24 +716,24 @@ func (ku *Kucoin) GetFuturesFundingHistory(ctx context.Context, symbol string, o
|
||||
params.Set("maxCount", strconv.FormatInt(maxCount, 10))
|
||||
}
|
||||
var resp *FuturesFundingHistoryResponse
|
||||
return resp, ku.SendAuthHTTPRequest(ctx, exchange.RestFutures, futuresRetrieveFundingHistoryEPL, http.MethodGet, common.EncodeURLValues(kucoinFuturesFundingHistory, params), nil, &resp)
|
||||
return resp, ku.SendAuthHTTPRequest(ctx, exchange.RestFutures, futuresFundingHistoryEPL, http.MethodGet, common.EncodeURLValues("/v1/funding-history", params), nil, &resp)
|
||||
}
|
||||
|
||||
// GetFuturesAccountOverview gets future account overview
|
||||
func (ku *Kucoin) GetFuturesAccountOverview(ctx context.Context, currency string) (FuturesAccount, error) {
|
||||
func (ku *Kucoin) GetFuturesAccountOverview(ctx context.Context, ccy string) (*FuturesAccount, error) {
|
||||
params := url.Values{}
|
||||
if currency != "" {
|
||||
params.Set("currency", currency)
|
||||
if ccy != "" {
|
||||
params.Set("currency", ccy)
|
||||
}
|
||||
resp := FuturesAccount{}
|
||||
return resp, ku.SendAuthHTTPRequest(ctx, exchange.RestFutures, futuresRetrieveAccountOverviewEPL, http.MethodGet, common.EncodeURLValues(kucoinFuturesAccountOverview, params), nil, &resp)
|
||||
var resp *FuturesAccount
|
||||
return resp, ku.SendAuthHTTPRequest(ctx, exchange.RestFutures, futuresAccountOverviewEPL, http.MethodGet, common.EncodeURLValues("/v1/account-overview", params), nil, &resp)
|
||||
}
|
||||
|
||||
// GetFuturesTransactionHistory gets future transaction history
|
||||
func (ku *Kucoin) GetFuturesTransactionHistory(ctx context.Context, currency, txType string, offset, maxCount int64, forward bool, startAt, endAt time.Time) (*FuturesTransactionHistoryResponse, error) {
|
||||
func (ku *Kucoin) GetFuturesTransactionHistory(ctx context.Context, ccy currency.Code, txType string, offset, maxCount int64, forward bool, startAt, endAt time.Time) (*FuturesTransactionHistoryResponse, error) {
|
||||
params := url.Values{}
|
||||
if currency != "" {
|
||||
params.Set("currency", currency)
|
||||
if !ccy.IsEmpty() {
|
||||
params.Set("currency", ccy.String())
|
||||
}
|
||||
if txType != "" {
|
||||
params.Set("type", txType)
|
||||
@@ -686,147 +752,81 @@ func (ku *Kucoin) GetFuturesTransactionHistory(ctx context.Context, currency, tx
|
||||
params.Set("maxCount", strconv.FormatInt(maxCount, 10))
|
||||
}
|
||||
var resp *FuturesTransactionHistoryResponse
|
||||
return resp, ku.SendAuthHTTPRequest(ctx, exchange.RestFutures, futuresRetrieveTransactionHistoryEPL, http.MethodGet, common.EncodeURLValues(kucoinFuturesTransactionHistory, params), nil, &resp)
|
||||
return resp, ku.SendAuthHTTPRequest(ctx, exchange.RestFutures, futuresRetrieveTransactionHistoryEPL, http.MethodGet, common.EncodeURLValues("/v1/transaction-history", params), nil, &resp)
|
||||
}
|
||||
|
||||
// CreateFuturesSubAccountAPIKey is used to create Futures APIs for sub-accounts
|
||||
func (ku *Kucoin) CreateFuturesSubAccountAPIKey(ctx context.Context, ipWhitelist, passphrase, permission, remark, subName string) (*APIKeyDetail, error) {
|
||||
if remark == "" {
|
||||
return nil, errRemarkIsRequired
|
||||
}
|
||||
if subName == "" {
|
||||
return nil, errInvalidSubAccountName
|
||||
}
|
||||
if passphrase == "" {
|
||||
return nil, errInvalidPassPhraseInstance
|
||||
}
|
||||
params := make(map[string]interface{})
|
||||
params["passphrase"] = passphrase
|
||||
params["remark"] = remark
|
||||
params["subName"] = subName
|
||||
if ipWhitelist != "" {
|
||||
params["ipWhitelist"] = ipWhitelist
|
||||
}
|
||||
if passphrase == "" {
|
||||
return nil, errors.New("passphrase can't be empty")
|
||||
}
|
||||
params["passphrase"] = passphrase
|
||||
if permission != "" {
|
||||
params["permission"] = permission
|
||||
}
|
||||
if remark == "" {
|
||||
return nil, errors.New("remark can't be empty")
|
||||
}
|
||||
params["remark"] = remark
|
||||
if subName == "" {
|
||||
return nil, errors.New("subName can't be empty")
|
||||
}
|
||||
params["subName"] = subName
|
||||
var resp *APIKeyDetail
|
||||
return resp, ku.SendAuthHTTPRequest(ctx, exchange.RestFutures, defaultFuturesEPL, http.MethodPost, kucoinFuturesSubAccountAPI, params, &resp)
|
||||
}
|
||||
|
||||
// GetFuturesDepositAddress gets deposit address for currency
|
||||
func (ku *Kucoin) GetFuturesDepositAddress(ctx context.Context, currency string) (*DepositAddress, error) {
|
||||
if currency == "" {
|
||||
return nil, errors.New("currency can't be empty")
|
||||
}
|
||||
params := url.Values{}
|
||||
params.Set("currency", currency)
|
||||
var resp *DepositAddress
|
||||
return resp, ku.SendAuthHTTPRequest(ctx, exchange.RestFutures, defaultFuturesEPL, http.MethodGet, common.EncodeURLValues(kucoinFuturesDepositAddress, params), nil, &resp)
|
||||
}
|
||||
|
||||
// GetFuturesDepositsList gets deposits list
|
||||
func (ku *Kucoin) GetFuturesDepositsList(ctx context.Context, currency, status string, startAt, endAt time.Time) (*FuturesDepositDetailsResponse, error) {
|
||||
params := url.Values{}
|
||||
if currency != "" {
|
||||
params.Set("currency", currency)
|
||||
}
|
||||
if status != "" {
|
||||
params.Set("status", status)
|
||||
}
|
||||
if !startAt.IsZero() {
|
||||
params.Set("startAt", strconv.FormatInt(startAt.UnixMilli(), 10))
|
||||
}
|
||||
if !endAt.IsZero() {
|
||||
params.Set("endAt", strconv.FormatInt(endAt.UnixMilli(), 10))
|
||||
}
|
||||
var resp *FuturesDepositDetailsResponse
|
||||
return resp, ku.SendAuthHTTPRequest(ctx, exchange.RestFutures, defaultFuturesEPL, http.MethodGet, common.EncodeURLValues(kucoinFuturesDepositsList, params), nil, &resp)
|
||||
}
|
||||
|
||||
// GetFuturesWithdrawalLimit gets withdrawal limits for currency
|
||||
func (ku *Kucoin) GetFuturesWithdrawalLimit(ctx context.Context, currency string) (*FuturesWithdrawalLimit, error) {
|
||||
if currency == "" {
|
||||
return nil, errors.New("currency can't be empty")
|
||||
}
|
||||
params := url.Values{}
|
||||
params.Set("currency", currency)
|
||||
var resp *FuturesWithdrawalLimit
|
||||
return resp, ku.SendAuthHTTPRequest(ctx, exchange.RestFutures, defaultFuturesEPL, http.MethodGet, common.EncodeURLValues(kucoinFuturesWithdrawalLimit, params), nil, &resp)
|
||||
}
|
||||
|
||||
// GetFuturesWithdrawalList gets withdrawal list
|
||||
func (ku *Kucoin) GetFuturesWithdrawalList(ctx context.Context, currency, status string, startAt, endAt time.Time) (*FuturesWithdrawalsListResponse, error) {
|
||||
params := url.Values{}
|
||||
if currency != "" {
|
||||
params.Set("currency", currency)
|
||||
}
|
||||
if status != "" {
|
||||
params.Set("status", status)
|
||||
}
|
||||
if !startAt.IsZero() {
|
||||
params.Set("startAt", strconv.FormatInt(startAt.UnixMilli(), 10))
|
||||
}
|
||||
if !endAt.IsZero() {
|
||||
params.Set("endAt", strconv.FormatInt(endAt.UnixMilli(), 10))
|
||||
}
|
||||
var resp *FuturesWithdrawalsListResponse
|
||||
return resp, ku.SendAuthHTTPRequest(ctx, exchange.RestFutures, defaultFuturesEPL, http.MethodGet, common.EncodeURLValues(kucoinFuturesWithdrawalList, params), nil, &resp)
|
||||
}
|
||||
|
||||
// CancelFuturesWithdrawal is used to cancel withdrawal request of only PROCESSING status
|
||||
func (ku *Kucoin) CancelFuturesWithdrawal(ctx context.Context, withdrawalID string) (bool, error) {
|
||||
var resp bool
|
||||
return resp, ku.SendAuthHTTPRequest(ctx, exchange.RestFutures, defaultFuturesEPL, http.MethodDelete, kucoinFuturesCancelWithdrawal+withdrawalID, nil, &resp)
|
||||
return resp, ku.SendAuthHTTPRequest(ctx, exchange.RestFutures, createSubAccountAPIKeyEPL, http.MethodPost, "/v1/sub/api-key", params, &resp)
|
||||
}
|
||||
|
||||
// TransferFuturesFundsToMainAccount helps in transferring funds from futures to main/trade account
|
||||
func (ku *Kucoin) TransferFuturesFundsToMainAccount(ctx context.Context, amount float64, currency, recAccountType string) (*TransferRes, error) {
|
||||
params := make(map[string]interface{})
|
||||
func (ku *Kucoin) TransferFuturesFundsToMainAccount(ctx context.Context, amount float64, ccy currency.Code, recAccountType string) (*TransferRes, error) {
|
||||
if amount <= 0 {
|
||||
return nil, errors.New("amount can't be zero or negative")
|
||||
return nil, order.ErrAmountBelowMin
|
||||
}
|
||||
params["amount"] = amount
|
||||
if currency == "" {
|
||||
return nil, errors.New("currency can't be empty")
|
||||
if ccy.IsEmpty() {
|
||||
return nil, currency.ErrCurrencyCodeEmpty
|
||||
}
|
||||
params["currency"] = currency
|
||||
if recAccountType == "" {
|
||||
return nil, errors.New("recAccountType can't be empty")
|
||||
return nil, fmt.Errorf("%w, invalid receive account type", errAccountTypeMissing)
|
||||
}
|
||||
params := make(map[string]interface{})
|
||||
params["amount"] = amount
|
||||
params["currency"] = ccy.String()
|
||||
params["recAccountType"] = recAccountType
|
||||
var resp *TransferRes
|
||||
return resp, ku.SendAuthHTTPRequest(ctx, exchange.RestFutures, defaultFuturesEPL, http.MethodPost, kucoinFuturesTransferFundtoMainAccount, params, &resp)
|
||||
return resp, ku.SendAuthHTTPRequest(ctx, exchange.RestFutures, transferOutToMainEPL, http.MethodPost, "/v3/transfer-out", params, &resp)
|
||||
}
|
||||
|
||||
// TransferFundsToFuturesAccount helps in transferring funds from payee account to futures account
|
||||
func (ku *Kucoin) TransferFundsToFuturesAccount(ctx context.Context, amount float64, currency, payAccountType string) error {
|
||||
params := make(map[string]interface{})
|
||||
func (ku *Kucoin) TransferFundsToFuturesAccount(ctx context.Context, amount float64, ccy currency.Code, payAccountType string) error {
|
||||
if amount <= 0 {
|
||||
return errors.New("amount can't be zero or negative")
|
||||
return order.ErrAmountBelowMin
|
||||
}
|
||||
params["amount"] = amount
|
||||
if currency == "" {
|
||||
return errors.New("currency can't be empty")
|
||||
if ccy.IsEmpty() {
|
||||
return currency.ErrCurrencyCodeEmpty
|
||||
}
|
||||
params["currency"] = currency
|
||||
if payAccountType == "" {
|
||||
return errors.New("payAccountType can't be empty")
|
||||
return fmt.Errorf("%w, payAccountType cannot be empty", errAccountTypeMissing)
|
||||
}
|
||||
params := make(map[string]interface{})
|
||||
params["amount"] = amount
|
||||
params["currency"] = ccy.String()
|
||||
params["payAccountType"] = payAccountType
|
||||
resp := struct {
|
||||
Error
|
||||
}{}
|
||||
return ku.SendAuthHTTPRequest(ctx, exchange.RestFutures, defaultFuturesEPL, http.MethodPost, kucoinFuturesTransferFundtoFuturesAccount, params, &resp)
|
||||
return ku.SendAuthHTTPRequest(ctx, exchange.RestFutures, transferFundToFuturesAccountEPL, http.MethodPost, "/v1/transfer-in", params, &resp)
|
||||
}
|
||||
|
||||
// GetFuturesTransferOutList gets list of transfer out
|
||||
func (ku *Kucoin) GetFuturesTransferOutList(ctx context.Context, currency, status string, startAt, endAt time.Time) (*TransferListsResponse, error) {
|
||||
if currency == "" {
|
||||
return nil, errors.New("currency can't be empty")
|
||||
func (ku *Kucoin) GetFuturesTransferOutList(ctx context.Context, ccy currency.Code, status string, startAt, endAt time.Time) (*TransferListsResponse, error) {
|
||||
if ccy.IsEmpty() {
|
||||
return nil, currency.ErrCurrencyCodeEmpty
|
||||
}
|
||||
params := url.Values{}
|
||||
params.Set("currency", currency)
|
||||
params.Set("currency", ccy.String())
|
||||
if status != "" {
|
||||
params.Set("status", status)
|
||||
}
|
||||
@@ -837,20 +837,7 @@ func (ku *Kucoin) GetFuturesTransferOutList(ctx context.Context, currency, statu
|
||||
params.Set("endAt", strconv.FormatInt(endAt.UnixMilli(), 10))
|
||||
}
|
||||
var resp *TransferListsResponse
|
||||
return resp, ku.SendAuthHTTPRequest(ctx, exchange.RestFutures, defaultFuturesEPL, http.MethodGet, common.EncodeURLValues(kucoinFuturesTransferOutList, params), nil, &resp)
|
||||
}
|
||||
|
||||
// CancelFuturesTransferOut is used to cancel transfer out request of only PROCESSING status
|
||||
func (ku *Kucoin) CancelFuturesTransferOut(ctx context.Context, applyID string) error {
|
||||
if applyID == "" {
|
||||
return errors.New("applyID can't be empty")
|
||||
}
|
||||
params := url.Values{}
|
||||
params.Set("applyId", applyID)
|
||||
resp := struct {
|
||||
Error
|
||||
}{}
|
||||
return ku.SendAuthHTTPRequest(ctx, exchange.RestFutures, defaultFuturesEPL, http.MethodDelete, common.EncodeURLValues(kucoinFuturesCancelTransferOut, params), nil, &resp)
|
||||
return resp, ku.SendAuthHTTPRequest(ctx, exchange.RestFutures, futuresTransferOutListEPL, http.MethodGet, common.EncodeURLValues("/v1/transfer-list", params), nil, &resp)
|
||||
}
|
||||
|
||||
func processFuturesOB(ob [][2]float64) []orderbook.Tranche {
|
||||
@@ -872,3 +859,63 @@ func constructFuturesOrderbook(o *futuresOrderbookResponse) *Orderbook {
|
||||
Time: o.Time.Time(),
|
||||
}
|
||||
}
|
||||
|
||||
// GetFuturesTradingPairsActualFees retrieves the actual fee rate of the trading pair. The fee rate of your sub-account is the same as that of the master account
|
||||
func (ku *Kucoin) GetFuturesTradingPairsActualFees(ctx context.Context, symbol string) (*TradingPairFee, error) {
|
||||
if symbol == "" {
|
||||
return nil, currency.ErrSymbolStringEmpty
|
||||
}
|
||||
params := url.Values{}
|
||||
params.Set("symbol", symbol)
|
||||
var resp *TradingPairFee
|
||||
return resp, ku.SendAuthHTTPRequest(ctx, exchange.RestFutures, futuresTradingPairFeeEPL, http.MethodGet, common.EncodeURLValues("/v1/trade-fees", params), nil, &resp)
|
||||
}
|
||||
|
||||
// GetPositionHistory query position history information records
|
||||
func (ku *Kucoin) GetPositionHistory(ctx context.Context, symbol string, from, to time.Time, limit, pageID int64) (*FuturesPositionHistory, error) {
|
||||
params := url.Values{}
|
||||
if !from.IsZero() && !to.IsZero() {
|
||||
err := common.StartEndTimeCheck(from, to)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
params.Set("from", strconv.FormatInt(from.UnixMilli(), 10))
|
||||
params.Set("to", strconv.FormatInt(to.UnixMilli(), 10))
|
||||
}
|
||||
if symbol != "" {
|
||||
params.Set("symbol", symbol)
|
||||
}
|
||||
if limit > 0 {
|
||||
params.Set("limit", strconv.FormatInt(limit, 10))
|
||||
}
|
||||
if pageID > 0 {
|
||||
params.Set("pageId", strconv.FormatInt(pageID, 10))
|
||||
}
|
||||
var resp *FuturesPositionHistory
|
||||
return resp, ku.SendAuthHTTPRequest(ctx, exchange.RestFutures, futuresPositionHistoryEPL, http.MethodGet, common.EncodeURLValues("/v1/history-positions", params), nil, &resp)
|
||||
}
|
||||
|
||||
// GetMaximumOpenPositionSize retrieves a maximum open position size
|
||||
func (ku *Kucoin) GetMaximumOpenPositionSize(ctx context.Context, symbol string, price float64, leverage int64) (*FuturesMaxOpenPositionSize, error) {
|
||||
if symbol == "" {
|
||||
return nil, currency.ErrSymbolStringEmpty
|
||||
}
|
||||
if price <= 0 {
|
||||
return nil, order.ErrPriceBelowMin
|
||||
}
|
||||
if leverage <= 0 {
|
||||
return nil, fmt.Errorf("%w, leverage is required", errInvalidLeverage)
|
||||
}
|
||||
params := url.Values{}
|
||||
params.Set("symbol", symbol)
|
||||
params.Set("price", strconv.FormatFloat(price, 'f', -1, 64))
|
||||
params.Set("leverage", strconv.FormatInt(leverage, 10))
|
||||
var resp *FuturesMaxOpenPositionSize
|
||||
return resp, ku.SendAuthHTTPRequest(ctx, exchange.RestFutures, futuresMaxOpenPositionsSizeEPL, http.MethodGet, common.EncodeURLValues("/v2/getMaxOpenSize", params), nil, &resp)
|
||||
}
|
||||
|
||||
// GetLatestTickersForAllContracts retrieves all futures instruments ticker information
|
||||
func (ku *Kucoin) GetLatestTickersForAllContracts(ctx context.Context) ([]WsFuturesTicker, error) {
|
||||
var resp []WsFuturesTicker
|
||||
return resp, ku.SendAuthHTTPRequest(ctx, exchange.RestFutures, futuresAllTickersInfoEPL, http.MethodGet, "/v1/allTickers", nil, &resp)
|
||||
}
|
||||
|
||||
@@ -141,6 +141,13 @@ type FuturesFundingRate struct {
|
||||
PredictedValue float64 `json:"predictedValue"`
|
||||
}
|
||||
|
||||
// FundingHistoryItem represents funding history item
|
||||
type FundingHistoryItem struct {
|
||||
Symbol string `json:"symbol"`
|
||||
FundingRate float64 `json:"fundingRate"`
|
||||
Timepoint convert.ExchangeTime `json:"timepoint"`
|
||||
}
|
||||
|
||||
// FuturesKline stores kline data
|
||||
type FuturesKline struct {
|
||||
StartTime time.Time
|
||||
@@ -151,7 +158,7 @@ type FuturesKline struct {
|
||||
Volume float64
|
||||
}
|
||||
|
||||
// FutureOrdersResponse represents a future order response list detail.
|
||||
// FutureOrdersResponse represents a future order response list detail
|
||||
type FutureOrdersResponse struct {
|
||||
CurrentPage int64 `json:"currentPage"`
|
||||
PageSize int64 `json:"pageSize"`
|
||||
@@ -200,7 +207,7 @@ type FuturesOrder struct {
|
||||
ReduceOnly bool `json:"reduceOnly"`
|
||||
}
|
||||
|
||||
// FutureFillsResponse represents a future fills list response detail.
|
||||
// FutureFillsResponse represents a future fills list response detail
|
||||
type FutureFillsResponse struct {
|
||||
CurrentPage int64 `json:"currentPage"`
|
||||
PageSize int64 `json:"pageSize"`
|
||||
@@ -209,7 +216,7 @@ type FutureFillsResponse struct {
|
||||
Items []FuturesFill `json:"items"`
|
||||
}
|
||||
|
||||
// FuturesFill represents list of recent fills for futures orders.
|
||||
// FuturesFill represents list of recent fills for futures orders
|
||||
type FuturesFill struct {
|
||||
Symbol string `json:"symbol"`
|
||||
TradeID string `json:"tradeId"`
|
||||
@@ -232,7 +239,7 @@ type FuturesFill struct {
|
||||
TradeTime convert.ExchangeTime `json:"tradeTime"`
|
||||
}
|
||||
|
||||
// FuturesOpenOrderStats represents futures open order summary stats information.
|
||||
// FuturesOpenOrderStats represents futures open order summary stats information
|
||||
type FuturesOpenOrderStats struct {
|
||||
OpenOrderBuySize int64 `json:"openOrderBuySize"`
|
||||
OpenOrderSellSize int64 `json:"openOrderSellSize"`
|
||||
@@ -241,7 +248,7 @@ type FuturesOpenOrderStats struct {
|
||||
SettleCurrency string `json:"settleCurrency"`
|
||||
}
|
||||
|
||||
// FuturesPosition represents futures position detailed information.
|
||||
// FuturesPosition represents futures position detailed information
|
||||
type FuturesPosition struct {
|
||||
ID string `json:"id"`
|
||||
Symbol string `json:"symbol"`
|
||||
@@ -283,7 +290,19 @@ type FuturesPosition struct {
|
||||
RiskLimitLevel int64 `json:"riskLimitLevel"`
|
||||
}
|
||||
|
||||
// FuturesRiskLimitLevel represents futures risk limit level information.
|
||||
// WithdrawMarginResponse represents a response data after withdrawing a margin
|
||||
type WithdrawMarginResponse struct {
|
||||
Symbol string `json:"symbol"`
|
||||
WithdrawAmount float64 `json:"withdrawAmount"`
|
||||
}
|
||||
|
||||
// MarginRemovingResponse represents a response data for margin response
|
||||
type MarginRemovingResponse struct {
|
||||
Symbol string `json:"symbol"`
|
||||
WithdrawAmount float64 `json:"withdrawAmount"`
|
||||
}
|
||||
|
||||
// FuturesRiskLimitLevel represents futures risk limit level information
|
||||
type FuturesRiskLimitLevel struct {
|
||||
Symbol string `json:"symbol"`
|
||||
Level int64 `json:"level"`
|
||||
@@ -294,7 +313,7 @@ type FuturesRiskLimitLevel struct {
|
||||
MaintainMargin float64 `json:"maintainMargin"`
|
||||
}
|
||||
|
||||
// FuturesFundingHistory represents futures funding information.
|
||||
// FuturesFundingHistory represents futures funding information
|
||||
type FuturesFundingHistory struct {
|
||||
ID string `json:"id"`
|
||||
Symbol string `json:"symbol"`
|
||||
@@ -307,7 +326,7 @@ type FuturesFundingHistory struct {
|
||||
SettleCurrency string `json:"settleCurrency"`
|
||||
}
|
||||
|
||||
// FuturesAccount holds futures account detail information.
|
||||
// FuturesAccount holds futures account detail information
|
||||
type FuturesAccount struct {
|
||||
AccountEquity float64 `json:"accountEquity"` // marginBalance + Unrealised PNL
|
||||
UnrealisedPNL float64 `json:"unrealisedPNL"` // unrealised profit and loss
|
||||
@@ -344,7 +363,7 @@ type APIKeyDetail struct {
|
||||
CreateAt convert.ExchangeTime `json:"createdAt"`
|
||||
}
|
||||
|
||||
// FuturesDepositDetailsResponse represents a futures deposits list detail response.
|
||||
// FuturesDepositDetailsResponse represents a futures deposits list detail response
|
||||
type FuturesDepositDetailsResponse struct {
|
||||
CurrentPage int64 `json:"currentPage"`
|
||||
PageSize int64 `json:"pageSize"`
|
||||
@@ -353,7 +372,7 @@ type FuturesDepositDetailsResponse struct {
|
||||
Items []FuturesDepositDetail `json:"items"`
|
||||
}
|
||||
|
||||
// FuturesDepositDetail represents futures deposit detail information.
|
||||
// FuturesDepositDetail represents futures deposit detail information
|
||||
type FuturesDepositDetail struct {
|
||||
Currency string `json:"currency"`
|
||||
Status string `json:"status"`
|
||||
@@ -365,7 +384,7 @@ type FuturesDepositDetail struct {
|
||||
CreatedAt convert.ExchangeTime `json:"createdAt"`
|
||||
}
|
||||
|
||||
// FuturesWithdrawalLimit represents withdrawal limit information.
|
||||
// FuturesWithdrawalLimit represents withdrawal limit information
|
||||
type FuturesWithdrawalLimit struct {
|
||||
Currency string `json:"currency"`
|
||||
ChainID string `json:"chainId"`
|
||||
@@ -380,7 +399,7 @@ type FuturesWithdrawalLimit struct {
|
||||
Precision float64 `json:"precision"`
|
||||
}
|
||||
|
||||
// FuturesWithdrawalsListResponse represents a list of futures Withdrawal history instance.
|
||||
// FuturesWithdrawalsListResponse represents a list of futures Withdrawal history instance
|
||||
type FuturesWithdrawalsListResponse struct {
|
||||
CurrentPage int64 `json:"currentPage"`
|
||||
PageSize int64 `json:"pageSize"`
|
||||
@@ -389,7 +408,7 @@ type FuturesWithdrawalsListResponse struct {
|
||||
Items []FuturesWithdrawalHistory `json:"items"`
|
||||
}
|
||||
|
||||
// FuturesWithdrawalHistory represents a list of Futures withdrawal history.
|
||||
// FuturesWithdrawalHistory represents a list of Futures withdrawal history
|
||||
type FuturesWithdrawalHistory struct {
|
||||
WithdrawalID string `json:"withdrawalId"`
|
||||
Currency string `json:"currency"`
|
||||
@@ -405,7 +424,7 @@ type FuturesWithdrawalHistory struct {
|
||||
Reason string `json:"reason"`
|
||||
}
|
||||
|
||||
// TransferBase represents transfer base information.
|
||||
// TransferBase represents transfer base information
|
||||
type TransferBase struct {
|
||||
ApplyID string `json:"applyId"`
|
||||
Currency string `json:"currency"`
|
||||
@@ -431,7 +450,7 @@ type TransferRes struct {
|
||||
UpdatedAt convert.ExchangeTime `json:"updatedAt"`
|
||||
}
|
||||
|
||||
// TransferListsResponse represents a transfer lists detail.
|
||||
// TransferListsResponse represents a transfer lists detail
|
||||
type TransferListsResponse struct {
|
||||
CurrentPage int64 `json:"currentPage"`
|
||||
PageSize int64 `json:"pageSize"`
|
||||
@@ -440,13 +459,13 @@ type TransferListsResponse struct {
|
||||
Items []Transfer `json:"items"`
|
||||
}
|
||||
|
||||
// Transfer represents a transfer detail.
|
||||
// Transfer represents a transfer detail
|
||||
type Transfer struct {
|
||||
TransferBase
|
||||
Offset int64 `json:"offset"`
|
||||
}
|
||||
|
||||
// FuturesServiceStatus represents service status.
|
||||
// FuturesServiceStatus represents service status
|
||||
type FuturesServiceStatus struct {
|
||||
Status string `json:"status"`
|
||||
Message string `json:"msg"`
|
||||
|
||||
@@ -7,113 +7,417 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
threeSecondsInterval = time.Second * 3
|
||||
oneMinuteInterval = time.Minute
|
||||
)
|
||||
|
||||
// rate of request per interval
|
||||
const (
|
||||
retrieveAccountLedgerRate = 18
|
||||
masterSubUserTransferRate = 3
|
||||
retrieveDepositListRate = 6
|
||||
retrieveV1HistoricalDepositListRate = 6
|
||||
retrieveWithdrawalListRate = 6
|
||||
retrieveV1HistoricalWithdrawalListRate = 6
|
||||
placeOrderRate = 45
|
||||
placeMarginOrdersRate = 45
|
||||
placeBulkOrdersRate = 3
|
||||
cancelOrderRate = 60
|
||||
cancelAllOrdersRate = 3
|
||||
listOrdersRate = 30
|
||||
listFillsRate = 9
|
||||
retrieveFullOrderbookRate = 30
|
||||
retrieveMarginAccountRate = 1
|
||||
|
||||
futuresRetrieveAccountOverviewRate = 30
|
||||
futuresRetrieveTransactionHistoryRate = 9
|
||||
futuresPlaceOrderRate = 30
|
||||
futuresCancelAnOrderRate = 40
|
||||
futuresLimitOrderMassCancelationRate = 9
|
||||
futuresRetrieveOrderListRate = 30
|
||||
futuresRetrieveFillsRate = 9
|
||||
futuresRecentFillsRate = 9
|
||||
futuresRetrievePositionListRate = 9
|
||||
futuresRetrieveFundingHistoryRate = 9
|
||||
futuresRetrieveFullOrderbookLevel2Rate = 30
|
||||
|
||||
defaultSpotRate = 1200
|
||||
defaultFuturesRate = 1200
|
||||
thirtySecondsInterval = time.Second * 30
|
||||
)
|
||||
|
||||
const (
|
||||
// for spot endpoints
|
||||
retrieveAccountLedgerEPL request.EndpointLimit = iota
|
||||
masterSubUserTransferEPL
|
||||
retrieveDepositListEPL
|
||||
retrieveV1HistoricalDepositListEPL
|
||||
retrieveWithdrawalListEPL
|
||||
accountSummaryInfoEPL request.EndpointLimit = iota
|
||||
allAccountEPL
|
||||
accountDetailEPL
|
||||
accountLedgersEPL
|
||||
hfAccountLedgersEPL
|
||||
hfAccountLedgersMarginEPL
|
||||
futuresAccountLedgersEPL
|
||||
subAccountInfoV1EPL
|
||||
allSubAccountsInfoV2EPL
|
||||
createSubUserEPL
|
||||
subAccountsEPL
|
||||
subAccountBalancesEPL
|
||||
allSubAccountBalancesV2EPL
|
||||
subAccountSpotAPIListEPL
|
||||
createSpotAPIForSubAccountEPL
|
||||
modifySubAccountSpotAPIEPL
|
||||
deleteSubAccountSpotAPIEPL
|
||||
marginAccountDetailEPL
|
||||
crossMarginAccountsDetailEPL
|
||||
isolatedMarginAccountDetailEPL
|
||||
futuresAccountsDetailEPL
|
||||
tradingPairActualFeeEPL
|
||||
allFuturesSubAccountBalancesEPL
|
||||
futuresTradingPairFeeEPL
|
||||
futuresPositionHistoryEPL
|
||||
futuresMaxOpenPositionsSizeEPL
|
||||
futuresAllTickersInfoEPL
|
||||
createDepositAddressEPL
|
||||
depositAddressesV2EPL
|
||||
depositAddressesV1EPL
|
||||
depositListEPL
|
||||
historicDepositListEPL
|
||||
withdrawalListEPL
|
||||
retrieveV1HistoricalWithdrawalListEPL
|
||||
withdrawalQuotaEPL
|
||||
applyWithdrawalEPL
|
||||
cancelWithdrawalsEPL
|
||||
getTransferablesEPL
|
||||
flexiTransferEPL
|
||||
masterSubUserTransferEPL
|
||||
innerTransferEPL
|
||||
toMainOrTradeAccountEPL
|
||||
toFuturesAccountEPL
|
||||
futuresTransferOutRequestRecordsEPL
|
||||
basicFeesEPL
|
||||
tradeFeesEPL
|
||||
spotCurrenciesV3EPL
|
||||
spotCurrencyDetailEPL
|
||||
symbolsEPL
|
||||
tickersEPL
|
||||
allTickersEPL
|
||||
statistics24HrEPL
|
||||
marketListEPL
|
||||
partOrderbook20EPL
|
||||
partOrderbook100EPL
|
||||
fullOrderbookEPL
|
||||
tradeHistoryEPL
|
||||
klinesEPL
|
||||
fiatPriceEPL
|
||||
currentServerTimeEPL
|
||||
serviceStatusEPL
|
||||
hfPlaceOrderEPL
|
||||
hfSyncPlaceOrderEPL
|
||||
hfMultipleOrdersEPL
|
||||
hfSyncPlaceMultipleHFOrdersEPL
|
||||
hfModifyOrderEPL
|
||||
cancelHFOrderEPL
|
||||
hfSyncCancelOrderEPL
|
||||
hfCancelOrderByClientOrderIDEPL
|
||||
cancelSpecifiedNumberHFOrdersByOrderIDEPL
|
||||
hfCancelAllOrdersBySymbolEPL
|
||||
hfCancelAllOrdersEPL
|
||||
hfGetAllActiveOrdersEPL
|
||||
hfSymbolsWithActiveOrdersEPL
|
||||
hfCompletedOrderListEPL
|
||||
hfOrderDetailByOrderIDEPL
|
||||
autoCancelHFOrderSettingEPL
|
||||
autoCancelHFOrderSettingQueryEPL
|
||||
hfFilledListEPL
|
||||
placeOrderEPL
|
||||
placeMarginOrdersEPL
|
||||
placeBulkOrdersEPL
|
||||
cancelOrderEPL
|
||||
cancelOrderByClientOrderIDEPL
|
||||
cancelAllOrdersEPL
|
||||
listOrdersEPL
|
||||
recentOrdersEPL
|
||||
orderDetailByIDEPL
|
||||
getOrderByClientSuppliedOrderIDEPL
|
||||
listFillsEPL
|
||||
retrieveFullOrderbookEPL
|
||||
retrieveMarginAccountEPL
|
||||
defaultSpotEPL
|
||||
|
||||
// for futures endpoints
|
||||
futuresRetrieveAccountOverviewEPL
|
||||
futuresRetrieveTransactionHistoryEPL
|
||||
futuresPlaceOrderEPL
|
||||
getRecentFillsEPL
|
||||
placeStopOrderEPL
|
||||
cancelStopOrderEPL
|
||||
cancelStopOrderByClientIDEPL
|
||||
cancelStopOrdersEPL
|
||||
listStopOrdersEPL
|
||||
getStopOrderDetailEPL
|
||||
getStopOrderByClientIDEPL
|
||||
placeOCOOrderEPL
|
||||
cancelOCOOrderByIDEPL
|
||||
cancelMultipleOCOOrdersEPL
|
||||
getOCOOrderByIDEPL
|
||||
getOCOOrderDetailsByOrderIDEPL
|
||||
getOCOOrdersEPL
|
||||
placeMarginOrderEPL
|
||||
cancelMarginHFOrderByIDEPL
|
||||
getMarginHFOrderDetailByID
|
||||
cancelAllMarginHFOrdersBySymbolEPL
|
||||
getActiveMarginHFOrdersEPL
|
||||
getFilledHFMarginOrdersEPL
|
||||
getMarginHFOrderDetailByOrderIDEPL
|
||||
getMarginHFTradeFillsEPL
|
||||
placeMarginOrdersEPL
|
||||
leveragedTokenInfoEPL
|
||||
getMarkPriceEPL
|
||||
getAllMarginMarkPriceEPL
|
||||
getMarginConfigurationEPL
|
||||
crossIsolatedMarginRiskLimitCurrencyConfigEPL
|
||||
isolatedMarginPairConfigEPL
|
||||
isolatedMarginAccountInfoEPL
|
||||
singleIsolatedMarginAccountInfoEPL
|
||||
postMarginBorrowOrderEPL
|
||||
postMarginRepaymentEPL
|
||||
getCrossIsolatedMarginInterestRecordsEPL
|
||||
marginBorrowingHistoryEPL
|
||||
marginRepaymentHistoryEPL
|
||||
lendingCurrencyInfoEPL
|
||||
interestRateEPL
|
||||
marginLendingSubscriptionEPL
|
||||
redemptionEPL
|
||||
modifySubscriptionEPL
|
||||
getRedemptionOrdersEPL
|
||||
getSubscriptionOrdersEPL
|
||||
futuresOpenContractsEPL
|
||||
futuresContractEPL
|
||||
futuresTickerEPL
|
||||
futuresOrderbookEPL
|
||||
futuresPartOrderbookDepth20EPL
|
||||
futuresPartOrderbookDepth100EPL
|
||||
futuresTransactionHistoryEPL
|
||||
futuresKlineEPL
|
||||
futuresInterestRateEPL
|
||||
futuresIndexListEPL
|
||||
futuresCurrentMarkPriceEPL
|
||||
futuresPremiumIndexEPL
|
||||
futuresTransactionVolumeEPL
|
||||
futuresServerTimeEPL
|
||||
futuresServiceStatusEPL
|
||||
multipleFuturesOrdersEPL
|
||||
futuresCancelAnOrderEPL
|
||||
futuresPlaceOrderEPL
|
||||
futuresLimitOrderMassCancelationEPL
|
||||
cancelUntriggeredFuturesStopOrdersEPL
|
||||
futuresCancelMultipleLimitOrdersEPL
|
||||
futuresRetrieveOrderListEPL
|
||||
futuresRecentCompletedOrdersEPL
|
||||
futuresOrdersByIDEPL
|
||||
futuresRetrieveFillsEPL
|
||||
futuresRecentFillsEPL
|
||||
futuresRetrievePositionListEPL
|
||||
futuresRetrieveFundingHistoryEPL
|
||||
futuresRetrieveFullOrderbookLevel2EPL
|
||||
defaultFuturesEPL
|
||||
futuresOpenOrderStatsEPL
|
||||
futuresPositionEPL
|
||||
futuresPositionListEPL
|
||||
setAutoDepositMarginEPL
|
||||
maxWithdrawMarginEPL
|
||||
removeMarginManuallyEPL
|
||||
futuresAddMarginManuallyEPL
|
||||
futuresRiskLimitLevelEPL
|
||||
futuresUpdateRiskLimitLevelEPL
|
||||
futuresCurrentFundingRateEPL
|
||||
futuresPublicFundingRateEPL
|
||||
futuresFundingHistoryEPL
|
||||
spotAuthenticationEPL
|
||||
futuresAuthenticationEPL
|
||||
futuresOrderDetailsByClientOrderIDEPL
|
||||
modifySubAccountAPIEPL
|
||||
allSubAccountsBalanceEPL
|
||||
allUserSubAccountsV2EPL
|
||||
futuresRetrieveTransactionHistoryEPL
|
||||
futuresAccountOverviewEPL
|
||||
createSubAccountAPIKeyEPL
|
||||
transferOutToMainEPL
|
||||
transferFundToFuturesAccountEPL
|
||||
futuresTransferOutListEPL
|
||||
|
||||
subscribeToEarnEPL
|
||||
earnRedemptionEPL
|
||||
earnRedemptionPreviewEPL
|
||||
|
||||
kucoinEarnSavingsProductsEPL
|
||||
kucoinEarnFixedIncomeCurrentHoldingEPL
|
||||
earnLimitedTimePromotionProductEPL
|
||||
earnKCSStakingProductEPL
|
||||
earnStakingProductEPL
|
||||
|
||||
vipLendingEPL
|
||||
affilateUserRebateInfoEPL
|
||||
marginPairsConfigurationEPL
|
||||
modifyLeverageMultiplierEPL
|
||||
marginActiveHFOrdersEPL
|
||||
)
|
||||
|
||||
// GetRateLimit returns a RateLimit instance, which implements the request.Limiter interface.
|
||||
func GetRateLimit() request.RateLimitDefinitions {
|
||||
spotRate := request.NewRateLimit(thirtySecondsInterval, 4000)
|
||||
futuresRate := request.NewRateLimit(thirtySecondsInterval, 2000)
|
||||
managementRate := request.NewRateLimit(thirtySecondsInterval, 2000)
|
||||
publicRate := request.NewRateLimit(thirtySecondsInterval, 2000)
|
||||
|
||||
return request.RateLimitDefinitions{
|
||||
// spot specific rate limiters
|
||||
retrieveAccountLedgerEPL: request.NewRateLimitWithWeight(threeSecondsInterval, retrieveAccountLedgerRate, 1),
|
||||
masterSubUserTransferEPL: request.NewRateLimitWithWeight(threeSecondsInterval, masterSubUserTransferRate, 1),
|
||||
retrieveDepositListEPL: request.NewRateLimitWithWeight(threeSecondsInterval, retrieveDepositListRate, 1),
|
||||
retrieveV1HistoricalDepositListEPL: request.NewRateLimitWithWeight(threeSecondsInterval, retrieveV1HistoricalDepositListRate, 1),
|
||||
retrieveWithdrawalListEPL: request.NewRateLimitWithWeight(threeSecondsInterval, retrieveWithdrawalListRate, 1),
|
||||
retrieveV1HistoricalWithdrawalListEPL: request.NewRateLimitWithWeight(threeSecondsInterval, retrieveV1HistoricalWithdrawalListRate, 1),
|
||||
placeOrderEPL: request.NewRateLimitWithWeight(threeSecondsInterval, placeOrderRate, 1),
|
||||
placeMarginOrdersEPL: request.NewRateLimitWithWeight(threeSecondsInterval, placeMarginOrdersRate, 1),
|
||||
placeBulkOrdersEPL: request.NewRateLimitWithWeight(threeSecondsInterval, placeBulkOrdersRate, 1),
|
||||
cancelOrderEPL: request.NewRateLimitWithWeight(threeSecondsInterval, cancelOrderRate, 1),
|
||||
cancelAllOrdersEPL: request.NewRateLimitWithWeight(threeSecondsInterval, cancelAllOrdersRate, 1),
|
||||
listOrdersEPL: request.NewRateLimitWithWeight(threeSecondsInterval, listOrdersRate, 1),
|
||||
listFillsEPL: request.NewRateLimitWithWeight(threeSecondsInterval, listFillsRate, 1),
|
||||
retrieveFullOrderbookEPL: request.NewRateLimitWithWeight(threeSecondsInterval, retrieveFullOrderbookRate, 1),
|
||||
retrieveMarginAccountEPL: request.NewRateLimitWithWeight(threeSecondsInterval, retrieveMarginAccountRate, 1),
|
||||
accountSummaryInfoEPL: request.GetRateLimiterWithWeight(managementRate, 20),
|
||||
allAccountEPL: request.GetRateLimiterWithWeight(managementRate, 5),
|
||||
accountDetailEPL: request.GetRateLimiterWithWeight(managementRate, 5),
|
||||
accountLedgersEPL: request.GetRateLimiterWithWeight(managementRate, 2),
|
||||
hfAccountLedgersEPL: request.GetRateLimiterWithWeight(spotRate, 2),
|
||||
hfAccountLedgersMarginEPL: request.GetRateLimiterWithWeight(spotRate, 2),
|
||||
futuresAccountLedgersEPL: request.GetRateLimiterWithWeight(spotRate, 2),
|
||||
subAccountInfoV1EPL: request.GetRateLimiterWithWeight(managementRate, 20),
|
||||
allSubAccountsInfoV2EPL: request.GetRateLimiterWithWeight(managementRate, 20),
|
||||
createSubUserEPL: request.GetRateLimiterWithWeight(managementRate, 20),
|
||||
subAccountsEPL: request.GetRateLimiterWithWeight(managementRate, 15),
|
||||
subAccountBalancesEPL: request.GetRateLimiterWithWeight(managementRate, 20),
|
||||
allSubAccountBalancesV2EPL: request.GetRateLimiterWithWeight(managementRate, 20),
|
||||
subAccountSpotAPIListEPL: request.GetRateLimiterWithWeight(managementRate, 20),
|
||||
createSpotAPIForSubAccountEPL: request.GetRateLimiterWithWeight(managementRate, 20),
|
||||
modifySubAccountSpotAPIEPL: request.GetRateLimiterWithWeight(managementRate, 30),
|
||||
deleteSubAccountSpotAPIEPL: request.GetRateLimiterWithWeight(managementRate, 30),
|
||||
marginAccountDetailEPL: request.GetRateLimiterWithWeight(spotRate, 40),
|
||||
crossMarginAccountsDetailEPL: request.GetRateLimiterWithWeight(spotRate, 15),
|
||||
isolatedMarginAccountDetailEPL: request.GetRateLimiterWithWeight(spotRate, 15),
|
||||
futuresAccountsDetailEPL: request.GetRateLimiterWithWeight(futuresRate, 5),
|
||||
tradingPairActualFeeEPL: request.GetRateLimiterWithWeight(spotRate, 3),
|
||||
allFuturesSubAccountBalancesEPL: request.GetRateLimiterWithWeight(futuresRate, 6),
|
||||
futuresTradingPairFeeEPL: request.GetRateLimiterWithWeight(futuresRate, 3),
|
||||
futuresPositionHistoryEPL: request.GetRateLimiterWithWeight(futuresRate, 2),
|
||||
futuresMaxOpenPositionsSizeEPL: request.GetRateLimiterWithWeight(futuresRate, 2),
|
||||
futuresAllTickersInfoEPL: request.GetRateLimiterWithWeight(futuresRate, 5),
|
||||
createDepositAddressEPL: request.GetRateLimiterWithWeight(managementRate, 20),
|
||||
depositAddressesV2EPL: request.GetRateLimiterWithWeight(managementRate, 5),
|
||||
depositAddressesV1EPL: request.GetRateLimiterWithWeight(managementRate, 5),
|
||||
depositListEPL: request.GetRateLimiterWithWeight(managementRate, 5),
|
||||
historicDepositListEPL: request.GetRateLimiterWithWeight(managementRate, 5),
|
||||
withdrawalListEPL: request.GetRateLimiterWithWeight(managementRate, 20),
|
||||
retrieveV1HistoricalWithdrawalListEPL: request.GetRateLimiterWithWeight(managementRate, 20),
|
||||
withdrawalQuotaEPL: request.GetRateLimiterWithWeight(managementRate, 20),
|
||||
applyWithdrawalEPL: request.GetRateLimiterWithWeight(managementRate, 5),
|
||||
cancelWithdrawalsEPL: request.GetRateLimiterWithWeight(managementRate, 20),
|
||||
getTransferablesEPL: request.GetRateLimiterWithWeight(managementRate, 20),
|
||||
flexiTransferEPL: request.GetRateLimiterWithWeight(managementRate, 4),
|
||||
masterSubUserTransferEPL: request.GetRateLimiterWithWeight(managementRate, 30),
|
||||
innerTransferEPL: request.GetRateLimiterWithWeight(managementRate, 10),
|
||||
toMainOrTradeAccountEPL: request.GetRateLimiterWithWeight(managementRate, 20),
|
||||
toFuturesAccountEPL: request.GetRateLimiterWithWeight(managementRate, 20),
|
||||
futuresTransferOutRequestRecordsEPL: request.GetRateLimiterWithWeight(managementRate, 20),
|
||||
basicFeesEPL: request.GetRateLimiterWithWeight(spotRate, 3),
|
||||
tradeFeesEPL: request.GetRateLimiterWithWeight(spotRate, 3),
|
||||
spotCurrenciesV3EPL: request.GetRateLimiterWithWeight(publicRate, 3),
|
||||
spotCurrencyDetailEPL: request.GetRateLimiterWithWeight(publicRate, 3),
|
||||
symbolsEPL: request.GetRateLimiterWithWeight(publicRate, 4),
|
||||
tickersEPL: request.GetRateLimiterWithWeight(publicRate, 2),
|
||||
allTickersEPL: request.GetRateLimiterWithWeight(publicRate, 15),
|
||||
statistics24HrEPL: request.GetRateLimiterWithWeight(publicRate, 15),
|
||||
marketListEPL: request.GetRateLimiterWithWeight(publicRate, 3),
|
||||
partOrderbook20EPL: request.GetRateLimiterWithWeight(publicRate, 2),
|
||||
partOrderbook100EPL: request.GetRateLimiterWithWeight(publicRate, 4),
|
||||
fullOrderbookEPL: request.GetRateLimiterWithWeight(spotRate, 3),
|
||||
tradeHistoryEPL: request.GetRateLimiterWithWeight(publicRate, 3),
|
||||
klinesEPL: request.GetRateLimiterWithWeight(publicRate, 3),
|
||||
fiatPriceEPL: request.GetRateLimiterWithWeight(publicRate, 3),
|
||||
currentServerTimeEPL: request.GetRateLimiterWithWeight(publicRate, 3),
|
||||
serviceStatusEPL: request.GetRateLimiterWithWeight(publicRate, 3),
|
||||
hfPlaceOrderEPL: request.GetRateLimiterWithWeight(spotRate, 1),
|
||||
hfSyncPlaceOrderEPL: request.GetRateLimiterWithWeight(spotRate, 1),
|
||||
hfMultipleOrdersEPL: request.GetRateLimiterWithWeight(spotRate, 1),
|
||||
hfSyncPlaceMultipleHFOrdersEPL: request.GetRateLimiterWithWeight(spotRate, 1),
|
||||
hfModifyOrderEPL: request.GetRateLimiterWithWeight(spotRate, 3),
|
||||
cancelHFOrderEPL: request.GetRateLimiterWithWeight(spotRate, 1),
|
||||
hfSyncCancelOrderEPL: request.GetRateLimiterWithWeight(spotRate, 1),
|
||||
hfCancelOrderByClientOrderIDEPL: request.GetRateLimiterWithWeight(spotRate, 1),
|
||||
cancelSpecifiedNumberHFOrdersByOrderIDEPL: request.GetRateLimiterWithWeight(spotRate, 2),
|
||||
hfCancelAllOrdersBySymbolEPL: request.GetRateLimiterWithWeight(spotRate, 2),
|
||||
hfCancelAllOrdersEPL: request.GetRateLimiterWithWeight(spotRate, 30),
|
||||
hfGetAllActiveOrdersEPL: request.GetRateLimiterWithWeight(spotRate, 2),
|
||||
hfSymbolsWithActiveOrdersEPL: request.GetRateLimiterWithWeight(spotRate, 2),
|
||||
hfCompletedOrderListEPL: request.GetRateLimiterWithWeight(spotRate, 2),
|
||||
hfOrderDetailByOrderIDEPL: request.GetRateLimiterWithWeight(spotRate, 2),
|
||||
autoCancelHFOrderSettingEPL: request.GetRateLimiterWithWeight(spotRate, 2),
|
||||
autoCancelHFOrderSettingQueryEPL: request.GetRateLimiterWithWeight(spotRate, 2),
|
||||
hfFilledListEPL: request.GetRateLimiterWithWeight(spotRate, 2),
|
||||
placeOrderEPL: request.GetRateLimiterWithWeight(spotRate, 2),
|
||||
placeBulkOrdersEPL: request.GetRateLimiterWithWeight(spotRate, 3),
|
||||
cancelOrderEPL: request.GetRateLimiterWithWeight(spotRate, 3),
|
||||
cancelOrderByClientOrderIDEPL: request.GetRateLimiterWithWeight(spotRate, 5),
|
||||
cancelAllOrdersEPL: request.GetRateLimiterWithWeight(spotRate, 20),
|
||||
listOrdersEPL: request.GetRateLimiterWithWeight(spotRate, 2),
|
||||
recentOrdersEPL: request.GetRateLimiterWithWeight(spotRate, 3),
|
||||
orderDetailByIDEPL: request.GetRateLimiterWithWeight(spotRate, 2),
|
||||
getOrderByClientSuppliedOrderIDEPL: request.GetRateLimiterWithWeight(spotRate, 3),
|
||||
listFillsEPL: request.GetRateLimiterWithWeight(spotRate, 10),
|
||||
getRecentFillsEPL: request.GetRateLimiterWithWeight(spotRate, 20),
|
||||
placeStopOrderEPL: request.GetRateLimiterWithWeight(spotRate, 2),
|
||||
cancelStopOrderEPL: request.GetRateLimiterWithWeight(spotRate, 3),
|
||||
cancelStopOrderByClientIDEPL: request.GetRateLimiterWithWeight(spotRate, 5),
|
||||
cancelStopOrdersEPL: request.GetRateLimiterWithWeight(spotRate, 3),
|
||||
listStopOrdersEPL: request.GetRateLimiterWithWeight(spotRate, 8),
|
||||
getStopOrderDetailEPL: request.GetRateLimiterWithWeight(spotRate, 3),
|
||||
getStopOrderByClientIDEPL: request.GetRateLimiterWithWeight(spotRate, 3),
|
||||
placeOCOOrderEPL: request.GetRateLimiterWithWeight(spotRate, 2),
|
||||
cancelOCOOrderByIDEPL: request.GetRateLimiterWithWeight(spotRate, 3),
|
||||
cancelMultipleOCOOrdersEPL: request.GetRateLimiterWithWeight(spotRate, 3),
|
||||
getOCOOrderByIDEPL: request.GetRateLimiterWithWeight(spotRate, 2),
|
||||
getOCOOrderDetailsByOrderIDEPL: request.GetRateLimiterWithWeight(spotRate, 2),
|
||||
getOCOOrdersEPL: request.GetRateLimiterWithWeight(spotRate, 2),
|
||||
placeMarginOrderEPL: request.GetRateLimiterWithWeight(spotRate, 5),
|
||||
cancelMarginHFOrderByIDEPL: request.GetRateLimiterWithWeight(spotRate, 5),
|
||||
getMarginHFOrderDetailByID: request.GetRateLimiterWithWeight(spotRate, 5),
|
||||
cancelAllMarginHFOrdersBySymbolEPL: request.GetRateLimiterWithWeight(spotRate, 10),
|
||||
getActiveMarginHFOrdersEPL: request.GetRateLimiterWithWeight(spotRate, 4),
|
||||
getFilledHFMarginOrdersEPL: request.GetRateLimiterWithWeight(spotRate, 10),
|
||||
getMarginHFOrderDetailByOrderIDEPL: request.GetRateLimiterWithWeight(spotRate, 4),
|
||||
getMarginHFTradeFillsEPL: request.GetRateLimiterWithWeight(spotRate, 5),
|
||||
placeMarginOrdersEPL: request.GetRateLimiterWithWeight(spotRate, 5),
|
||||
leveragedTokenInfoEPL: request.GetRateLimiterWithWeight(spotRate, 25),
|
||||
getMarkPriceEPL: request.GetRateLimiterWithWeight(publicRate, 2),
|
||||
getAllMarginMarkPriceEPL: request.GetRateLimiterWithWeight(publicRate, 10),
|
||||
getMarginConfigurationEPL: request.GetRateLimiterWithWeight(spotRate, 25),
|
||||
crossIsolatedMarginRiskLimitCurrencyConfigEPL: request.GetRateLimiterWithWeight(spotRate, 20),
|
||||
isolatedMarginPairConfigEPL: request.GetRateLimiterWithWeight(spotRate, 20),
|
||||
isolatedMarginAccountInfoEPL: request.GetRateLimiterWithWeight(spotRate, 50),
|
||||
singleIsolatedMarginAccountInfoEPL: request.GetRateLimiterWithWeight(spotRate, 50),
|
||||
postMarginBorrowOrderEPL: request.GetRateLimiterWithWeight(spotRate, 15),
|
||||
postMarginRepaymentEPL: request.GetRateLimiterWithWeight(spotRate, 10),
|
||||
getCrossIsolatedMarginInterestRecordsEPL: request.GetRateLimiterWithWeight(spotRate, 20),
|
||||
marginBorrowingHistoryEPL: request.GetRateLimiterWithWeight(spotRate, 15),
|
||||
marginRepaymentHistoryEPL: request.GetRateLimiterWithWeight(spotRate, 15),
|
||||
lendingCurrencyInfoEPL: request.GetRateLimiterWithWeight(spotRate, 10),
|
||||
interestRateEPL: request.GetRateLimiterWithWeight(publicRate, 5),
|
||||
marginLendingSubscriptionEPL: request.GetRateLimiterWithWeight(spotRate, 15),
|
||||
redemptionEPL: request.GetRateLimiterWithWeight(spotRate, 15),
|
||||
modifySubscriptionEPL: request.GetRateLimiterWithWeight(spotRate, 10),
|
||||
getRedemptionOrdersEPL: request.GetRateLimiterWithWeight(spotRate, 10),
|
||||
getSubscriptionOrdersEPL: request.GetRateLimiterWithWeight(spotRate, 10),
|
||||
futuresOpenContractsEPL: request.GetRateLimiterWithWeight(publicRate, 3),
|
||||
futuresContractEPL: request.GetRateLimiterWithWeight(publicRate, 3),
|
||||
futuresTickerEPL: request.GetRateLimiterWithWeight(publicRate, 2),
|
||||
futuresOrderbookEPL: request.GetRateLimiterWithWeight(publicRate, 3),
|
||||
futuresPartOrderbookDepth20EPL: request.GetRateLimiterWithWeight(publicRate, 5),
|
||||
futuresPartOrderbookDepth100EPL: request.GetRateLimiterWithWeight(publicRate, 10),
|
||||
futuresTransactionHistoryEPL: request.GetRateLimiterWithWeight(publicRate, 5),
|
||||
futuresKlineEPL: request.GetRateLimiterWithWeight(publicRate, 3),
|
||||
futuresInterestRateEPL: request.GetRateLimiterWithWeight(publicRate, 5),
|
||||
futuresIndexListEPL: request.GetRateLimiterWithWeight(publicRate, 2),
|
||||
futuresCurrentMarkPriceEPL: request.GetRateLimiterWithWeight(publicRate, 3),
|
||||
futuresPremiumIndexEPL: request.GetRateLimiterWithWeight(publicRate, 3),
|
||||
futuresTransactionVolumeEPL: request.GetRateLimiterWithWeight(futuresRate, 3),
|
||||
futuresServerTimeEPL: request.GetRateLimiterWithWeight(publicRate, 2),
|
||||
futuresServiceStatusEPL: request.GetRateLimiterWithWeight(publicRate, 4),
|
||||
multipleFuturesOrdersEPL: request.GetRateLimiterWithWeight(futuresRate, 20),
|
||||
futuresCancelAnOrderEPL: request.GetRateLimiterWithWeight(futuresRate, 1),
|
||||
futuresPlaceOrderEPL: request.GetRateLimiterWithWeight(futuresRate, 2),
|
||||
futuresLimitOrderMassCancelationEPL: request.GetRateLimiterWithWeight(futuresRate, 30),
|
||||
cancelUntriggeredFuturesStopOrdersEPL: request.GetRateLimiterWithWeight(futuresRate, 15),
|
||||
futuresCancelMultipleLimitOrdersEPL: request.GetRateLimiterWithWeight(futuresRate, 30),
|
||||
futuresRetrieveOrderListEPL: request.GetRateLimiterWithWeight(futuresRate, 2),
|
||||
futuresRecentCompletedOrdersEPL: request.GetRateLimiterWithWeight(futuresRate, 5),
|
||||
futuresOrdersByIDEPL: request.GetRateLimiterWithWeight(futuresRate, 5),
|
||||
futuresRetrieveFillsEPL: request.GetRateLimiterWithWeight(futuresRate, 5),
|
||||
futuresRecentFillsEPL: request.GetRateLimiterWithWeight(futuresRate, 3),
|
||||
futuresOpenOrderStatsEPL: request.GetRateLimiterWithWeight(futuresRate, 10),
|
||||
futuresPositionEPL: request.GetRateLimiterWithWeight(futuresRate, 2),
|
||||
futuresPositionListEPL: request.GetRateLimiterWithWeight(futuresRate, 2),
|
||||
setAutoDepositMarginEPL: request.GetRateLimiterWithWeight(futuresRate, 4),
|
||||
maxWithdrawMarginEPL: request.GetRateLimiterWithWeight(futuresRate, 10),
|
||||
removeMarginManuallyEPL: request.GetRateLimiterWithWeight(futuresRate, 10),
|
||||
futuresAddMarginManuallyEPL: request.GetRateLimiterWithWeight(futuresRate, 4),
|
||||
futuresRiskLimitLevelEPL: request.GetRateLimiterWithWeight(futuresRate, 5),
|
||||
futuresUpdateRiskLimitLevelEPL: request.GetRateLimiterWithWeight(futuresRate, 4),
|
||||
futuresCurrentFundingRateEPL: request.GetRateLimiterWithWeight(publicRate, 2),
|
||||
futuresPublicFundingRateEPL: request.GetRateLimiterWithWeight(publicRate, 5),
|
||||
futuresFundingHistoryEPL: request.GetRateLimiterWithWeight(futuresRate, 5),
|
||||
spotAuthenticationEPL: request.GetRateLimiterWithWeight(spotRate, 10),
|
||||
futuresAuthenticationEPL: request.GetRateLimiterWithWeight(futuresRate, 10),
|
||||
futuresOrderDetailsByClientOrderIDEPL: request.GetRateLimiterWithWeight(futuresRate, 5),
|
||||
modifySubAccountAPIEPL: request.GetRateLimiterWithWeight(managementRate, 30),
|
||||
allSubAccountsBalanceEPL: request.GetRateLimiterWithWeight(managementRate, 20),
|
||||
allUserSubAccountsV2EPL: request.GetRateLimiterWithWeight(managementRate, 20),
|
||||
futuresRetrieveTransactionHistoryEPL: request.GetRateLimiterWithWeight(managementRate, 2),
|
||||
futuresAccountOverviewEPL: request.GetRateLimiterWithWeight(futuresRate, 5),
|
||||
createSubAccountAPIKeyEPL: request.GetRateLimiterWithWeight(managementRate, 20),
|
||||
transferOutToMainEPL: request.GetRateLimiterWithWeight(managementRate, 20),
|
||||
transferFundToFuturesAccountEPL: request.GetRateLimiterWithWeight(managementRate, 20),
|
||||
futuresTransferOutListEPL: request.GetRateLimiterWithWeight(managementRate, 20),
|
||||
|
||||
// default spot and futures rates
|
||||
defaultSpotEPL: request.NewRateLimitWithWeight(oneMinuteInterval, defaultSpotRate, 1),
|
||||
defaultFuturesEPL: request.NewRateLimitWithWeight(oneMinuteInterval, defaultFuturesRate, 1),
|
||||
subscribeToEarnEPL: request.GetRateLimiterWithWeight(spotRate, 5),
|
||||
earnRedemptionEPL: request.GetRateLimiterWithWeight(spotRate, 5),
|
||||
earnRedemptionPreviewEPL: request.GetRateLimiterWithWeight(spotRate, 5),
|
||||
|
||||
// futures specific rate limiters
|
||||
futuresRetrieveAccountOverviewEPL: request.NewRateLimitWithWeight(threeSecondsInterval, futuresRetrieveAccountOverviewRate, 1),
|
||||
futuresRetrieveTransactionHistoryEPL: request.NewRateLimitWithWeight(threeSecondsInterval, futuresRetrieveTransactionHistoryRate, 1),
|
||||
futuresPlaceOrderEPL: request.NewRateLimitWithWeight(threeSecondsInterval, futuresPlaceOrderRate, 1),
|
||||
futuresCancelAnOrderEPL: request.NewRateLimitWithWeight(threeSecondsInterval, futuresCancelAnOrderRate, 1),
|
||||
futuresLimitOrderMassCancelationEPL: request.NewRateLimitWithWeight(threeSecondsInterval, futuresLimitOrderMassCancelationRate, 1),
|
||||
futuresRetrieveOrderListEPL: request.NewRateLimitWithWeight(threeSecondsInterval, futuresRetrieveOrderListRate, 1),
|
||||
futuresRetrieveFillsEPL: request.NewRateLimitWithWeight(threeSecondsInterval, futuresRetrieveFillsRate, 1),
|
||||
futuresRecentFillsEPL: request.NewRateLimitWithWeight(threeSecondsInterval, futuresRecentFillsRate, 1),
|
||||
futuresRetrievePositionListEPL: request.NewRateLimitWithWeight(threeSecondsInterval, futuresRetrievePositionListRate, 1),
|
||||
futuresRetrieveFundingHistoryEPL: request.NewRateLimitWithWeight(threeSecondsInterval, futuresRetrieveFundingHistoryRate, 1),
|
||||
futuresRetrieveFullOrderbookLevel2EPL: request.NewRateLimitWithWeight(threeSecondsInterval, futuresRetrieveFullOrderbookLevel2Rate, 1),
|
||||
kucoinEarnSavingsProductsEPL: request.GetRateLimiterWithWeight(spotRate, 5),
|
||||
kucoinEarnFixedIncomeCurrentHoldingEPL: request.GetRateLimiterWithWeight(spotRate, 5),
|
||||
earnLimitedTimePromotionProductEPL: request.GetRateLimiterWithWeight(spotRate, 5),
|
||||
|
||||
earnKCSStakingProductEPL: request.GetRateLimiterWithWeight(spotRate, 5),
|
||||
earnStakingProductEPL: request.GetRateLimiterWithWeight(spotRate, 5),
|
||||
|
||||
vipLendingEPL: request.GetRateLimiterWithWeight(spotRate, 1),
|
||||
affilateUserRebateInfoEPL: request.GetRateLimiterWithWeight(spotRate, 30),
|
||||
marginPairsConfigurationEPL: request.GetRateLimiterWithWeight(spotRate, 5),
|
||||
modifyLeverageMultiplierEPL: request.GetRateLimiterWithWeight(spotRate, 5),
|
||||
marginActiveHFOrdersEPL: request.GetRateLimiterWithWeight(spotRate, 2),
|
||||
}
|
||||
}
|
||||
|
||||
201
exchanges/kucoin/kucoin_ratelimit_test.go
Normal file
201
exchanges/kucoin/kucoin_ratelimit_test.go
Normal file
@@ -0,0 +1,201 @@
|
||||
package kucoin
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/request"
|
||||
)
|
||||
|
||||
func TestRateLimit_LimitStatic(t *testing.T) {
|
||||
t.Parallel()
|
||||
testTable := map[string]request.EndpointLimit{
|
||||
"all Account": allAccountEPL,
|
||||
"account Detail": accountDetailEPL,
|
||||
"account Ledgers": accountLedgersEPL,
|
||||
"hf Account Ledgers": hfAccountLedgersEPL,
|
||||
"hf Account Ledgers Margin": hfAccountLedgersMarginEPL,
|
||||
"futures Account Ledgers": futuresAccountLedgersEPL,
|
||||
"sub Account Info V1": subAccountInfoV1EPL,
|
||||
"all Sub Accounts Info V2": allSubAccountsInfoV2EPL,
|
||||
"create SubUser": createSubUserEPL,
|
||||
"sub Accounts": subAccountsEPL,
|
||||
"sub Account Balances": subAccountBalancesEPL,
|
||||
"all SubAccount Balances V2": allSubAccountBalancesV2EPL,
|
||||
"sub Account Spot API List": subAccountSpotAPIListEPL,
|
||||
"create Spot API For Sub Account": createSpotAPIForSubAccountEPL,
|
||||
"modify Sub Account Spot API": modifySubAccountSpotAPIEPL,
|
||||
"delete Sub Account Spot API": deleteSubAccountSpotAPIEPL,
|
||||
"margin Account Detail": marginAccountDetailEPL,
|
||||
"cross Margin Accounts Detail": crossMarginAccountsDetailEPL,
|
||||
"isolated Margin Account Detail": isolatedMarginAccountDetailEPL,
|
||||
"futures Accounts Detail": futuresAccountsDetailEPL,
|
||||
"all Futures Sub Account Balances": allFuturesSubAccountBalancesEPL,
|
||||
"create Deposit Address": createDepositAddressEPL,
|
||||
"deposit Addresses V2": depositAddressesV2EPL,
|
||||
"deposit Addresses V1": depositAddressesV1EPL,
|
||||
"deposit List": depositListEPL,
|
||||
"historic Deposit List": historicDepositListEPL,
|
||||
"withdrawal List": withdrawalListEPL,
|
||||
"retrieve V1 Historical Withdrawal List": retrieveV1HistoricalWithdrawalListEPL,
|
||||
"withdrawal Quota": withdrawalQuotaEPL,
|
||||
"apply Withdrawal": applyWithdrawalEPL,
|
||||
"cancel Withdrawals": cancelWithdrawalsEPL,
|
||||
"get Transferables": getTransferablesEPL,
|
||||
"flexi Transfer": flexiTransferEPL,
|
||||
"master Sub User Transfer": masterSubUserTransferEPL,
|
||||
"inner Transfer": innerTransferEPL,
|
||||
"to Main Or TradeAccount": toMainOrTradeAccountEPL,
|
||||
"to Futures Account": toFuturesAccountEPL,
|
||||
"futures Transfer Out Request Records": futuresTransferOutRequestRecordsEPL,
|
||||
"basic Fees": basicFeesEPL,
|
||||
"trade Fees": tradeFeesEPL,
|
||||
"spot Currencies V3": spotCurrenciesV3EPL,
|
||||
"spot Currency Detail": spotCurrencyDetailEPL,
|
||||
"symbols": symbolsEPL,
|
||||
"tickers": tickersEPL,
|
||||
"all Tickers": allTickersEPL,
|
||||
"statistics 24Hr": statistics24HrEPL,
|
||||
"market List": marketListEPL,
|
||||
"part Orderbook 20": partOrderbook20EPL,
|
||||
"part Orderbook 100": partOrderbook100EPL,
|
||||
"full Orderbook": fullOrderbookEPL,
|
||||
"trade History": tradeHistoryEPL,
|
||||
"klines": klinesEPL,
|
||||
"fiat Price": fiatPriceEPL,
|
||||
"current Server Time": currentServerTimeEPL,
|
||||
"service Status": serviceStatusEPL,
|
||||
"hf Place Order": hfPlaceOrderEPL,
|
||||
"hf Sync Place Order": hfSyncPlaceOrderEPL,
|
||||
"hf Multiple Orders": hfMultipleOrdersEPL,
|
||||
"hf Sync Place Multiple HF Orders": hfSyncPlaceMultipleHFOrdersEPL,
|
||||
"hf Modify Order": hfModifyOrderEPL,
|
||||
"cancel HF Order": cancelHFOrderEPL,
|
||||
"hf Sync Cancel Order": hfSyncCancelOrderEPL,
|
||||
"hf Cancel Order By Client OrderID": hfCancelOrderByClientOrderIDEPL,
|
||||
"cancel Specified Number HF Orders By OrderID": cancelSpecifiedNumberHFOrdersByOrderIDEPL,
|
||||
"hf Cancel All Orders By Symbol": hfCancelAllOrdersBySymbolEPL,
|
||||
"hf Cancel All Orders": hfCancelAllOrdersEPL,
|
||||
"hf Get All Active Orders": hfGetAllActiveOrdersEPL,
|
||||
"hf Symbols With Active Orders": hfSymbolsWithActiveOrdersEPL,
|
||||
"hf Completed Order List": hfCompletedOrderListEPL,
|
||||
"hf Order Detail By OrderID": hfOrderDetailByOrderIDEPL,
|
||||
"auto Cancel HF Order Setting": autoCancelHFOrderSettingEPL,
|
||||
"auto Cancel HF Order Setting Query": autoCancelHFOrderSettingQueryEPL,
|
||||
"hf Filled List": hfFilledListEPL,
|
||||
"place Order": placeOrderEPL,
|
||||
"place Bulk Orders": placeBulkOrdersEPL,
|
||||
"cancel Order": cancelOrderEPL,
|
||||
"cancel Order By Client OrderID": cancelOrderByClientOrderIDEPL,
|
||||
"cancel All Orders": cancelAllOrdersEPL,
|
||||
"list Orders": listOrdersEPL,
|
||||
"recent Orders": recentOrdersEPL,
|
||||
"order Detail By ID": orderDetailByIDEPL,
|
||||
"get Order By Client Supplied OrderID": getOrderByClientSuppliedOrderIDEPL,
|
||||
"list Fills": listFillsEPL,
|
||||
"get Recent Fills": getRecentFillsEPL,
|
||||
"place Stop Order": placeStopOrderEPL,
|
||||
"cancel Stop Order": cancelStopOrderEPL,
|
||||
"cancel Stop Order By ClientID": cancelStopOrderByClientIDEPL,
|
||||
"cancel Stop Orders": cancelStopOrdersEPL,
|
||||
"list Stop Orders": listStopOrdersEPL,
|
||||
"get Stop Order Detail": getStopOrderDetailEPL,
|
||||
"get Stop Order By ClientID": getStopOrderByClientIDEPL,
|
||||
"place OCO Order": placeOCOOrderEPL,
|
||||
"cancel OCOOrder By ID": cancelOCOOrderByIDEPL,
|
||||
"cancel Multiple OCO Orders": cancelMultipleOCOOrdersEPL,
|
||||
"get OCO Order By ID": getOCOOrderByIDEPL,
|
||||
"get OCO Order Details By OrderID": getOCOOrderDetailsByOrderIDEPL,
|
||||
"get OCO Orders": getOCOOrdersEPL,
|
||||
"place Margin Order": placeMarginOrderEPL,
|
||||
"cancel Margin HF Order By ID": cancelMarginHFOrderByIDEPL,
|
||||
"get Margin HF Order Detail By ID": getMarginHFOrderDetailByID,
|
||||
"cancel All Margin HF Orders By Symbol": cancelAllMarginHFOrdersBySymbolEPL,
|
||||
"get Active Margin HF Orders": getActiveMarginHFOrdersEPL,
|
||||
"get Filled HF Margin Orders": getFilledHFMarginOrdersEPL,
|
||||
"get Margin HF Order Detail By Order ID": getMarginHFOrderDetailByOrderIDEPL,
|
||||
"get Margin HF Trade Fills": getMarginHFTradeFillsEPL,
|
||||
"place Margin Orders": placeMarginOrdersEPL,
|
||||
"leveraged Token Info": leveragedTokenInfoEPL,
|
||||
"get Mark Price": getMarkPriceEPL,
|
||||
"get Margin Configuration": getMarginConfigurationEPL,
|
||||
"cross Isolated Margin Risk Limit Currency Config": crossIsolatedMarginRiskLimitCurrencyConfigEPL,
|
||||
"isolated Margin Pair Config": isolatedMarginPairConfigEPL,
|
||||
"isolated Margin Account Info": isolatedMarginAccountInfoEPL,
|
||||
"single Isolated Margin Account Info": singleIsolatedMarginAccountInfoEPL,
|
||||
"post Margin Borrow Order": postMarginBorrowOrderEPL,
|
||||
"post Margin Repayment": postMarginRepaymentEPL,
|
||||
"margin Borrowing History": marginBorrowingHistoryEPL,
|
||||
"margin Repayment History": marginRepaymentHistoryEPL,
|
||||
"lending Currency Info": lendingCurrencyInfoEPL,
|
||||
"interest Rate": interestRateEPL,
|
||||
"margin Lending Subscription": marginLendingSubscriptionEPL,
|
||||
"redemption": redemptionEPL,
|
||||
"modify Subscription": modifySubscriptionEPL,
|
||||
"get Redemption Orders": getRedemptionOrdersEPL,
|
||||
"get Subscription Orders": getSubscriptionOrdersEPL,
|
||||
"futures Open Contracts": futuresOpenContractsEPL,
|
||||
"futures Contract": futuresContractEPL,
|
||||
"futures Ticker": futuresTickerEPL,
|
||||
"futures Orderbook": futuresOrderbookEPL,
|
||||
"futures Part Orderbook Depth20": futuresPartOrderbookDepth20EPL,
|
||||
"futures Part Orderbook Depth100": futuresPartOrderbookDepth100EPL,
|
||||
"futures Transaction History": futuresTransactionHistoryEPL,
|
||||
"futures Kline": futuresKlineEPL,
|
||||
"futures Interest Rate": futuresInterestRateEPL,
|
||||
"futures Index List": futuresIndexListEPL,
|
||||
"futures Current Mark Price": futuresCurrentMarkPriceEPL,
|
||||
"futures Premium Index": futuresPremiumIndexEPL,
|
||||
"futures Transaction Volume": futuresTransactionVolumeEPL,
|
||||
"futures Server Time": futuresServerTimeEPL,
|
||||
"futures Service Status": futuresServiceStatusEPL,
|
||||
"multiple Futures Orders": multipleFuturesOrdersEPL,
|
||||
"futures Cancel An Order": futuresCancelAnOrderEPL,
|
||||
"futures Place Order": futuresPlaceOrderEPL,
|
||||
"futures Limit Order Mass Cancellation": futuresLimitOrderMassCancelationEPL,
|
||||
"cancel Untriggered Futures Stop Orders": cancelUntriggeredFuturesStopOrdersEPL,
|
||||
"futures Cancel Multiple Limit Orders": futuresCancelMultipleLimitOrdersEPL,
|
||||
"futures Retrieve Order List": futuresRetrieveOrderListEPL,
|
||||
"futures Recent Completed Orders": futuresRecentCompletedOrdersEPL,
|
||||
"futures Orders By ID": futuresOrdersByIDEPL,
|
||||
"futures Retrieve Fills": futuresRetrieveFillsEPL,
|
||||
"futures Recent Fills": futuresRecentFillsEPL,
|
||||
"futures Open Order Stats": futuresOpenOrderStatsEPL,
|
||||
"futures Position": futuresPositionEPL,
|
||||
"futures Position List": futuresPositionListEPL,
|
||||
"set Auto Deposit Margin": setAutoDepositMarginEPL,
|
||||
"max Withdraw Margin": maxWithdrawMarginEPL,
|
||||
"remove Margin Manually": removeMarginManuallyEPL,
|
||||
"futures Add Margin Manually": futuresAddMarginManuallyEPL,
|
||||
"futures Risk Limit Level": futuresRiskLimitLevelEPL,
|
||||
"futures Update Risk Limit Level": futuresUpdateRiskLimitLevelEPL,
|
||||
"futures Current Funding Rate": futuresCurrentFundingRateEPL,
|
||||
"futures Public Funding Rate": futuresPublicFundingRateEPL,
|
||||
"futures Funding History": futuresFundingHistoryEPL,
|
||||
"spot Authentication": spotAuthenticationEPL,
|
||||
"futures Authentication": futuresAuthenticationEPL,
|
||||
"futures Order Details By Client Order ID": futuresOrderDetailsByClientOrderIDEPL,
|
||||
"modify Sub Account API": modifySubAccountAPIEPL,
|
||||
"all Sub Accounts Balance": allSubAccountsBalanceEPL,
|
||||
"all User Sub Accounts V2": allUserSubAccountsV2EPL,
|
||||
"futures Retrieve Transaction History": futuresRetrieveTransactionHistoryEPL,
|
||||
"futures Account Overview": futuresAccountOverviewEPL,
|
||||
"create Sub Account API Key": createSubAccountAPIKeyEPL,
|
||||
"transfer Out To Main": transferOutToMainEPL,
|
||||
"transfer Fund To Futures Account": transferFundToFuturesAccountEPL,
|
||||
"futures Transfer Out List": futuresTransferOutListEPL,
|
||||
}
|
||||
rl, err := request.New("rateLimitTest2", http.DefaultClient, request.WithLimiter(GetRateLimit()))
|
||||
require.NoError(t, err)
|
||||
for name, tt := range testTable {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
if err := rl.InitiateRateLimit(context.Background(), tt); err != nil {
|
||||
t.Fatalf("error applying rate limit: %v", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -38,7 +38,7 @@ const (
|
||||
publicBullets = "/v1/bullet-public"
|
||||
privateBullets = "/v1/bullet-private"
|
||||
|
||||
// spot channels
|
||||
// Spot channels
|
||||
marketTickerChannel = "/market/ticker" // /market/ticker:{symbol},...
|
||||
marketSnapshotChannel = "/market/snapshot" // /market/snapshot:{symbol},...
|
||||
marketOrderbookChannel = "/market/level2" // /market/level2:{symbol},...
|
||||
@@ -56,21 +56,24 @@ const (
|
||||
marginLoanChannel = "/margin/loan" // /margin/loan:{currency}
|
||||
spotMarketAdvancedChannel = "/spotMarket/advancedOrders"
|
||||
|
||||
// futures channels
|
||||
futuresTickerChannel = "/contractMarket/tickerV2" // /contractMarket/tickerV2:{symbol},...
|
||||
futuresOrderbookChannel = "/contractMarket/level2" // /contractMarket/level2:{symbol},...
|
||||
futuresOrderbookDepth5Channel = "/contractMarket/level2Depth5" // /contractMarket/level2Depth5:{symbol},...
|
||||
futuresOrderbookDepth50Channel = "/contractMarket/level2Depth50" // /contractMarket/level2Depth50:{symbol},...
|
||||
futuresExecutionDataChannel = "/contractMarket/execution" // /contractMarket/execution:{symbol},...
|
||||
futuresContractMarketDataChannel = "/contract/instrument" // /contract/instrument:{symbol},...
|
||||
futuresSystemAnnouncementChannel = "/contract/announcement"
|
||||
futuresTrasactionStatisticsTimerEventChannel = "/contractMarket/snapshot" // /contractMarket/snapshot:{symbol},...
|
||||
// Futures channels
|
||||
futuresTransactionStatisticsTimerEventChannel = "/contractMarket/snapshot" // /contractMarket/snapshot:{symbol}
|
||||
futuresTickerChannel = "/contractMarket/tickerV2" // /contractMarket/tickerV2:{symbol},...
|
||||
futuresOrderbookChannel = "/contractMarket/level2" // /contractMarket/level2:{symbol},...
|
||||
futuresOrderbookDepth5Channel = "/contractMarket/level2Depth5" // /contractMarket/level2Depth5:{symbol},...
|
||||
futuresOrderbookDepth50Channel = "/contractMarket/level2Depth50" // /contractMarket/level2Depth50:{symbol},...
|
||||
futuresExecutionDataChannel = "/contractMarket/execution" // /contractMarket/execution:{symbol},...
|
||||
futuresContractMarketDataChannel = "/contract/instrument" // /contract/instrument:{symbol},...
|
||||
futuresSystemAnnouncementChannel = "/contract/announcement"
|
||||
futuresTrasactionStatisticsTimerEventChannel = "/contractMarket/snapshot" // /contractMarket/snapshot:{symbol},...
|
||||
|
||||
// futures private channels
|
||||
futuresTradeOrderChannel = "/contractMarket/tradeOrders" // /contractMarket/tradeOrders:{symbol},...
|
||||
futuresPositionChangeEventChannel = "/contract/position" // /contract/position:{symbol},...
|
||||
futuresStopOrdersLifecycleEventChannel = "/contractMarket/advancedOrders"
|
||||
futuresAccountBalanceEventChannel = "/contractAccount/wallet"
|
||||
|
||||
futuresLimitCandles = "/contractMarket/limitCandle"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -174,9 +177,9 @@ func (ku *Kucoin) GetAuthenticatedInstanceServers(ctx context.Context) (*WSInsta
|
||||
Data *WSInstanceServers `json:"data"`
|
||||
Error
|
||||
}{}
|
||||
err := ku.SendAuthHTTPRequest(ctx, exchange.RestSpot, defaultSpotEPL, http.MethodPost, privateBullets, nil, &response)
|
||||
err := ku.SendAuthHTTPRequest(ctx, exchange.RestSpot, spotAuthenticationEPL, http.MethodPost, privateBullets, nil, &response)
|
||||
if err != nil && strings.Contains(err.Error(), "400003") {
|
||||
return response.Data, ku.SendAuthHTTPRequest(ctx, exchange.RestFutures, defaultFuturesEPL, http.MethodPost, privateBullets, nil, &response)
|
||||
return response.Data, ku.SendAuthHTTPRequest(ctx, exchange.RestFutures, futuresAuthenticationEPL, http.MethodPost, privateBullets, nil, &response)
|
||||
}
|
||||
return response.Data, err
|
||||
}
|
||||
@@ -196,6 +199,7 @@ func (ku *Kucoin) wsReadData() {
|
||||
}
|
||||
}
|
||||
|
||||
// wsHandleData processes a websocket incoming data.
|
||||
func (ku *Kucoin) wsHandleData(respData []byte) error {
|
||||
resp := WsPushData{}
|
||||
err := json.Unmarshal(respData, &resp)
|
||||
@@ -268,7 +272,8 @@ func (ku *Kucoin) wsHandleData(respData []byte) error {
|
||||
return err
|
||||
}
|
||||
return ku.processFuturesOrderbookLevel2(resp.Data, topicInfo[1])
|
||||
case futuresOrderbookDepth5Channel, futuresOrderbookDepth50Channel:
|
||||
case futuresOrderbookDepth5Channel,
|
||||
futuresOrderbookDepth50Channel:
|
||||
if err := ku.ensureFuturesOrderbookSnapshotLoaded(topicInfo[1]); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -282,7 +287,7 @@ func (ku *Kucoin) wsHandleData(respData []byte) error {
|
||||
}
|
||||
case futuresSystemAnnouncementChannel:
|
||||
return ku.processFuturesSystemAnnouncement(resp.Data, resp.Subject)
|
||||
case futuresTrasactionStatisticsTimerEventChannel:
|
||||
case futuresTransactionStatisticsTimerEventChannel:
|
||||
return ku.processFuturesTransactionStatistics(resp.Data, topicInfo[1])
|
||||
case futuresTradeOrderChannel:
|
||||
return ku.processFuturesPrivateTradeOrders(resp.Data)
|
||||
@@ -312,6 +317,12 @@ func (ku *Kucoin) wsHandleData(respData []byte) error {
|
||||
var response WsFuturesPositionFundingSettlement
|
||||
return ku.processData(resp.Data, &response)
|
||||
}
|
||||
case futuresLimitCandles:
|
||||
instrumentInfos := strings.Split(topicInfo[1], "_")
|
||||
if len(instrumentInfos) != 2 {
|
||||
return errors.New("invalid instrument information")
|
||||
}
|
||||
return ku.processFuturesKline(resp.Data, instrumentInfos[1])
|
||||
default:
|
||||
ku.Websocket.DataHandler <- stream.UnhandledMessageWarning{
|
||||
Message: ku.Name + stream.UnhandledMessage + string(respData),
|
||||
@@ -321,6 +332,7 @@ func (ku *Kucoin) wsHandleData(respData []byte) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// processData used to deserialize and forward the data to DataHandler.
|
||||
func (ku *Kucoin) processData(respData []byte, resp interface{}) error {
|
||||
if err := json.Unmarshal(respData, &resp); err != nil {
|
||||
return err
|
||||
@@ -329,6 +341,7 @@ func (ku *Kucoin) processData(respData []byte, resp interface{}) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// processFuturesAccountBalanceEvent used to process futures account balance change incoming data.
|
||||
func (ku *Kucoin) processFuturesAccountBalanceEvent(respData []byte) error {
|
||||
resp := WsFuturesAvailableBalance{}
|
||||
if err := json.Unmarshal(respData, &resp); err != nil {
|
||||
@@ -343,6 +356,7 @@ func (ku *Kucoin) processFuturesAccountBalanceEvent(respData []byte) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// processFuturesStopOrderLifecycleEvent processes futures stop orders lifecycle events.
|
||||
func (ku *Kucoin) processFuturesStopOrderLifecycleEvent(respData []byte) error {
|
||||
resp := WsStopOrderLifecycleEvent{}
|
||||
err := json.Unmarshal(respData, &resp)
|
||||
@@ -382,6 +396,7 @@ func (ku *Kucoin) processFuturesStopOrderLifecycleEvent(respData []byte) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// processFuturesPrivateTradeOrders processes futures private trade orders updates.
|
||||
func (ku *Kucoin) processFuturesPrivateTradeOrders(respData []byte) error {
|
||||
resp := WsFuturesTradeOrder{}
|
||||
if err := json.Unmarshal(respData, &resp); err != nil {
|
||||
@@ -391,7 +406,7 @@ func (ku *Kucoin) processFuturesPrivateTradeOrders(respData []byte) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
oStatus, err := ku.stringToOrderStatus(resp.Status)
|
||||
oStatus, err := ku.StringToOrderStatus(resp.Status)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -426,6 +441,7 @@ func (ku *Kucoin) processFuturesPrivateTradeOrders(respData []byte) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// processFuturesTransactionStatistics processes a futures transaction statistics
|
||||
func (ku *Kucoin) processFuturesTransactionStatistics(respData []byte, instrument string) error {
|
||||
resp := WsFuturesTransactionStatisticsTimeEvent{}
|
||||
if err := json.Unmarshal(respData, &resp); err != nil {
|
||||
@@ -435,6 +451,7 @@ func (ku *Kucoin) processFuturesTransactionStatistics(respData []byte, instrumen
|
||||
return nil
|
||||
}
|
||||
|
||||
// processFuturesSystemAnnouncement processes a system announcement.
|
||||
func (ku *Kucoin) processFuturesSystemAnnouncement(respData []byte, subject string) error {
|
||||
resp := WsFuturesFundingBegin{}
|
||||
if err := json.Unmarshal(respData, &resp); err != nil {
|
||||
@@ -445,6 +462,7 @@ func (ku *Kucoin) processFuturesSystemAnnouncement(respData []byte, subject stri
|
||||
return nil
|
||||
}
|
||||
|
||||
// processFuturesFundingData processes a futures account funding data.
|
||||
func (ku *Kucoin) processFuturesFundingData(respData []byte, instrument string) error {
|
||||
resp := WsFundingRate{}
|
||||
if err := json.Unmarshal(respData, &resp); err != nil {
|
||||
@@ -455,6 +473,7 @@ func (ku *Kucoin) processFuturesFundingData(respData []byte, instrument string)
|
||||
return nil
|
||||
}
|
||||
|
||||
// processFuturesMarkPriceAndIndexPrice processes a futures account mark price and index price changes.
|
||||
func (ku *Kucoin) processFuturesMarkPriceAndIndexPrice(respData []byte, instrument string) error {
|
||||
resp := WsFuturesMarkPriceAndIndexPrice{}
|
||||
if err := json.Unmarshal(respData, &resp); err != nil {
|
||||
@@ -488,6 +507,7 @@ func (ku *Kucoin) ensureFuturesOrderbookSnapshotLoaded(symbol string) error {
|
||||
return ku.Websocket.Orderbook.LoadSnapshot(orderbooks)
|
||||
}
|
||||
|
||||
// processFuturesOrderbookSnapshot processes a futures account orderbook websocket update.
|
||||
func (ku *Kucoin) processFuturesOrderbookSnapshot(respData []byte, instrument string) error {
|
||||
response := WsOrderbookLevel5Response{}
|
||||
if err := json.Unmarshal(respData, &response); err != nil {
|
||||
@@ -512,6 +532,7 @@ func (ku *Kucoin) processFuturesOrderbookSnapshot(respData []byte, instrument st
|
||||
})
|
||||
}
|
||||
|
||||
// ProcessFuturesOrderbookLevel2 processes a V2 futures account orderbook data.
|
||||
func (ku *Kucoin) processFuturesOrderbookLevel2(respData []byte, instrument string) error {
|
||||
resp := WsFuturesOrderbookInfo{}
|
||||
if err := json.Unmarshal(respData, &resp); err != nil {
|
||||
@@ -539,6 +560,7 @@ func (ku *Kucoin) processFuturesOrderbookLevel2(respData []byte, instrument stri
|
||||
return ku.Websocket.Orderbook.Update(&base)
|
||||
}
|
||||
|
||||
// processFuturesTickerV2 processes a futures account ticker data.
|
||||
func (ku *Kucoin) processFuturesTickerV2(respData []byte) error {
|
||||
resp := WsFuturesTicker{}
|
||||
if err := json.Unmarshal(respData, &resp); err != nil {
|
||||
@@ -554,19 +576,48 @@ func (ku *Kucoin) processFuturesTickerV2(respData []byte) error {
|
||||
}
|
||||
ku.Websocket.DataHandler <- &ticker.Price{
|
||||
AssetType: asset.Futures,
|
||||
Last: resp.FilledPrice,
|
||||
Volume: resp.FilledSize,
|
||||
Last: resp.FilledPrice.Float64(),
|
||||
Volume: resp.FilledSize.Float64(),
|
||||
LastUpdated: resp.FilledTime.Time(),
|
||||
ExchangeName: ku.Name,
|
||||
Pair: pair,
|
||||
Ask: resp.BestAskPrice.Float64(),
|
||||
Bid: resp.BestBidPrice.Float64(),
|
||||
AskSize: resp.BestAskSize,
|
||||
BidSize: resp.BestBidSize,
|
||||
AskSize: resp.BestAskSize.Float64(),
|
||||
BidSize: resp.BestBidSize.Float64(),
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// processFuturesKline represents a futures instrument kline data update.
|
||||
func (ku *Kucoin) processFuturesKline(respData []byte, intervalStr string) error {
|
||||
resp := WsFuturesKline{}
|
||||
err := json.Unmarshal(respData, &resp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var pair currency.Pair
|
||||
pair, err = currency.NewPairFromString(resp.Symbol)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ku.Websocket.DataHandler <- &stream.KlineData{
|
||||
Timestamp: resp.Time.Time(),
|
||||
AssetType: asset.Futures,
|
||||
Exchange: ku.Name,
|
||||
StartTime: time.Unix(resp.Candles[0].Int64(), 0),
|
||||
Interval: intervalStr,
|
||||
OpenPrice: resp.Candles[1].Float64(),
|
||||
ClosePrice: resp.Candles[2].Float64(),
|
||||
HighPrice: resp.Candles[3].Float64(),
|
||||
LowPrice: resp.Candles[4].Float64(),
|
||||
Volume: resp.Candles[6].Float64(),
|
||||
Pair: pair,
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// processStopOrderEvent represents a stop order update event.
|
||||
func (ku *Kucoin) processStopOrderEvent(respData []byte) error {
|
||||
resp := WsStopOrder{}
|
||||
err := json.Unmarshal(respData, &resp)
|
||||
@@ -602,6 +653,7 @@ func (ku *Kucoin) processStopOrderEvent(respData []byte) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// processMarginLendingTradeOrderEvent represents a margin lending trade order event.
|
||||
func (ku *Kucoin) processMarginLendingTradeOrderEvent(respData []byte) error {
|
||||
resp := WsMarginTradeOrderEntersEvent{}
|
||||
if err := json.Unmarshal(respData, &resp); err != nil {
|
||||
@@ -611,6 +663,7 @@ func (ku *Kucoin) processMarginLendingTradeOrderEvent(respData []byte) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// processAccountBalanceChange processes an account balance change
|
||||
func (ku *Kucoin) processAccountBalanceChange(respData []byte) error {
|
||||
response := WsAccountBalance{}
|
||||
err := json.Unmarshal(respData, &response)
|
||||
@@ -626,6 +679,7 @@ func (ku *Kucoin) processAccountBalanceChange(respData []byte) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// processOrderChangeEvent processes order update events.
|
||||
func (ku *Kucoin) processOrderChangeEvent(respData []byte, topic string) error {
|
||||
response := WsTradeOrder{}
|
||||
err := json.Unmarshal(respData, &response)
|
||||
@@ -636,7 +690,7 @@ func (ku *Kucoin) processOrderChangeEvent(respData []byte, topic string) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
oStatus, err := ku.stringToOrderStatus(response.Status)
|
||||
oStatus, err := ku.StringToOrderStatus(response.Status)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -674,6 +728,7 @@ func (ku *Kucoin) processOrderChangeEvent(respData []byte, topic string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// processTradeData processes a websocket trade data and instruments.
|
||||
func (ku *Kucoin) processTradeData(respData []byte, instrument, topic string) error {
|
||||
response := WsTrade{}
|
||||
err := json.Unmarshal(respData, &response)
|
||||
@@ -715,6 +770,7 @@ func (ku *Kucoin) processTradeData(respData []byte, instrument, topic string) er
|
||||
return nil
|
||||
}
|
||||
|
||||
// processTicker processes a ticker data for an instrument.
|
||||
func (ku *Kucoin) processTicker(respData []byte, instrument, topic string) error {
|
||||
response := WsTicker{}
|
||||
err := json.Unmarshal(respData, &response)
|
||||
@@ -749,6 +805,7 @@ func (ku *Kucoin) processTicker(respData []byte, instrument, topic string) error
|
||||
return nil
|
||||
}
|
||||
|
||||
// processCandlesticks processes a candlestick data for an instrument with a particular interval
|
||||
func (ku *Kucoin) processCandlesticks(respData []byte, instrument, intervalString, topic string) error {
|
||||
pair, err := currency.NewPairFromString(instrument)
|
||||
if err != nil {
|
||||
@@ -788,6 +845,7 @@ func (ku *Kucoin) processCandlesticks(respData []byte, instrument, intervalStrin
|
||||
return nil
|
||||
}
|
||||
|
||||
// processOrderbookWithDepth processes order book data with a specified depth for a particular symbol.
|
||||
func (ku *Kucoin) processOrderbookWithDepth(respData []byte, instrument, topic string) error {
|
||||
pair, err := currency.NewPairFromString(instrument)
|
||||
if err != nil {
|
||||
@@ -806,7 +864,7 @@ func (ku *Kucoin) processOrderbookWithDepth(respData []byte, instrument, topic s
|
||||
}
|
||||
for x := range assets {
|
||||
var init bool
|
||||
init, err = ku.UpdateLocalBuffer(result.Result, assets[x])
|
||||
init, err = ku.updateLocalBuffer(result.Result, assets[x])
|
||||
if err != nil {
|
||||
if init {
|
||||
return nil
|
||||
@@ -817,9 +875,9 @@ func (ku *Kucoin) processOrderbookWithDepth(respData []byte, instrument, topic s
|
||||
return nil
|
||||
}
|
||||
|
||||
// UpdateLocalBuffer updates orderbook buffer and checks status if the book is Initial Sync being via the REST
|
||||
// updateLocalBuffer updates orderbook buffer and checks status if the book is Initial Sync being via the REST
|
||||
// protocol.
|
||||
func (ku *Kucoin) UpdateLocalBuffer(wsdp *WsOrderbook, assetType asset.Item) (bool, error) {
|
||||
func (ku *Kucoin) updateLocalBuffer(wsdp *WsOrderbook, assetType asset.Item) (bool, error) {
|
||||
enabledPairs, err := ku.GetEnabledPairs(assetType)
|
||||
if err != nil {
|
||||
return false, err
|
||||
@@ -836,9 +894,9 @@ func (ku *Kucoin) UpdateLocalBuffer(wsdp *WsOrderbook, assetType asset.Item) (bo
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
err = ku.obm.stageWsUpdate(wsdp, currencyPair, assetType)
|
||||
err = ku.obm.StageWsUpdate(wsdp, currencyPair, assetType)
|
||||
if err != nil {
|
||||
init, err2 := ku.obm.checkIsInitialSync(currencyPair, assetType)
|
||||
init, err2 := ku.obm.CheckIsInitialSync(currencyPair, assetType)
|
||||
if err2 != nil {
|
||||
return false, err2
|
||||
}
|
||||
@@ -847,12 +905,13 @@ func (ku *Kucoin) UpdateLocalBuffer(wsdp *WsOrderbook, assetType asset.Item) (bo
|
||||
|
||||
err = ku.applyBufferUpdate(currencyPair, assetType)
|
||||
if err != nil {
|
||||
ku.flushAndCleanup(currencyPair, assetType)
|
||||
ku.FlushAndCleanup(currencyPair, assetType)
|
||||
}
|
||||
|
||||
return false, err
|
||||
}
|
||||
|
||||
// processOrderbook processes orderbook data for a specific symbol.
|
||||
func (ku *Kucoin) processOrderbook(respData []byte, symbol, topic string) error {
|
||||
var response Level2Depth5Or20
|
||||
err := json.Unmarshal(respData, &response)
|
||||
@@ -882,8 +941,10 @@ func (ku *Kucoin) processOrderbook(respData []byte, symbol, topic string) error
|
||||
return err
|
||||
}
|
||||
|
||||
lastUpdated := time.UnixMilli(response.Timestamp)
|
||||
|
||||
var lastUpdatedTime = response.Timestamp.Time()
|
||||
if response.Timestamp.Time().IsZero() {
|
||||
lastUpdatedTime = time.Now()
|
||||
}
|
||||
for x := range assets {
|
||||
err = ku.Websocket.Orderbook.LoadSnapshot(&orderbook.Base{
|
||||
Exchange: ku.Name,
|
||||
@@ -891,7 +952,7 @@ func (ku *Kucoin) processOrderbook(respData []byte, symbol, topic string) error
|
||||
Bids: bids,
|
||||
Pair: pair,
|
||||
Asset: assets[x],
|
||||
LastUpdated: lastUpdated,
|
||||
LastUpdated: lastUpdatedTime,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -900,6 +961,7 @@ func (ku *Kucoin) processOrderbook(respData []byte, symbol, topic string) error
|
||||
return nil
|
||||
}
|
||||
|
||||
// processMarketSnapshot processes a price ticker information for a symbol.
|
||||
func (ku *Kucoin) processMarketSnapshot(respData []byte, topic string) error {
|
||||
response := WsSnapshot{}
|
||||
err := json.Unmarshal(respData, &response)
|
||||
@@ -1038,6 +1100,7 @@ type job struct {
|
||||
AssetType asset.Item
|
||||
}
|
||||
|
||||
// setupOrderbookManager sets up the orderbook manager for websocket orderbook data handling.
|
||||
func (ku *Kucoin) setupOrderbookManager() {
|
||||
locker.Lock()
|
||||
defer locker.Unlock()
|
||||
@@ -1066,46 +1129,23 @@ func (ku *Kucoin) setupOrderbookManager() {
|
||||
}
|
||||
}
|
||||
|
||||
// ProcessUpdate processes the websocket orderbook update
|
||||
func (ku *Kucoin) ProcessUpdate(cp currency.Pair, a asset.Item, ws *WsOrderbook) error {
|
||||
// processUpdate processes the websocket orderbook update
|
||||
func (ku *Kucoin) processUpdate(cp currency.Pair, a asset.Item, ws *WsOrderbook) error {
|
||||
updateBid := make([]orderbook.Tranche, len(ws.Changes.Bids))
|
||||
for i := range ws.Changes.Bids {
|
||||
p, err := strconv.ParseFloat(ws.Changes.Bids[i][0], 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
a, err := strconv.ParseFloat(ws.Changes.Bids[i][1], 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var sequence int64
|
||||
if len(ws.Changes.Bids[i]) > 2 && ws.Changes.Bids[i][2] != "" {
|
||||
sequence, err = strconv.ParseInt(ws.Changes.Bids[i][2], 10, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(ws.Changes.Bids[i]) > 2 {
|
||||
sequence = ws.Changes.Bids[i][2].Int64()
|
||||
}
|
||||
updateBid[i] = orderbook.Tranche{Price: p, Amount: a, ID: sequence}
|
||||
updateBid[i] = orderbook.Tranche{Price: ws.Changes.Bids[i][0].Float64(), Amount: ws.Changes.Bids[i][1].Float64(), ID: sequence}
|
||||
}
|
||||
|
||||
updateAsk := make([]orderbook.Tranche, len(ws.Changes.Asks))
|
||||
for i := range ws.Changes.Asks {
|
||||
p, err := strconv.ParseFloat(ws.Changes.Asks[i][0], 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
a, err := strconv.ParseFloat(ws.Changes.Asks[i][1], 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var sequence int64
|
||||
if len(ws.Changes.Asks[i]) > 2 && ws.Changes.Asks[i][2] != "" {
|
||||
sequence, err = strconv.ParseInt(ws.Changes.Asks[i][2], 10, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(ws.Changes.Asks[i]) > 2 {
|
||||
sequence = ws.Changes.Asks[i][2].Int64()
|
||||
}
|
||||
updateAsk[i] = orderbook.Tranche{Price: p, Amount: a, ID: sequence}
|
||||
updateAsk[i] = orderbook.Tranche{Price: ws.Changes.Asks[i][0].Float64(), Amount: ws.Changes.Asks[i][1].Float64(), ID: sequence}
|
||||
}
|
||||
|
||||
return ku.Websocket.Orderbook.Update(&orderbook.Update{
|
||||
@@ -1121,7 +1161,7 @@ func (ku *Kucoin) ProcessUpdate(cp currency.Pair, a asset.Item, ws *WsOrderbook)
|
||||
// applyBufferUpdate applies the buffer to the orderbook or initiates a new
|
||||
// orderbook sync by the REST protocol which is off handed to go routine.
|
||||
func (ku *Kucoin) applyBufferUpdate(pair currency.Pair, assetType asset.Item) error {
|
||||
fetching, needsFetching, err := ku.obm.handleFetchingBook(pair, assetType)
|
||||
fetching, needsFetching, err := ku.obm.HandleFetchingBook(pair, assetType)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -1132,7 +1172,7 @@ func (ku *Kucoin) applyBufferUpdate(pair currency.Pair, assetType asset.Item) er
|
||||
if ku.Verbose {
|
||||
log.Debugf(log.WebsocketMgr, "%s Orderbook: Fetching via REST\n", ku.Name)
|
||||
}
|
||||
return ku.obm.fetchBookViaREST(pair, assetType)
|
||||
return ku.obm.FetchBookViaREST(pair, assetType)
|
||||
}
|
||||
|
||||
recent, err := ku.Websocket.Orderbook.GetOrderbook(pair, assetType)
|
||||
@@ -1145,7 +1185,7 @@ func (ku *Kucoin) applyBufferUpdate(pair currency.Pair, assetType asset.Item) er
|
||||
}
|
||||
|
||||
if recent != nil {
|
||||
err = ku.obm.checkAndProcessUpdate(ku.ProcessUpdate, pair, assetType, recent)
|
||||
err = ku.obm.CheckAndProcessUpdate(ku.processUpdate, pair, assetType, recent)
|
||||
if err != nil {
|
||||
log.Errorf(
|
||||
log.WebsocketMgr,
|
||||
@@ -1249,7 +1289,7 @@ func (ku *Kucoin) SeedLocalCacheWithBook(p currency.Pair, orderbookNew *Orderboo
|
||||
func (ku *Kucoin) processJob(p currency.Pair, assetType asset.Item) error {
|
||||
err := ku.SeedLocalCache(context.TODO(), p, assetType)
|
||||
if err != nil {
|
||||
err = ku.obm.stopFetchingBook(p, assetType)
|
||||
err = ku.obm.StopFetchingBook(p, assetType)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -1257,7 +1297,7 @@ func (ku *Kucoin) processJob(p currency.Pair, assetType asset.Item) error {
|
||||
p, assetType, err)
|
||||
}
|
||||
|
||||
err = ku.obm.stopFetchingBook(p, assetType)
|
||||
err = ku.obm.StopFetchingBook(p, assetType)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -1266,14 +1306,14 @@ func (ku *Kucoin) processJob(p currency.Pair, assetType asset.Item) error {
|
||||
// new update to initiate this.
|
||||
err = ku.applyBufferUpdate(p, assetType)
|
||||
if err != nil {
|
||||
ku.flushAndCleanup(p, assetType)
|
||||
ku.FlushAndCleanup(p, assetType)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// flushAndCleanup flushes orderbook and clean local cache
|
||||
func (ku *Kucoin) flushAndCleanup(p currency.Pair, assetType asset.Item) {
|
||||
// FlushAndCleanup flushes orderbook and clean local cache
|
||||
func (ku *Kucoin) FlushAndCleanup(p currency.Pair, assetType asset.Item) {
|
||||
errClean := ku.Websocket.Orderbook.FlushOrderbook(p, assetType)
|
||||
if errClean != nil {
|
||||
log.Errorf(log.WebsocketMgr,
|
||||
@@ -1281,7 +1321,7 @@ func (ku *Kucoin) flushAndCleanup(p currency.Pair, assetType asset.Item) {
|
||||
ku.Name,
|
||||
errClean)
|
||||
}
|
||||
errClean = ku.obm.cleanup(p, assetType)
|
||||
errClean = ku.obm.Cleanup(p, assetType)
|
||||
if errClean != nil {
|
||||
log.Errorf(log.WebsocketMgr, "%s cleanup websocket error: %v",
|
||||
ku.Name,
|
||||
@@ -1289,9 +1329,9 @@ func (ku *Kucoin) flushAndCleanup(p currency.Pair, assetType asset.Item) {
|
||||
}
|
||||
}
|
||||
|
||||
// stageWsUpdate stages websocket update to roll through updates that need to
|
||||
// StageWsUpdate stages websocket update to roll through updates that need to
|
||||
// be applied to a fetched orderbook via REST.
|
||||
func (o *orderbookManager) stageWsUpdate(u *WsOrderbook, pair currency.Pair, a asset.Item) error {
|
||||
func (o *orderbookManager) StageWsUpdate(u *WsOrderbook, pair currency.Pair, a asset.Item) error {
|
||||
o.Lock()
|
||||
defer o.Unlock()
|
||||
m1, ok := o.state[pair.Base]
|
||||
@@ -1336,9 +1376,9 @@ func (o *orderbookManager) stageWsUpdate(u *WsOrderbook, pair currency.Pair, a a
|
||||
}
|
||||
}
|
||||
|
||||
// handleFetchingBook checks if a full book is being fetched or needs to be
|
||||
// HandleFetchingBook checks if a full book is being fetched or needs to be
|
||||
// fetched
|
||||
func (o *orderbookManager) handleFetchingBook(pair currency.Pair, assetType asset.Item) (fetching, needsFetching bool, err error) {
|
||||
func (o *orderbookManager) HandleFetchingBook(pair currency.Pair, assetType asset.Item) (fetching, needsFetching bool, err error) {
|
||||
o.Lock()
|
||||
defer o.Unlock()
|
||||
state, ok := o.state[pair.Base][pair.Quote][assetType]
|
||||
@@ -1362,8 +1402,8 @@ func (o *orderbookManager) handleFetchingBook(pair currency.Pair, assetType asse
|
||||
return false, false, nil
|
||||
}
|
||||
|
||||
// stopFetchingBook completes the book fetching.
|
||||
func (o *orderbookManager) stopFetchingBook(pair currency.Pair, assetType asset.Item) error {
|
||||
// StopFetchingBook completes the book fetching.
|
||||
func (o *orderbookManager) StopFetchingBook(pair currency.Pair, assetType asset.Item) error {
|
||||
o.Lock()
|
||||
defer o.Unlock()
|
||||
state, ok := o.state[pair.Base][pair.Quote][assetType]
|
||||
@@ -1381,8 +1421,8 @@ func (o *orderbookManager) stopFetchingBook(pair currency.Pair, assetType asset.
|
||||
return nil
|
||||
}
|
||||
|
||||
// completeInitialSync sets if an asset type has completed its initial sync
|
||||
func (o *orderbookManager) completeInitialSync(pair currency.Pair, assetType asset.Item) error {
|
||||
// CompleteInitialSync sets if an asset type has completed its initial sync
|
||||
func (o *orderbookManager) CompleteInitialSync(pair currency.Pair, assetType asset.Item) error {
|
||||
o.Lock()
|
||||
defer o.Unlock()
|
||||
state, ok := o.state[pair.Base][pair.Quote][assetType]
|
||||
@@ -1400,9 +1440,9 @@ func (o *orderbookManager) completeInitialSync(pair currency.Pair, assetType ass
|
||||
return nil
|
||||
}
|
||||
|
||||
// checkIsInitialSync checks status if the book is Initial Sync being via the REST
|
||||
// CheckIsInitialSync checks status if the book is Initial Sync being via the REST
|
||||
// protocol.
|
||||
func (o *orderbookManager) checkIsInitialSync(pair currency.Pair, assetType asset.Item) (bool, error) {
|
||||
func (o *orderbookManager) CheckIsInitialSync(pair currency.Pair, assetType asset.Item) (bool, error) {
|
||||
o.Lock()
|
||||
defer o.Unlock()
|
||||
state, ok := o.state[pair.Base][pair.Quote][assetType]
|
||||
@@ -1415,9 +1455,9 @@ func (o *orderbookManager) checkIsInitialSync(pair currency.Pair, assetType asse
|
||||
return state.initialSync, nil
|
||||
}
|
||||
|
||||
// fetchBookViaREST pushes a job of fetching the orderbook via the REST protocol
|
||||
// FetchBookViaREST pushes a job of fetching the orderbook via the REST protocol
|
||||
// to get an initial full book that we can apply our buffered updates too.
|
||||
func (o *orderbookManager) fetchBookViaREST(pair currency.Pair, assetType asset.Item) error {
|
||||
func (o *orderbookManager) FetchBookViaREST(pair currency.Pair, assetType asset.Item) error {
|
||||
o.Lock()
|
||||
defer o.Unlock()
|
||||
|
||||
@@ -1441,7 +1481,7 @@ func (o *orderbookManager) fetchBookViaREST(pair currency.Pair, assetType asset.
|
||||
}
|
||||
}
|
||||
|
||||
func (o *orderbookManager) checkAndProcessUpdate(processor func(currency.Pair, asset.Item, *WsOrderbook) error, pair currency.Pair, assetType asset.Item, recent *orderbook.Base) error {
|
||||
func (o *orderbookManager) CheckAndProcessUpdate(processor func(currency.Pair, asset.Item, *WsOrderbook) error, pair currency.Pair, assetType asset.Item, recent *orderbook.Base) error {
|
||||
o.Lock()
|
||||
defer o.Unlock()
|
||||
state, ok := o.state[pair.Base][pair.Quote][assetType]
|
||||
@@ -1456,7 +1496,7 @@ buffer:
|
||||
for {
|
||||
select {
|
||||
case d := <-state.buffer:
|
||||
process, err := state.validate(d, recent)
|
||||
process, err := state.Validate(d, recent)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -1474,8 +1514,8 @@ buffer:
|
||||
return nil
|
||||
}
|
||||
|
||||
// validate checks for correct update alignment
|
||||
func (u *update) validate(updt *WsOrderbook, recent *orderbook.Base) (bool, error) {
|
||||
// Validate checks for correct update alignment
|
||||
func (u *update) Validate(updt *WsOrderbook, recent *orderbook.Base) (bool, error) {
|
||||
if updt.SequenceEnd <= recent.LastUpdateID {
|
||||
// Drop any event where u is <= lastUpdateId in the snapshot.
|
||||
return false, nil
|
||||
@@ -1495,8 +1535,8 @@ func (u *update) validate(updt *WsOrderbook, recent *orderbook.Base) (bool, erro
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// cleanup cleans up buffer and reset fetch and init
|
||||
func (o *orderbookManager) cleanup(pair currency.Pair, assetType asset.Item) error {
|
||||
// Cleanup cleans up buffer and reset fetch and init
|
||||
func (o *orderbookManager) Cleanup(pair currency.Pair, assetType asset.Item) error {
|
||||
o.Lock()
|
||||
state, ok := o.state[pair.Base][pair.Quote][assetType]
|
||||
if !ok {
|
||||
@@ -1517,14 +1557,14 @@ bufferEmpty:
|
||||
}
|
||||
o.Unlock()
|
||||
// disable rest orderbook synchronisation
|
||||
_ = o.stopFetchingBook(pair, assetType)
|
||||
_ = o.completeInitialSync(pair, assetType)
|
||||
_ = o.stopNeedsFetchingBook(pair, assetType)
|
||||
_ = o.StopFetchingBook(pair, assetType)
|
||||
_ = o.CompleteInitialSync(pair, assetType)
|
||||
_ = o.StopNeedsFetchingBook(pair, assetType)
|
||||
return nil
|
||||
}
|
||||
|
||||
// stopNeedsFetchingBook completes the book fetching initiation.
|
||||
func (o *orderbookManager) stopNeedsFetchingBook(pair currency.Pair, assetType asset.Item) error {
|
||||
// StopNeedsFetchingBook completes the book fetching initiation.
|
||||
func (o *orderbookManager) StopNeedsFetchingBook(pair currency.Pair, assetType asset.Item) error {
|
||||
o.Lock()
|
||||
defer o.Unlock()
|
||||
state, ok := o.state[pair.Base][pair.Quote][assetType]
|
||||
@@ -1677,7 +1717,7 @@ func isCurrencyChannel(s *subscription.Subscription) bool {
|
||||
// channelInterval returns the channel interval if it has one
|
||||
func channelInterval(s *subscription.Subscription) string {
|
||||
if channelName(s, s.Asset) == marketCandlesChannel {
|
||||
if i, err := intervalToString(s.Interval); err == nil {
|
||||
if i, err := IntervalToString(s.Interval); err == nil {
|
||||
return i
|
||||
}
|
||||
}
|
||||
@@ -1700,7 +1740,7 @@ func assetCurrencies(s *subscription.Subscription, ap map[asset.Item]currency.Pa
|
||||
// If the subscription has a viable interval it's appended after each symbol
|
||||
func joinPairsWithInterval(b currency.Pairs, s *subscription.Subscription) string {
|
||||
out := make([]string, len(b))
|
||||
suffix, err := intervalToString(s.Interval)
|
||||
suffix, err := IntervalToString(s.Interval)
|
||||
if err == nil {
|
||||
suffix = "_" + suffix
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -89,6 +89,9 @@ type Submit struct {
|
||||
|
||||
// Hidden when enabled orders not displaying in order book.
|
||||
Hidden bool
|
||||
|
||||
// Iceberg specifies whether or not only visible portions of orders are shown in iceberg orders
|
||||
Iceberg bool
|
||||
}
|
||||
|
||||
// SubmitResponse is what is returned after submitting an order to an exchange
|
||||
@@ -301,6 +304,8 @@ type MultiOrderRequest struct {
|
||||
// FromOrderID for some APIs require order history searching
|
||||
// from a specific orderID rather than via timestamps
|
||||
FromOrderID string
|
||||
|
||||
MarginType margin.Type
|
||||
}
|
||||
|
||||
// Status defines order status types
|
||||
@@ -418,7 +423,7 @@ type RiskManagement struct {
|
||||
TriggerPriceType PriceType
|
||||
Price float64
|
||||
|
||||
// LimitPrice limit order price when stop-los or take-profit risk management method is triggered
|
||||
// LimitPrice limit order price when stop-loss or take-profit risk management method is triggered
|
||||
LimitPrice float64
|
||||
// OrderType order type when stop-loss or take-profit risk management method is triggered.
|
||||
OrderType Type
|
||||
@@ -430,6 +435,10 @@ type RiskManagementModes struct {
|
||||
Mode string
|
||||
TakeProfit RiskManagement
|
||||
StopLoss RiskManagement
|
||||
|
||||
// StopEntry stop: 'entry': Triggers when the last trade price changes to a value at or above the stopPrice.
|
||||
// see: https://www.kucoin.com/docs/rest/spot-trading/stop-order/introduction
|
||||
StopEntry RiskManagement
|
||||
}
|
||||
|
||||
// PriceType enforces a standard for price types used for take-profit and stop-loss trigger types
|
||||
|
||||
Reference in New Issue
Block a user