GateIO: Add GetEstimatedInterestRate REST endpoint (#2102)

* gateio: Add func GetEstimatedInterestRate (cherry-pickable)

* Add tests

* Update exchanges/gateio/gateio.go

Co-authored-by: Gareth Kirwan <gbjkirwan@gmail.com>

* Update exchanges/gateio/gateio.go

Co-authored-by: Gareth Kirwan <gbjkirwan@gmail.com>

* gk: nits

* thrasher-: nits

---------

Co-authored-by: Ryan O'Hara-Reid <ryan.oharareid@thrasher.io>
Co-authored-by: Gareth Kirwan <gbjkirwan@gmail.com>
This commit is contained in:
Ryan O'Hara-Reid
2025-11-11 15:47:37 +11:00
committed by GitHub
parent 497e13dc62
commit a70c834f04
6 changed files with 84 additions and 27 deletions

View File

@@ -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

View File

@@ -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")
}

View File

@@ -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

View File

@@ -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:

View File

@@ -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(),