mirror of
https://github.com/d0zingcat/gocryptotrader.git
synced 2026-05-14 07:26:47 +00:00
Binance: Fix exchange order limits not populating (#1187)
* Binance: Fix Exchange Order Limits not populating The order of the filters cannot be trusted. New filters have been added after the 2nd filter, breaking all filter passing afterwards. This adds a basic test that the data is being populated, but more could be done on testing. We should have stricter typing on the filters, perhaps by unmarshalling into json.RawMessage initially and then into typed stuct fields based on the filterType. Finally we should spot both missing and unhandled filters, at least in tests. * Binance: Add TODO for unhandled filterTypes
This commit is contained in:
@@ -1196,30 +1196,42 @@ func (b *Binance) FetchSpotExchangeLimits(ctx context.Context) ([]order.MinMaxLe
|
||||
}
|
||||
|
||||
for z := range assets {
|
||||
if len(spot.Symbols[x].Filters) < 8 {
|
||||
continue
|
||||
l := order.MinMaxLevel{
|
||||
Pair: cp,
|
||||
Asset: assets[z],
|
||||
}
|
||||
|
||||
limits = append(limits, order.MinMaxLevel{
|
||||
Pair: cp,
|
||||
Asset: assets[z],
|
||||
MinPrice: spot.Symbols[x].Filters[0].MinPrice,
|
||||
MaxPrice: spot.Symbols[x].Filters[0].MaxPrice,
|
||||
PriceStepIncrementSize: spot.Symbols[x].Filters[0].TickSize,
|
||||
MultiplierUp: spot.Symbols[x].Filters[1].MultiplierUp,
|
||||
MultiplierDown: spot.Symbols[x].Filters[1].MultiplierDown,
|
||||
AveragePriceMinutes: spot.Symbols[x].Filters[1].AvgPriceMinutes,
|
||||
MaxAmount: spot.Symbols[x].Filters[2].MaxQty,
|
||||
MinAmount: spot.Symbols[x].Filters[2].MinQty,
|
||||
AmountStepIncrementSize: spot.Symbols[x].Filters[2].StepSize,
|
||||
MinNotional: spot.Symbols[x].Filters[3].MinNotional,
|
||||
MaxIcebergParts: spot.Symbols[x].Filters[4].Limit,
|
||||
MarketMinQty: spot.Symbols[x].Filters[5].MinQty,
|
||||
MarketMaxQty: spot.Symbols[x].Filters[5].MaxQty,
|
||||
MarketStepIncrementSize: spot.Symbols[x].Filters[5].StepSize,
|
||||
MaxTotalOrders: spot.Symbols[x].Filters[6].MaxNumOrders,
|
||||
MaxAlgoOrders: spot.Symbols[x].Filters[7].MaxNumAlgoOrders,
|
||||
})
|
||||
for _, f := range spot.Symbols[x].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
|
||||
case percentPriceFilter:
|
||||
l.MultiplierUp = f.MultiplierUp
|
||||
l.MultiplierDown = f.MultiplierDown
|
||||
l.AveragePriceMinutes = f.AvgPriceMinutes
|
||||
case lotSizeFilter:
|
||||
l.MaxAmount = f.MaxQty
|
||||
l.MinAmount = f.MinQty
|
||||
l.AmountStepIncrementSize = f.StepSize
|
||||
case notionalFilter:
|
||||
l.MinNotional = f.MinNotional
|
||||
case icebergPartsFilter:
|
||||
l.MaxIcebergParts = f.Limit
|
||||
case marketLotSizeFilter:
|
||||
l.MarketMinQty = f.MinQty
|
||||
l.MarketMaxQty = f.MaxQty
|
||||
l.MarketStepIncrementSize = f.StepSize
|
||||
case maxNumOrdersFilter:
|
||||
l.MaxTotalOrders = f.MaxNumOrders
|
||||
l.MaxAlgoOrders = f.MaxNumAlgoOrders
|
||||
}
|
||||
}
|
||||
|
||||
limits = append(limits, l)
|
||||
}
|
||||
}
|
||||
return limits, nil
|
||||
|
||||
@@ -2734,3 +2734,84 @@ func TestFetchSpotExchangeLimits(t *testing.T) {
|
||||
t.Error("expected a response")
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpdateOrderExecutionLimits(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tests := map[asset.Item]currency.Pair{
|
||||
asset.Spot: currency.NewPair(currency.BTC, currency.USDT),
|
||||
asset.Margin: currency.NewPair(currency.ETH, currency.BTC),
|
||||
}
|
||||
for _, a := range []asset.Item{asset.CoinMarginedFutures, asset.USDTMarginedFutures} {
|
||||
pairs, err := b.FetchTradablePairs(context.Background(), a)
|
||||
if err != nil {
|
||||
t.Errorf("Error fetching dated %s pairs for test: %v", a, err)
|
||||
}
|
||||
tests[a] = pairs[0]
|
||||
}
|
||||
|
||||
for _, a := range b.GetAssetTypes(false) {
|
||||
if err := b.UpdateOrderExecutionLimits(context.Background(), a); err != nil {
|
||||
t.Error("Binance UpdateOrderExecutionLimits() error", err)
|
||||
continue
|
||||
}
|
||||
|
||||
p := tests[a]
|
||||
limits, err := b.GetOrderExecutionLimits(a, p)
|
||||
if err != nil {
|
||||
t.Errorf("Binance GetOrderExecutionLimits() error during TestUpdateOrderExecutionLimits; Asset: %s Pair: %s Err: %v", a, p, err)
|
||||
continue
|
||||
}
|
||||
if limits.MinPrice == 0 {
|
||||
t.Errorf("Binance UpdateOrderExecutionLimits empty MinPrice; Asset: %s, Pair: %s, Got: %v", a, p, limits.MinPrice)
|
||||
}
|
||||
if limits.MaxPrice == 0 {
|
||||
t.Errorf("Binance UpdateOrderExecutionLimits empty MaxPrice; Asset: %s, Pair: %s, Got: %v", a, p, limits.MaxPrice)
|
||||
}
|
||||
if limits.PriceStepIncrementSize == 0 {
|
||||
t.Errorf("Binance UpdateOrderExecutionLimits empty PriceStepIncrementSize; Asset: %s, Pair: %s, Got: %v", a, p, limits.PriceStepIncrementSize)
|
||||
}
|
||||
if limits.MinAmount == 0 {
|
||||
t.Errorf("Binance UpdateOrderExecutionLimits empty MinAmount; Asset: %s, Pair: %s, Got: %v", a, p, limits.MinAmount)
|
||||
}
|
||||
if limits.MaxAmount == 0 {
|
||||
t.Errorf("Binance UpdateOrderExecutionLimits empty MaxAmount; Asset: %s, Pair: %s, Got: %v", a, p, limits.MaxAmount)
|
||||
}
|
||||
if limits.AmountStepIncrementSize == 0 {
|
||||
t.Errorf("Binance UpdateOrderExecutionLimits empty AmountStepIncrementSize; Asset: %s, Pair: %s, Got: %v", a, p, limits.AmountStepIncrementSize)
|
||||
}
|
||||
if a == asset.USDTMarginedFutures && limits.MinNotional == 0 {
|
||||
t.Errorf("Binance UpdateOrderExecutionLimits empty MinNotional; Asset: %s, Pair: %s, Got: %v", a, p, limits.MinNotional)
|
||||
}
|
||||
if limits.MarketMaxQty == 0 {
|
||||
t.Errorf("Binance UpdateOrderExecutionLimits empty MarketMaxQty; Asset: %s, Pair: %s, Got: %v", a, p, limits.MarketMaxQty)
|
||||
}
|
||||
if limits.MaxTotalOrders == 0 {
|
||||
t.Errorf("Binance UpdateOrderExecutionLimits empty MaxTotalOrders; Asset: %s, Pair: %s, Got: %v", a, p, limits.MaxTotalOrders)
|
||||
}
|
||||
|
||||
if a == asset.Spot || a == asset.Margin {
|
||||
if limits.MaxIcebergParts == 0 {
|
||||
t.Errorf("Binance UpdateOrderExecutionLimits empty MaxIcebergParts; Asset: %s, Pair: %s, Got: %v", a, p, limits.MaxIcebergParts)
|
||||
}
|
||||
}
|
||||
|
||||
if a == asset.CoinMarginedFutures || a == asset.USDTMarginedFutures {
|
||||
if limits.MultiplierUp == 0 {
|
||||
t.Errorf("Binance UpdateOrderExecutionLimits empty MultiplierUp; Asset: %s, Pair: %s, Got: %v", a, p, limits.MultiplierUp)
|
||||
}
|
||||
if limits.MultiplierDown == 0 {
|
||||
t.Errorf("Binance UpdateOrderExecutionLimits empty MultiplierDown; Asset: %s, Pair: %s, Got: %v", a, p, limits.MultiplierDown)
|
||||
}
|
||||
if limits.MarketMinQty == 0 {
|
||||
t.Errorf("Binance UpdateOrderExecutionLimits empty MarketMinQty; Asset: %s, Pair: %s, Got: %v", a, p, limits.MarketMinQty)
|
||||
}
|
||||
if limits.MarketStepIncrementSize == 0 {
|
||||
t.Errorf("Binance UpdateOrderExecutionLimits empty MarketStepIncrementSize; Asset: %s, Pair: %s, Got: %v", a, p, limits.MarketStepIncrementSize)
|
||||
}
|
||||
if limits.MaxAlgoOrders == 0 {
|
||||
t.Errorf("Binance UpdateOrderExecutionLimits empty MaxAlgoOrders; Asset: %s, Pair: %s, Got: %v", a, p, limits.MaxAlgoOrders)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,21 @@ const (
|
||||
Completed
|
||||
)
|
||||
|
||||
type filterType string
|
||||
|
||||
const (
|
||||
priceFilter filterType = "PRICE_FILTER"
|
||||
lotSizeFilter filterType = "LOT_SIZE"
|
||||
icebergPartsFilter filterType = "ICEBERG_PARTS"
|
||||
marketLotSizeFilter filterType = "MARKET_LOT_SIZE"
|
||||
trailingDeltaFilter filterType = "TRAILING_DELTA"
|
||||
percentPriceFilter filterType = "PERCENT_PRICE"
|
||||
percentPriceBySizeFilter filterType = "PERCENT_PRICE_BY_SIDE"
|
||||
notionalFilter filterType = "NOTIONAL"
|
||||
maxNumOrdersFilter filterType = "MAX_NUM_ORDERS"
|
||||
maxNumAlgoOrdersFilter filterType = "MAX_NUM_ALGO_ORDERS"
|
||||
)
|
||||
|
||||
// ExchangeInfo holds the full exchange information type
|
||||
type ExchangeInfo struct {
|
||||
Code int `json:"code"`
|
||||
@@ -35,40 +50,42 @@ type ExchangeInfo struct {
|
||||
} `json:"rateLimits"`
|
||||
ExchangeFilters interface{} `json:"exchangeFilters"`
|
||||
Symbols []struct {
|
||||
Symbol string `json:"symbol"`
|
||||
Status string `json:"status"`
|
||||
BaseAsset string `json:"baseAsset"`
|
||||
BaseAssetPrecision int `json:"baseAssetPrecision"`
|
||||
QuoteAsset string `json:"quoteAsset"`
|
||||
QuotePrecision int `json:"quotePrecision"`
|
||||
OrderTypes []string `json:"orderTypes"`
|
||||
IcebergAllowed bool `json:"icebergAllowed"`
|
||||
OCOAllowed bool `json:"ocoAllowed"`
|
||||
QuoteOrderQtyMarketAllowed bool `json:"quoteOrderQtyMarketAllowed"`
|
||||
IsSpotTradingAllowed bool `json:"isSpotTradingAllowed"`
|
||||
IsMarginTradingAllowed bool `json:"isMarginTradingAllowed"`
|
||||
Filters []struct {
|
||||
FilterType string `json:"filterType"`
|
||||
MinPrice float64 `json:"minPrice,string"`
|
||||
MaxPrice float64 `json:"maxPrice,string"`
|
||||
TickSize float64 `json:"tickSize,string"`
|
||||
MultiplierUp float64 `json:"multiplierUp,string"`
|
||||
MultiplierDown float64 `json:"multiplierDown,string"`
|
||||
AvgPriceMinutes int64 `json:"avgPriceMins"`
|
||||
MinQty float64 `json:"minQty,string"`
|
||||
MaxQty float64 `json:"maxQty,string"`
|
||||
StepSize float64 `json:"stepSize,string"`
|
||||
MinNotional float64 `json:"minNotional,string"`
|
||||
ApplyToMarket bool `json:"applyToMarket"`
|
||||
Limit int64 `json:"limit"`
|
||||
MaxNumAlgoOrders int64 `json:"maxNumAlgoOrders"`
|
||||
MaxNumIcebergOrders int64 `json:"maxNumIcebergOrders"`
|
||||
MaxNumOrders int64 `json:"maxNumOrders"`
|
||||
} `json:"filters"`
|
||||
Permissions []string `json:"permissions"`
|
||||
Symbol string `json:"symbol"`
|
||||
Status string `json:"status"`
|
||||
BaseAsset string `json:"baseAsset"`
|
||||
BaseAssetPrecision int `json:"baseAssetPrecision"`
|
||||
QuoteAsset string `json:"quoteAsset"`
|
||||
QuotePrecision int `json:"quotePrecision"`
|
||||
OrderTypes []string `json:"orderTypes"`
|
||||
IcebergAllowed bool `json:"icebergAllowed"`
|
||||
OCOAllowed bool `json:"ocoAllowed"`
|
||||
QuoteOrderQtyMarketAllowed bool `json:"quoteOrderQtyMarketAllowed"`
|
||||
IsSpotTradingAllowed bool `json:"isSpotTradingAllowed"`
|
||||
IsMarginTradingAllowed bool `json:"isMarginTradingAllowed"`
|
||||
Filters []*filterData `json:"filters"`
|
||||
Permissions []string `json:"permissions"`
|
||||
} `json:"symbols"`
|
||||
}
|
||||
|
||||
type filterData struct {
|
||||
FilterType filterType `json:"filterType"`
|
||||
MinPrice float64 `json:"minPrice,string"`
|
||||
MaxPrice float64 `json:"maxPrice,string"`
|
||||
TickSize float64 `json:"tickSize,string"`
|
||||
MultiplierUp float64 `json:"multiplierUp,string"`
|
||||
MultiplierDown float64 `json:"multiplierDown,string"`
|
||||
AvgPriceMinutes int64 `json:"avgPriceMins"`
|
||||
MinQty float64 `json:"minQty,string"`
|
||||
MaxQty float64 `json:"maxQty,string"`
|
||||
StepSize float64 `json:"stepSize,string"`
|
||||
MinNotional float64 `json:"minNotional,string"`
|
||||
ApplyToMarket bool `json:"applyToMarket"`
|
||||
Limit int64 `json:"limit"`
|
||||
MaxNumAlgoOrders int64 `json:"maxNumAlgoOrders"`
|
||||
MaxNumIcebergOrders int64 `json:"maxNumIcebergOrders"`
|
||||
MaxNumOrders int64 `json:"maxNumOrders"`
|
||||
}
|
||||
|
||||
// CoinInfo stores information about all supported coins
|
||||
type CoinInfo struct {
|
||||
Coin string `json:"coin"`
|
||||
|
||||
Reference in New Issue
Block a user