exchange/order/limits: Migrate to new package and integrate with exchanges (#1860)

* move limits, transition to key gen

* rollout NewExchangePairAssetKey everywhere

* test improvements

* self-review fixes

* ok, lets go

* fix merge issue

* slower value func,assertify,drop IsValidPairString

* remove binance reference for backtesting test

* Redundant nil checks removed due to redundancy

* Update order_test.go

* Move limits back into /exchanges/

* puts limits in a different box again

* SHAZBERT SPECIAL SUGGESTIONS

* Update gateio_wrapper.go

* fixes all build issues

* Many niteroos!

* something has gone awry

* bugfix

* gk's everywhere nits

* lint

* extra lint

* re-remove IsValidPairString

* lint fix

* standardise test

* revert some bads

* dupe rm

* another revert 360 mcgee

* un-in-revertify

* Update exchange/order/limits/levels_test.go

Co-authored-by: Adrian Gallagher <adrian.gallagher@thrasher.io>

* fix

* Update exchanges/binance/binance_test.go

HERE'S HOPING GITHUB FORMATS THIS CORRECTLY!

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

* update text

* rn func, same line err gk4202000

---------

Co-authored-by: Adrian Gallagher <adrian.gallagher@thrasher.io>
Co-authored-by: Gareth Kirwan <gbjkirwan@gmail.com>
This commit is contained in:
Scott
2025-08-26 12:30:21 +10:00
committed by GitHub
parent fc0f262c42
commit 85403fe801
103 changed files with 1751 additions and 2168 deletions

View File

@@ -15,11 +15,12 @@ import (
"github.com/thrasher-corp/gocryptotrader/common"
"github.com/thrasher-corp/gocryptotrader/common/crypto"
"github.com/thrasher-corp/gocryptotrader/common/key"
"github.com/thrasher-corp/gocryptotrader/currency"
"github.com/thrasher-corp/gocryptotrader/encoding/json"
"github.com/thrasher-corp/gocryptotrader/exchange/order/limits"
exchange "github.com/thrasher-corp/gocryptotrader/exchanges"
"github.com/thrasher-corp/gocryptotrader/exchanges/asset"
"github.com/thrasher-corp/gocryptotrader/exchanges/order"
"github.com/thrasher-corp/gocryptotrader/exchanges/request"
)
@@ -1121,9 +1122,9 @@ func (e *Exchange) MaintainWsAuthStreamKey(ctx context.Context) error {
}
// FetchExchangeLimits fetches order execution limits filtered by asset
func (e *Exchange) FetchExchangeLimits(ctx context.Context, a asset.Item) ([]order.MinMaxLevel, error) {
func (e *Exchange) FetchExchangeLimits(ctx context.Context, a asset.Item) ([]limits.MinMaxLevel, error) {
if a != asset.Spot && a != asset.Margin {
return nil, fmt.Errorf("%w %v", asset.ErrNotSupported, a)
return nil, fmt.Errorf("%w %q", asset.ErrNotSupported, a)
}
resp, err := e.GetExchangeInfo(ctx)
@@ -1133,7 +1134,7 @@ func (e *Exchange) FetchExchangeLimits(ctx context.Context, a asset.Item) ([]ord
aUpper := strings.ToUpper(a.String())
limits := make([]order.MinMaxLevel, 0, len(resp.Symbols))
l := make([]limits.MinMaxLevel, 0, len(resp.Symbols))
for _, s := range resp.Symbols {
var cp currency.Pair
cp, err = currency.NewPairFromStrings(s.BaseAsset, s.QuoteAsset)
@@ -1145,44 +1146,43 @@ func (e *Exchange) FetchExchangeLimits(ctx context.Context, a asset.Item) ([]ord
if !slices.Contains(s.PermissionSets[i], aUpper) {
continue
}
l := order.MinMaxLevel{
Pair: cp,
Asset: a,
mml := limits.MinMaxLevel{
Key: key.NewExchangeAssetPair(e.Name, a, cp),
}
for _, f := range s.Filters {
// TODO: Unhandled filters:
// maxPosition, trailingDelta, percentPriceBySide, maxNumAlgoOrders
switch f.FilterType {
case priceFilter:
l.MinPrice = f.MinPrice
l.MaxPrice = f.MaxPrice
l.PriceStepIncrementSize = f.TickSize
mml.MinPrice = f.MinPrice
mml.MaxPrice = f.MaxPrice
mml.PriceStepIncrementSize = f.TickSize
case percentPriceFilter:
l.MultiplierUp = f.MultiplierUp
l.MultiplierDown = f.MultiplierDown
l.AveragePriceMinutes = f.AvgPriceMinutes
mml.MultiplierUp = f.MultiplierUp
mml.MultiplierDown = f.MultiplierDown
mml.AveragePriceMinutes = f.AvgPriceMinutes
case lotSizeFilter:
l.MaximumBaseAmount = f.MaxQty
l.MinimumBaseAmount = f.MinQty
l.AmountStepIncrementSize = f.StepSize
mml.MaximumBaseAmount = f.MaxQty
mml.MinimumBaseAmount = f.MinQty
mml.AmountStepIncrementSize = f.StepSize
case notionalFilter:
l.MinNotional = f.MinNotional
mml.MinNotional = f.MinNotional
case icebergPartsFilter:
l.MaxIcebergParts = f.Limit
mml.MaxIcebergParts = f.Limit
case marketLotSizeFilter:
l.MarketMinQty = f.MinQty
l.MarketMaxQty = f.MaxQty
l.MarketStepIncrementSize = f.StepSize
mml.MarketMinQty = f.MinQty
mml.MarketMaxQty = f.MaxQty
mml.MarketStepIncrementSize = f.StepSize
case maxNumOrdersFilter:
l.MaxTotalOrders = f.MaxNumOrders
l.MaxAlgoOrders = f.MaxNumAlgoOrders
mml.MaxTotalOrders = f.MaxNumOrders
mml.MaxAlgoOrders = f.MaxNumAlgoOrders
}
}
limits = append(limits, l)
l = append(l, mml)
break
}
}
return limits, nil
return l, nil
}
// CryptoLoanIncomeHistory returns crypto loan income history

View File

@@ -11,12 +11,13 @@ import (
"strings"
"time"
"github.com/thrasher-corp/gocryptotrader/common/key"
"github.com/thrasher-corp/gocryptotrader/currency"
"github.com/thrasher-corp/gocryptotrader/encoding/json"
"github.com/thrasher-corp/gocryptotrader/exchange/order/limits"
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/request"
)
@@ -1095,13 +1096,13 @@ func (e *Exchange) FuturesPositionsADLEstimate(ctx context.Context, symbol curre
}
// FetchCoinMarginExchangeLimits fetches coin margined order execution limits
func (e *Exchange) FetchCoinMarginExchangeLimits(ctx context.Context) ([]order.MinMaxLevel, error) {
func (e *Exchange) FetchCoinMarginExchangeLimits(ctx context.Context) ([]limits.MinMaxLevel, error) {
coinFutures, err := e.FuturesExchangeInfo(ctx)
if err != nil {
return nil, err
}
limits := make([]order.MinMaxLevel, 0, len(coinFutures.Symbols))
l := make([]limits.MinMaxLevel, 0, len(coinFutures.Symbols))
for x := range coinFutures.Symbols {
symbol := strings.Split(coinFutures.Symbols[x].Symbol, currency.UnderscoreDelimiter)
var cp currency.Pair
@@ -1114,9 +1115,8 @@ func (e *Exchange) FetchCoinMarginExchangeLimits(ctx context.Context) ([]order.M
continue
}
limits = append(limits, order.MinMaxLevel{
Pair: cp,
Asset: asset.CoinMarginedFutures,
l = append(l, limits.MinMaxLevel{
Key: key.NewExchangeAssetPair(e.Name, asset.CoinMarginedFutures, cp),
MinPrice: coinFutures.Symbols[x].Filters[0].MinPrice,
MaxPrice: coinFutures.Symbols[x].Filters[0].MaxPrice,
PriceStepIncrementSize: coinFutures.Symbols[x].Filters[0].TickSize,
@@ -1133,5 +1133,5 @@ func (e *Exchange) FetchCoinMarginExchangeLimits(ctx context.Context) ([]order.M
MultiplierDecimal: coinFutures.Symbols[x].Filters[5].MultiplierDecimal,
})
}
return limits, nil
return l, nil
}

View File

@@ -2509,48 +2509,6 @@ func TestUFuturesHistoricalTrades(t *testing.T) {
}
}
func TestSetExchangeOrderExecutionLimits(t *testing.T) {
t.Parallel()
err := e.UpdateOrderExecutionLimits(t.Context(), asset.Spot)
if err != nil {
t.Fatal(err)
}
err = e.UpdateOrderExecutionLimits(t.Context(), asset.CoinMarginedFutures)
if err != nil {
t.Fatal(err)
}
err = e.UpdateOrderExecutionLimits(t.Context(), asset.USDTMarginedFutures)
if err != nil {
t.Fatal(err)
}
err = e.UpdateOrderExecutionLimits(t.Context(), asset.Binary)
if err == nil {
t.Fatal("expected unhandled case")
}
cmfCP, err := currency.NewPairFromStrings("BTCUSD", "PERP")
if err != nil {
t.Fatal(err)
}
limit, err := e.GetOrderExecutionLimits(asset.CoinMarginedFutures, cmfCP)
if err != nil {
t.Fatal(err)
}
if limit == (order.MinMaxLevel{}) {
t.Fatal("exchange limit should be loaded")
}
err = limit.Conforms(0.000001, 0.1, order.Limit)
require.ErrorIs(t, err, order.ErrAmountBelowMin)
err = limit.Conforms(0.01, 1, order.Limit)
require.ErrorIs(t, err, order.ErrPriceBelowMin)
}
func TestWsOrderExecutionReport(t *testing.T) {
t.Parallel()
e := new(Exchange) //nolint:govet // Intentional shadow
@@ -2750,13 +2708,13 @@ func TestFormatUSDTMarginedFuturesPair(t *testing.T) {
func TestFetchExchangeLimits(t *testing.T) {
t.Parallel()
limits, err := e.FetchExchangeLimits(t.Context(), asset.Spot)
l, err := e.FetchExchangeLimits(t.Context(), asset.Spot)
assert.NoError(t, err, "FetchExchangeLimits should not error")
assert.NotEmpty(t, limits, "Should get some limits back")
assert.NotEmpty(t, l, "Should get some limits back")
limits, err = e.FetchExchangeLimits(t.Context(), asset.Margin)
l, err = e.FetchExchangeLimits(t.Context(), asset.Margin)
assert.NoError(t, err, "FetchExchangeLimits should not error")
assert.NotEmpty(t, limits, "Should get some limits back")
assert.NotEmpty(t, l, "Should get some limits back")
_, err = e.FetchExchangeLimits(t.Context(), asset.Futures)
assert.ErrorIs(t, err, asset.ErrNotSupported, "FetchExchangeLimits should error on other asset types")
@@ -2764,48 +2722,37 @@ func TestFetchExchangeLimits(t *testing.T) {
func TestUpdateOrderExecutionLimits(t *testing.T) {
t.Parallel()
spotEnabled, err := e.GetEnabledPairs(asset.Spot)
require.NoError(t, err, "GetEnabledPairs must not error")
tests := map[asset.Item]currency.Pair{
asset.Spot: spotEnabled[0],
asset.Margin: currency.NewPair(currency.ETH, currency.BTC),
}
for _, a := range []asset.Item{asset.CoinMarginedFutures, asset.USDTMarginedFutures} {
pairs, err := e.FetchTradablePairs(t.Context(), a)
require.NoErrorf(t, err, "FetchTradablePairs must not error for %s", a)
require.NotEmptyf(t, pairs, "Must get some pairs for %s", a)
tests[a] = pairs[0]
}
testexch.UpdatePairsOnce(t, e)
for _, a := range e.GetAssetTypes(false) {
err := e.UpdateOrderExecutionLimits(t.Context(), a)
require.NoError(t, err, "UpdateOrderExecutionLimits must not error")
p := tests[a]
limits, err := e.GetOrderExecutionLimits(a, p)
require.NoErrorf(t, err, "GetOrderExecutionLimits must not error for %s pair %s", a, p)
assert.Positivef(t, limits.MinPrice, "MinPrice should be positive for %s pair %s", a, p)
assert.Positivef(t, limits.MaxPrice, "MaxPrice should be positive for %s pair %s", a, p)
assert.Positivef(t, limits.PriceStepIncrementSize, "PriceStepIncrementSize should be positive for %s pair %s", a, p)
assert.Positivef(t, limits.MinimumBaseAmount, "MinimumBaseAmount should be positive for %s pair %s", a, p)
assert.Positivef(t, limits.MaximumBaseAmount, "MaximumBaseAmount should be positive for %s pair %s", a, p)
assert.Positivef(t, limits.AmountStepIncrementSize, "AmountStepIncrementSize should be positive for %s pair %s", a, p)
assert.Positivef(t, limits.MarketMaxQty, "MarketMaxQty should be positive for %s pair %s", a, p)
assert.Positivef(t, limits.MaxTotalOrders, "MaxTotalOrders should be positive for %s pair %s", a, p)
switch a {
case asset.Spot, asset.Margin:
assert.Positivef(t, limits.MaxIcebergParts, "MaxIcebergParts should be positive for %s pair %s", a, p)
case asset.USDTMarginedFutures:
assert.Positivef(t, limits.MinNotional, "MinNotional should be positive for %s pair %s", a, p)
fallthrough
case asset.CoinMarginedFutures:
assert.Positivef(t, limits.MultiplierUp, "MultiplierUp should be positive for %s pair %s", a, p)
assert.Positivef(t, limits.MultiplierDown, "MultiplierDown should be positive for %s pair %s", a, p)
assert.Positivef(t, limits.MarketMinQty, "MarketMinQty should be positive for %s pair %s", a, p)
assert.Positivef(t, limits.MarketStepIncrementSize, "MarketStepIncrementSize should be positive for %s pair %s", a, p)
assert.Positivef(t, limits.MaxAlgoOrders, "MaxAlgoOrders should be positive for %s pair %s", a, p)
}
t.Run(a.String(), func(t *testing.T) {
t.Parallel()
require.NoError(t, e.UpdateOrderExecutionLimits(t.Context(), a), "UpdateOrderExecutionLimits must not error")
pairs, err := e.CurrencyPairs.GetPairs(a, false)
require.NoError(t, err, "GetPairs must not error")
l, err := e.GetOrderExecutionLimits(a, pairs[0])
require.NoError(t, err, "GetOrderExecutionLimits must not error")
assert.Positive(t, l.MinPrice, "MinPrice should be positive")
assert.Positive(t, l.MaxPrice, "MaxPrice should be positive")
assert.Positive(t, l.PriceStepIncrementSize, "PriceStepIncrementSize should be positive")
assert.Positive(t, l.MinimumBaseAmount, "MinimumBaseAmount should be positive")
assert.Positive(t, l.MaximumBaseAmount, "MaximumBaseAmount should be positive")
assert.Positive(t, l.AmountStepIncrementSize, "AmountStepIncrementSize should be positive")
assert.Positive(t, l.MarketMaxQty, "MarketMaxQty should be positive")
assert.Positive(t, l.MaxTotalOrders, "MaxTotalOrders should be positive")
switch a {
case asset.Spot, asset.Margin:
assert.Positive(t, l.MaxIcebergParts, "MaxIcebergParts should be positive")
case asset.USDTMarginedFutures:
assert.Positive(t, l.MinNotional, "MinNotional should be positive")
fallthrough
case asset.CoinMarginedFutures:
assert.Positive(t, l.MultiplierUp, "MultiplierUp should be positive")
assert.Positive(t, l.MultiplierDown, "MultiplierDown should be positive")
assert.Positive(t, l.MarketMinQty, "MarketMinQty should be positive")
assert.Positive(t, l.MarketStepIncrementSize, "MarketStepIncrementSize should be positive")
assert.Positive(t, l.MaxAlgoOrders, "MaxAlgoOrders should be positive")
}
})
}
}

View File

@@ -10,12 +10,13 @@ import (
"strconv"
"time"
"github.com/thrasher-corp/gocryptotrader/common/key"
"github.com/thrasher-corp/gocryptotrader/currency"
"github.com/thrasher-corp/gocryptotrader/encoding/json"
"github.com/thrasher-corp/gocryptotrader/exchange/order/limits"
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/types"
)
@@ -1002,13 +1003,12 @@ func (e *Exchange) GetPerpMarkets(ctx context.Context) (PerpsExchangeInfo, error
}
// FetchUSDTMarginExchangeLimits fetches USDT margined order execution limits
func (e *Exchange) FetchUSDTMarginExchangeLimits(ctx context.Context) ([]order.MinMaxLevel, error) {
func (e *Exchange) FetchUSDTMarginExchangeLimits(ctx context.Context) ([]limits.MinMaxLevel, error) {
usdtFutures, err := e.UExchangeInfo(ctx)
if err != nil {
return nil, err
}
limits := make([]order.MinMaxLevel, 0, len(usdtFutures.Symbols))
l := make([]limits.MinMaxLevel, 0, len(usdtFutures.Symbols))
for x := range usdtFutures.Symbols {
var cp currency.Pair
cp, err = currency.NewPairFromStrings(usdtFutures.Symbols[x].BaseAsset,
@@ -1021,9 +1021,8 @@ func (e *Exchange) FetchUSDTMarginExchangeLimits(ctx context.Context) ([]order.M
continue
}
limits = append(limits, order.MinMaxLevel{
Pair: cp,
Asset: asset.USDTMarginedFutures,
l = append(l, limits.MinMaxLevel{
Key: key.NewExchangeAssetPair(e.Name, asset.USDTMarginedFutures, cp),
MinPrice: usdtFutures.Symbols[x].Filters[0].MinPrice,
MaxPrice: usdtFutures.Symbols[x].Filters[0].MaxPrice,
PriceStepIncrementSize: usdtFutures.Symbols[x].Filters[0].TickSize,
@@ -1041,7 +1040,7 @@ func (e *Exchange) FetchUSDTMarginExchangeLimits(ctx context.Context) ([]order.M
MultiplierDecimal: usdtFutures.Symbols[x].Filters[6].MultiplierDecimal,
})
}
return limits, nil
return l, nil
}
// SetAssetsMode sets the current asset margin type, true for multi, false for single

View File

@@ -14,6 +14,7 @@ import (
"github.com/thrasher-corp/gocryptotrader/common/key"
"github.com/thrasher-corp/gocryptotrader/config"
"github.com/thrasher-corp/gocryptotrader/currency"
"github.com/thrasher-corp/gocryptotrader/exchange/order/limits"
"github.com/thrasher-corp/gocryptotrader/exchange/websocket"
"github.com/thrasher-corp/gocryptotrader/exchange/websocket/buffer"
exchange "github.com/thrasher-corp/gocryptotrader/exchanges"
@@ -246,7 +247,7 @@ func (e *Exchange) Setup(exch *config.Exchange) error {
// FetchTradablePairs returns a list of the exchanges tradable pairs
func (e *Exchange) FetchTradablePairs(ctx context.Context, a asset.Item) (currency.Pairs, error) {
if !e.SupportsAsset(a) {
return nil, fmt.Errorf("%w %v", asset.ErrNotSupported, a)
return nil, fmt.Errorf("%w %q", asset.ErrNotSupported, a)
}
tradingStatus := "TRADING"
var pairs []currency.Pair
@@ -432,7 +433,7 @@ func (e *Exchange) UpdateTickers(ctx context.Context, a asset.Item) error {
}
}
default:
return fmt.Errorf("%w %v", asset.ErrNotSupported, a)
return fmt.Errorf("%w %q", asset.ErrNotSupported, a)
}
return nil
}
@@ -507,7 +508,7 @@ func (e *Exchange) UpdateTicker(ctx context.Context, p currency.Pair, a asset.It
}
default:
return nil, fmt.Errorf("%w %v", asset.ErrNotSupported, a)
return nil, fmt.Errorf("%w %q", asset.ErrNotSupported, a)
}
return ticker.GetTicker(e.Name, p, a)
}
@@ -808,7 +809,7 @@ func (e *Exchange) GetHistoricTrades(ctx context.Context, p currency.Pair, a ass
return nil, err
}
if a != asset.Spot {
return nil, fmt.Errorf("%w %v", asset.ErrNotSupported, a)
return nil, fmt.Errorf("%w %q", asset.ErrNotSupported, a)
}
rFmt, err := e.GetPairFormat(a, true)
if err != nil {
@@ -1704,7 +1705,7 @@ func (e *Exchange) GetHistoricCandles(ctx context.Context, pair currency.Pair, a
})
}
default:
return nil, fmt.Errorf("%w %v", asset.ErrNotSupported, a)
return nil, fmt.Errorf("%w %q", asset.ErrNotSupported, a)
}
return req.ProcessResponse(timeSeries)
}
@@ -1785,7 +1786,7 @@ func (e *Exchange) GetHistoricCandlesExtended(ctx context.Context, pair currency
})
}
default:
return nil, fmt.Errorf("%w %v", asset.ErrNotSupported, a)
return nil, fmt.Errorf("%w %q", asset.ErrNotSupported, a)
}
}
return req.ProcessResponse(timeSeries)
@@ -1836,24 +1837,24 @@ func compatibleOrderVars(side, status, orderType string) OrderVars {
// UpdateOrderExecutionLimits sets exchange executions for a required asset type
func (e *Exchange) UpdateOrderExecutionLimits(ctx context.Context, a asset.Item) error {
var limits []order.MinMaxLevel
var l []limits.MinMaxLevel
var err error
switch a {
case asset.Spot:
limits, err = e.FetchExchangeLimits(ctx, asset.Spot)
l, err = e.FetchExchangeLimits(ctx, asset.Spot)
case asset.USDTMarginedFutures:
limits, err = e.FetchUSDTMarginExchangeLimits(ctx)
l, err = e.FetchUSDTMarginExchangeLimits(ctx)
case asset.CoinMarginedFutures:
limits, err = e.FetchCoinMarginExchangeLimits(ctx)
l, err = e.FetchCoinMarginExchangeLimits(ctx)
case asset.Margin:
limits, err = e.FetchExchangeLimits(ctx, asset.Margin)
l, err = e.FetchExchangeLimits(ctx, asset.Margin)
default:
err = fmt.Errorf("%w %v", asset.ErrNotSupported, a)
err = fmt.Errorf("%w %q", asset.ErrNotSupported, a)
}
if err != nil {
return fmt.Errorf("cannot update exchange execution limits: %w", err)
}
return e.LoadLimits(limits)
return limits.Load(l)
}
// GetAvailableTransferChains returns the available transfer blockchains for the specific cryptocurrency
@@ -2252,7 +2253,7 @@ func (e *Exchange) IsPerpetualFutureCurrency(a asset.Item, cp currency.Pair) (bo
// SetCollateralMode sets the account's collateral mode for the asset type
func (e *Exchange) SetCollateralMode(ctx context.Context, a asset.Item, collateralMode collateral.Mode) error {
if a != asset.USDTMarginedFutures {
return fmt.Errorf("%w %v", asset.ErrNotSupported, a)
return fmt.Errorf("%w %q", asset.ErrNotSupported, a)
}
if collateralMode != collateral.MultiMode && collateralMode != collateral.SingleMode {
return fmt.Errorf("%w %v", order.ErrCollateralInvalid, collateralMode)
@@ -2263,7 +2264,7 @@ func (e *Exchange) SetCollateralMode(ctx context.Context, a asset.Item, collater
// GetCollateralMode returns the account's collateral mode for the asset type
func (e *Exchange) GetCollateralMode(ctx context.Context, a asset.Item) (collateral.Mode, error) {
if a != asset.USDTMarginedFutures {
return collateral.UnknownMode, fmt.Errorf("%w %v", asset.ErrNotSupported, a)
return collateral.UnknownMode, fmt.Errorf("%w %q", asset.ErrNotSupported, a)
}
isMulti, err := e.GetAssetsMode(ctx)
if err != nil {
@@ -2983,12 +2984,7 @@ func (e *Exchange) GetOpenInterest(ctx context.Context, k ...key.PairAsset) ([]f
return nil, err
}
result[i] = futures.OpenInterest{
Key: key.ExchangePairAsset{
Exchange: e.Name,
Base: k[i].Base,
Quote: k[i].Quote,
Asset: k[i].Asset,
},
Key: key.NewExchangeAssetPair(e.Name, k[i].Asset, k[i].Pair()),
OpenInterest: oi.OpenInterest,
}
case asset.CoinMarginedFutures:
@@ -2997,12 +2993,7 @@ func (e *Exchange) GetOpenInterest(ctx context.Context, k ...key.PairAsset) ([]f
return nil, err
}
result[i] = futures.OpenInterest{
Key: key.ExchangePairAsset{
Exchange: e.Name,
Base: k[i].Base,
Quote: k[i].Quote,
Asset: k[i].Asset,
},
Key: key.NewExchangeAssetPair(e.Name, k[i].Asset, k[i].Pair()),
OpenInterest: oi.OpenInterest,
}
}
@@ -3070,6 +3061,6 @@ func (e *Exchange) GetCurrencyTradeURL(ctx context.Context, a asset.Item, cp cur
case asset.Margin:
return tradeBaseURL + "trade/" + symbol + "?type=cross", nil
default:
return "", fmt.Errorf("%w %v", asset.ErrNotSupported, a)
return "", fmt.Errorf("%w %q", asset.ErrNotSupported, a)
}
}