diff --git a/exchanges/okx/okx.go b/exchanges/okx/okx.go index 86ed08a3..c1d5d06c 100644 --- a/exchanges/okx/okx.go +++ b/exchanges/okx/okx.go @@ -50,32 +50,27 @@ const ( okxAPIWebsocketPrivateURL = okxWebsocketURL + "private" // tradeEndpoints - tradeOrder = "trade/order" - placeMultipleOrderURL = "trade/batch-orders" - cancelTradeOrder = "trade/cancel-order" - cancelBatchTradeOrders = "trade/cancel-batch-orders" - amendOrder = "trade/amend-order" - amendBatchOrders = "trade/amend-batch-orders" - closePositionPath = "trade/close-position" - pendingTradeOrders = "trade/orders-pending" - tradeHistory = "trade/orders-history" - orderHistoryArchive = "trade/orders-history-archive" - tradeFills = "trade/fills" - tradeFillsHistory = "trade/fills-history" - assetBills = "asset/bills" - lightningDeposit = "asset/deposit-lightning" - assetDeposits = "asset/deposit-address" - pathToAssetDepositHistory = "asset/deposit-history" - assetWithdrawal = "asset/withdrawal" - assetLightningWithdrawal = "asset/withdrawal-lightning" - cancelWithdrawal = "asset/cancel-withdrawal" - withdrawalHistory = "asset/withdrawal-history" - smallAssetsConvert = "asset/convert-dust-assets" - assetSavingBalance = "asset/saving-balance" - assetSavingPurchaseOrRedemptionPath = "asset/purchase_redempt" - assetsLendingHistory = "asset/lending-history" - assetSetLendingRateRoute = "asset/set-lending-rate" - publicBorrowInfo = "asset/lending-rate-history" + tradeOrder = "trade/order" + placeMultipleOrderURL = "trade/batch-orders" + cancelTradeOrder = "trade/cancel-order" + cancelBatchTradeOrders = "trade/cancel-batch-orders" + amendOrder = "trade/amend-order" + amendBatchOrders = "trade/amend-batch-orders" + closePositionPath = "trade/close-position" + pendingTradeOrders = "trade/orders-pending" + tradeHistory = "trade/orders-history" + orderHistoryArchive = "trade/orders-history-archive" + tradeFills = "trade/fills" + tradeFillsHistory = "trade/fills-history" + assetBills = "asset/bills" + lightningDeposit = "asset/deposit-lightning" + assetDeposits = "asset/deposit-address" + pathToAssetDepositHistory = "asset/deposit-history" + assetWithdrawal = "asset/withdrawal" + assetLightningWithdrawal = "asset/withdrawal-lightning" + cancelWithdrawal = "asset/cancel-withdrawal" + withdrawalHistory = "asset/withdrawal-history" + smallAssetsConvert = "asset/convert-dust-assets" // Algo order routes cancelAlgoOrder = "trade/cancel-algos" @@ -234,6 +229,14 @@ const ( financeActiveOrders = "finance/staking-defi/orders-active" financeOrdersHistory = "finance/staking-defi/orders-history" + // Savings + financeSavingBalance = "finance/savings/balance" + financePurchaseRedempt = "finance/savings/purchase-redempt" + financeSetLendingRate = "finance/savings/set-lending-rate" + financeLendingHistory = "finance/savings/lending-history" + financePublicBorrowInfo = "finance/savings/lending-rate-summary" + financePublicBorrowHistory = "finance/savings/lending-rate-history" + // Status Endpoints systemStatus = "system/status" ) @@ -1641,7 +1644,7 @@ func (ok *Okx) GetSavingBalance(ctx context.Context, currency string) ([]SavingB if currency != "" { params.Set("ccy", currency) } - return resp, ok.SendHTTPRequest(ctx, exchange.RestSpot, getSavingBalanceEPL, http.MethodGet, common.EncodeURLValues(assetSavingBalance, params), nil, &resp, true) + return resp, ok.SendHTTPRequest(ctx, exchange.RestSpot, getSavingBalanceEPL, http.MethodGet, common.EncodeURLValues(financeSavingBalance, params), nil, &resp, true) } // SavingsPurchaseOrRedemption creates a purchase or redemption instance @@ -1656,12 +1659,12 @@ func (ok *Okx) SavingsPurchaseOrRedemption(ctx context.Context, arg *SavingsPurc case arg.Amount <= 0: return nil, errUnacceptableAmount case arg.ActionType != "purchase" && arg.ActionType != "redempt": - return nil, errors.New("invalid side value, side has to be either \"redemption\" or \"purchase\"") - case arg.ActionType == "purchase" && (arg.Rate < 1 || arg.Rate > 365): - return nil, errors.New("the rate value range is between 1% and 365%") + return nil, errors.New("invalid side value, side has to be either \"redempt\" or \"purchase\"") + case arg.ActionType == "purchase" && (arg.Rate < 0.01 || arg.Rate > 3.65): + return nil, errors.New("the rate value range is between 1% (0.01) and 365% (3.65)") } var resp []SavingsPurchaseRedemptionResponse - err := ok.SendHTTPRequest(ctx, exchange.RestSpot, savingsPurchaseRedemptionEPL, http.MethodPost, assetSavingPurchaseOrRedemptionPath, &arg, &resp, true) + err := ok.SendHTTPRequest(ctx, exchange.RestSpot, savingsPurchaseRedemptionEPL, http.MethodPost, financePurchaseRedempt, &arg, &resp, true) if err != nil { return nil, err } @@ -1687,18 +1690,18 @@ func (ok *Okx) GetLendingHistory(ctx context.Context, currency string, before, a params.Set("limit", strconv.FormatInt(limit, 10)) } var resp []LendingHistory - return resp, ok.SendHTTPRequest(ctx, exchange.RestSpot, setLendingRateEPL, http.MethodGet, common.EncodeURLValues(assetsLendingHistory, params), nil, &resp, true) + return resp, ok.SendHTTPRequest(ctx, exchange.RestSpot, getLendingHistoryEPL, http.MethodGet, common.EncodeURLValues(financeLendingHistory, params), nil, &resp, true) } -// SetLendingRate sets assets Lending Rate +// SetLendingRate sets an assets lending rate func (ok *Okx) SetLendingRate(ctx context.Context, arg LendingRate) (*LendingRate, error) { if arg.Currency == "" { return nil, errInvalidCurrencyValue - } else if arg.Rate < 1 || arg.Rate > 365 { - return nil, errors.New("invalid lending rate value. the rate value range is between 1% and 365%") + } else if arg.Rate < 0.01 || arg.Rate > 3.65 { + return nil, errors.New("invalid lending rate value. the rate value range is between 1% (0.01) and 365% (3.65)") } var resp []LendingRate - err := ok.SendHTTPRequest(ctx, exchange.RestSpot, getLendingHistoryEPL, http.MethodPost, assetSetLendingRateRoute, &arg, &resp, true) + err := ok.SendHTTPRequest(ctx, exchange.RestSpot, setLendingRateEPL, http.MethodPost, financeSetLendingRate, &arg, &resp, true) if err != nil { return nil, err } @@ -1708,14 +1711,33 @@ func (ok *Okx) SetLendingRate(ctx context.Context, arg LendingRate) (*LendingRat return nil, errNoValidResponseFromServer } -// GetPublicBorrowInfo return list of publix borrow history. +// GetPublicBorrowInfo returns the public borrow info. func (ok *Okx) GetPublicBorrowInfo(ctx context.Context, currency string) ([]PublicBorrowInfo, error) { params := url.Values{} if currency != "" { params.Set("ccy", currency) } var resp []PublicBorrowInfo - return resp, ok.SendHTTPRequest(ctx, exchange.RestSpot, getPublicBorrowInfoEPL, http.MethodGet, common.EncodeURLValues(publicBorrowInfo, params), nil, &resp, false) + return resp, ok.SendHTTPRequest(ctx, exchange.RestSpot, getPublicBorrowInfoEPL, http.MethodGet, common.EncodeURLValues(financePublicBorrowInfo, params), nil, &resp, false) +} + +// GetPublicBorrowHistory return list of publix borrow history. +func (ok *Okx) GetPublicBorrowHistory(ctx context.Context, currency string, before, after time.Time, limit int64) ([]PublicBorrowHistory, error) { + params := url.Values{} + if currency != "" { + params.Set("ccy", currency) + } + if !before.IsZero() { + params.Set("before", strconv.FormatInt(before.UnixMilli(), 10)) + } + if !after.IsZero() { + params.Set("after", strconv.FormatInt(after.UnixMilli(), 10)) + } + if limit > 0 { + params.Set("limit", strconv.FormatInt(limit, 10)) + } + var resp []PublicBorrowHistory + return resp, ok.SendHTTPRequest(ctx, exchange.RestSpot, getPublicBorrowHistoryEPL, http.MethodGet, common.EncodeURLValues(financePublicBorrowHistory, params), nil, &resp, false) } /***********************************Convert Endpoints | Authenticated s*****************************************/ @@ -2933,11 +2955,14 @@ func (ok *Okx) GetEarnActiveOrders(ctx context.Context, productID, protocolType, if productID != "" { params.Set("productId", productID) } - // protocol type 'staking' and 'defi' is allowed by default - if protocolType != "" && protocolType != "7D" && protocolType != "9D" && protocolType != "180D" { - return nil, errInvalidProtocolType + + if protocolType != "" { + // protocol type 'staking' and 'defi' is allowed by default + if protocolType != "staking" && protocolType != "defi" { + return nil, errInvalidProtocolType + } + params.Set("protocolType", protocolType) } - params.Set("protocolType", protocolType) if currency != "" { params.Set("ccy", currency) } diff --git a/exchanges/okx/okx_test.go b/exchanges/okx/okx_test.go index e5e93a34..15325657 100644 --- a/exchanges/okx/okx_test.go +++ b/exchanges/okx/okx_test.go @@ -1166,6 +1166,16 @@ func TestGetPublicBorrowInfo(t *testing.T) { if _, err := ok.GetPublicBorrowInfo(context.Background(), ""); err != nil { t.Error("Okx GetPublicBorrowInfo() error", err) } + if _, err := ok.GetPublicBorrowInfo(context.Background(), "USDT"); err != nil { + t.Error("Okx GetPublicBorrowInfo() error", err) + } +} + +func TestGetPublicBorrowHistory(t *testing.T) { + t.Parallel() + if _, err := ok.GetPublicBorrowHistory(context.Background(), "USDT", time.Time{}, time.Time{}, 1); err != nil { + t.Error("Okx GetPublicBorrowHistory() error", err) + } } func TestGetConvertCurrencies(t *testing.T) { diff --git a/exchanges/okx/okx_type_convert.go b/exchanges/okx/okx_type_convert.go index fb0c21c3..132339c6 100644 --- a/exchanges/okx/okx_type_convert.go +++ b/exchanges/okx/okx_type_convert.go @@ -15,22 +15,25 @@ type okxNumericalValue float64 // UnmarshalJSON is custom type json unmarshaller for okxNumericalValue func (a *okxNumericalValue) UnmarshalJSON(data []byte) error { - var num string + var num interface{} err := json.Unmarshal(data, &num) if err != nil { return err } - if num == "" { - return nil + switch d := num.(type) { + case float64: + *a = okxNumericalValue(d) + case string: + if d == "" { + return nil + } + convNum, err := strconv.ParseFloat(d, 64) + if err != nil { + return err + } + *a = okxNumericalValue(convNum) } - - v, err := strconv.ParseFloat(num, 64) - if err != nil { - return err - } - - *a = okxNumericalValue(v) return nil } diff --git a/exchanges/okx/okx_types.go b/exchanges/okx/okx_types.go index 7b6cca57..dc08b75f 100644 --- a/exchanges/okx/okx_types.go +++ b/exchanges/okx/okx_types.go @@ -1106,8 +1106,18 @@ type LendingHistory struct { Timestamp okxUnixMilliTime `json:"ts"` } -// PublicBorrowInfo holds borrow info. +// PublicBorrowInfo holds a currency's borrow info. type PublicBorrowInfo struct { + Currency string `json:"ccy"` + AverageAmount okxNumericalValue `json:"avgAmt"` + AverageAmountUSD okxNumericalValue `json:"avgAmtUsd"` + AverageRate okxNumericalValue `json:"avgRate"` + PreviousRate okxNumericalValue `json:"preRate"` + EstimatedRate okxNumericalValue `json:"estRate"` +} + +// PublicBorrowHistory holds a currencies borrow history. +type PublicBorrowHistory struct { Amount float64 `json:"amt,string"` Currency string `json:"ccy"` Rate float64 `json:"rate,string"` diff --git a/exchanges/okx/ratelimit.go b/exchanges/okx/ratelimit.go index 4acf942c..47e504ab 100644 --- a/exchanges/okx/ratelimit.go +++ b/exchanges/okx/ratelimit.go @@ -82,11 +82,13 @@ type RateLimit struct { CancelWithdrawal *rate.Limiter GetWithdrawalHistory *rate.Limiter SmallAssetsConvert *rate.Limiter - GetSavingBalance *rate.Limiter - SavingsPurchaseRedemp *rate.Limiter - SetLendingRate *rate.Limiter - GetLendingHistory *rate.Limiter - GetPublicBorrowInfo *rate.Limiter + // Savings + GetSavingBalance *rate.Limiter + SavingsPurchaseRedempt *rate.Limiter + SetLendingRate *rate.Limiter + GetLendingHistory *rate.Limiter + GetPublicBorrowInfo *rate.Limiter + GetPublicBorrowHistory *rate.Limiter // Convert GetConvertCurrencies *rate.Limiter GetConvertCurrencyPair *rate.Limiter @@ -255,11 +257,13 @@ const ( cancelWithdrawalRate = 6 getWithdrawalHistoryRate = 6 smallAssetsConvertRate = 1 - getSavingBalanceRate = 6 - savingsPurchaseRedemption = 6 - setLendingRateRate = 6 - getLendingHistoryRate = 6 - getPublicBorrowInfoRate = 6 + // Savings + getSavingBalanceRate = 6 + savingsPurchaseRedemptionRate = 6 + setLendingRateRate = 6 + getLendingHistoryRate = 6 + getPublicBorrowInfoRate = 6 + getPublicBorrowHistoryRate = 6 // Convert getConvertCurrenciesRate = 6 getConvertCurrencyPairRate = 6 @@ -430,6 +434,7 @@ const ( setLendingRateEPL getLendingHistoryEPL getPublicBorrowInfoEPL + getPublicBorrowHistoryEPL getConvertCurrenciesEPL getConvertCurrencyPairEPL estimateQuoteEPL @@ -644,13 +649,15 @@ func (r *RateLimit) Limit(ctx context.Context, f request.EndpointLimit) error { case getSavingBalanceEPL: return r.GetSavingBalance.Wait(ctx) case savingsPurchaseRedemptionEPL: - return r.SavingsPurchaseRedemp.Wait(ctx) + return r.SavingsPurchaseRedempt.Wait(ctx) case setLendingRateEPL: return r.SetLendingRate.Wait(ctx) case getLendingHistoryEPL: return r.GetLendingHistory.Wait(ctx) case getPublicBorrowInfoEPL: return r.GetPublicBorrowInfo.Wait(ctx) + case getPublicBorrowHistoryEPL: + return r.GetPublicBorrowHistory.Wait(ctx) case getConvertCurrenciesEPL: return r.GetConvertCurrencies.Wait(ctx) case getConvertCurrencyPairEPL: @@ -910,10 +917,11 @@ func SetRateLimit() *RateLimit { GetWithdrawalHistory: request.NewRateLimit(oneSecondInterval, getWithdrawalHistoryRate), SmallAssetsConvert: request.NewRateLimit(oneSecondInterval, smallAssetsConvertRate), GetSavingBalance: request.NewRateLimit(oneSecondInterval, getSavingBalanceRate), - SavingsPurchaseRedemp: request.NewRateLimit(oneSecondInterval, savingsPurchaseRedemption), + SavingsPurchaseRedempt: request.NewRateLimit(oneSecondInterval, savingsPurchaseRedemptionRate), SetLendingRate: request.NewRateLimit(oneSecondInterval, setLendingRateRate), GetLendingHistory: request.NewRateLimit(oneSecondInterval, getLendingHistoryRate), GetPublicBorrowInfo: request.NewRateLimit(oneSecondInterval, getPublicBorrowInfoRate), + GetPublicBorrowHistory: request.NewRateLimit(oneSecondInterval, getPublicBorrowHistoryRate), // Convert GetConvertCurrencies: request.NewRateLimit(oneSecondInterval, getConvertCurrenciesRate), GetConvertCurrencyPair: request.NewRateLimit(oneSecondInterval, getConvertCurrencyPairRate),