diff --git a/currency/code.go b/currency/code.go index f7b6489a..b24d22d4 100644 --- a/currency/code.go +++ b/currency/code.go @@ -9,27 +9,29 @@ import ( "github.com/thrasher-corp/gocryptotrader/encoding/json" ) +// Public errors var ( - // ErrCurrencyCodeEmpty defines an error if the currency code is empty - ErrCurrencyCodeEmpty = errors.New("currency code is empty") - // ErrCurrencyNotFound returned when a currency is not found in a list - ErrCurrencyNotFound = errors.New("currency code not found in list") - // ErrCurrencyPairEmpty defines an error if the currency pair is empty - ErrCurrencyPairEmpty = errors.New("currency pair is empty") - // ErrCurrencyNotSupported defines an error if the currency pair is not supported + ErrCurrencyCodeEmpty = errors.New("currency code is empty") + ErrCurrencyNotFound = errors.New("currency code not found in list") + ErrCurrencyPairEmpty = errors.New("currency pair is empty") ErrCurrencyNotSupported = errors.New("currency not supported") - // ErrCurrencyPairsEmpty returns when a currency.Pairs has len == 0 - ErrCurrencyPairsEmpty = errors.New("currency pairs is empty") - // EMPTYCODE is an empty currency code - EMPTYCODE = Code{} - // EMPTYPAIR is an empty currency pair - EMPTYPAIR = Pair{} + ErrCurrencyPairsEmpty = errors.New("currency pairs is empty") + ErrCurrencyCodesEmpty = errors.New("currency codes is empty") +) +var ( errItemIsNil = errors.New("item is nil") errItemIsEmpty = errors.New("item is empty") errRoleUnset = errors.New("role unset") ) +var ( + // EMPTYCODE is an empty currency code + EMPTYCODE Code + // EMPTYPAIR is an empty currency pair + EMPTYPAIR Pair +) + // String implements the stringer interface and returns a string representation // of the underlying role. func (r Role) String() string { diff --git a/exchanges/gateio/gateio.go b/exchanges/gateio/gateio.go index d9b2fe05..0f2e3ffd 100644 --- a/exchanges/gateio/gateio.go +++ b/exchanges/gateio/gateio.go @@ -166,6 +166,7 @@ var ( errMissingAPIKey = errors.New("missing API key information") errInvalidTextPrefix = errors.New("invalid text value, requires prefix `t-`") errSingleAssetRequired = errors.New("single asset type required") + errTooManyCurrencyCodes = errors.New("too many currency codes supplied") ) // validTimesInForce holds a list of supported time-in-force values and corresponding string representations. @@ -1323,6 +1324,31 @@ func (e *Exchange) ConvertSmallBalances(ctx context.Context, currs ...currency.C // ********************************* Margin ******************************************* +// GetEstimatedInterestRate retrieves estimated interest rate for provided currencies +func (e *Exchange) GetEstimatedInterestRate(ctx context.Context, currencies []currency.Code) (map[string]types.Number, error) { + if len(currencies) == 0 { + return nil, currency.ErrCurrencyCodesEmpty + } + if len(currencies) > 10 { + return nil, fmt.Errorf("%w: maximum 10", errTooManyCurrencyCodes) + } + var currStr strings.Builder + for i := range currencies { + if currencies[i].IsEmpty() { + return nil, currency.ErrCurrencyCodeEmpty + } + if i != 0 { + currStr.WriteString(",") + } + currStr.WriteString(currencies[i].String()) + } + params := url.Values{} + params.Set("currencies", currStr.String()) + + var response map[string]types.Number + return response, e.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, marginEstimateRateEPL, http.MethodGet, "margin/uni/estimate_rate", params, nil, &response) +} + // GetMarginSupportedCurrencyPairs retrieves margin supported currency pairs. func (e *Exchange) GetMarginSupportedCurrencyPairs(ctx context.Context) ([]MarginCurrencyPairInfo, error) { var currenciePairsInfo []MarginCurrencyPairInfo diff --git a/exchanges/gateio/gateio_test.go b/exchanges/gateio/gateio_test.go index 231e76ad..e41e5864 100644 --- a/exchanges/gateio/gateio_test.go +++ b/exchanges/gateio/gateio_test.go @@ -3707,3 +3707,35 @@ func TestUnmarshalJSONOrderbookLevels(t *testing.T) { require.Error(t, ob.UnmarshalJSON([]byte(`["p":"123.45","s":"0.001"]`))) } + +func TestGetEstimatedInterestRate(t *testing.T) { + t.Parallel() + + _, err := e.GetEstimatedInterestRate(t.Context(), nil) + require.ErrorIs(t, err, currency.ErrCurrencyCodesEmpty) + + _, err = e.GetEstimatedInterestRate(t.Context(), currency.Currencies{currency.EMPTYCODE}) + require.ErrorIs(t, err, currency.ErrCurrencyCodeEmpty) + + _, err = e.GetEstimatedInterestRate(t.Context(), currency.Currencies{ + currency.USDT, + currency.BTC, + currency.ETH, + currency.XRP, + currency.LTC, + currency.DOGE, + currency.BCH, + currency.SOL, + currency.ADA, + currency.DOT, + currency.MATIC, + }) + require.ErrorIs(t, err, errTooManyCurrencyCodes) + + sharedtestvalues.SkipTestIfCredentialsUnset(t, e) + got, err := e.GetEstimatedInterestRate(t.Context(), currency.Currencies{currency.BTC}) + require.NoError(t, err) + val, ok := got["BTC"] + require.True(t, ok, "result map must contain BTC key") + require.Positive(t, val.Float64(), "estimated interest rate must not be 0") +} diff --git a/exchanges/gateio/gateio_types.go b/exchanges/gateio/gateio_types.go index 693b84e4..f14d46a8 100644 --- a/exchanges/gateio/gateio_types.go +++ b/exchanges/gateio/gateio_types.go @@ -630,14 +630,14 @@ type CurrencyChain struct { // MarginCurrencyPairInfo represents margin currency pair detailed info. type MarginCurrencyPairInfo struct { - ID string `json:"id"` - Base string `json:"base"` - Quote string `json:"quote"` - Leverage float64 `json:"leverage"` - MinBaseAmount types.Number `json:"min_base_amount"` - MinQuoteAmount types.Number `json:"min_quote_amount"` - MaxQuoteAmount types.Number `json:"max_quote_amount"` - Status int32 `json:"status"` + ID currency.Pair `json:"id"` + Base currency.Code `json:"base"` + Quote currency.Code `json:"quote"` + Leverage float64 `json:"leverage"` + MinBaseAmount types.Number `json:"min_base_amount"` + MinQuoteAmount types.Number `json:"min_quote_amount"` + MaxQuoteAmount types.Number `json:"max_quote_amount"` + Status int32 `json:"status"` } // OrderbookOfLendingLoan represents order book of lending loans diff --git a/exchanges/gateio/gateio_wrapper.go b/exchanges/gateio/gateio_wrapper.go index e8cff02e..75155746 100644 --- a/exchanges/gateio/gateio_wrapper.go +++ b/exchanges/gateio/gateio_wrapper.go @@ -432,12 +432,7 @@ func (e *Exchange) FetchTradablePairs(ctx context.Context, a asset.Item) (curren if tradables[x].Status == 0 { continue } - p := strings.ToUpper(tradables[x].Base + currency.UnderscoreDelimiter + tradables[x].Quote) - cp, err := currency.NewPairFromString(p) - if err != nil { - return nil, err - } - pairs = append(pairs, cp) + pairs = append(pairs, tradables[x].ID) } return pairs, nil case asset.CoinMarginedFutures, asset.USDTMarginedFutures: diff --git a/exchanges/gateio/ratelimiter.go b/exchanges/gateio/ratelimiter.go index 5e77b2d8..030ab987 100644 --- a/exchanges/gateio/ratelimiter.go +++ b/exchanges/gateio/ratelimiter.go @@ -123,6 +123,7 @@ const ( marginGetMaxBorrowCrossEPL marginGetCrossBorrowHistoryEPL marginGetBorrowEPL + marginEstimateRateEPL flashSwapOrderEPL flashGetOrdersEPL @@ -312,6 +313,7 @@ var packageRateLimits = request.RateLimitDefinitions{ marginGetMaxBorrowCrossEPL: otherPrivateEndpointRateLimit(), marginGetCrossBorrowHistoryEPL: otherPrivateEndpointRateLimit(), marginGetBorrowEPL: otherPrivateEndpointRateLimit(), + marginEstimateRateEPL: otherPrivateEndpointRateLimit(), flashSwapOrderEPL: otherPrivateEndpointRateLimit(), flashGetOrdersEPL: otherPrivateEndpointRateLimit(),