Skip to content

Commit

Permalink
Update and improve the synchronization of "exchange_info_service" and…
Browse files Browse the repository at this point in the history
… "exchange_info_service_test" with the latest interface "exchange_info" status of Binance, and correct some issues (#519)

exchange_info_service:
    spot:
        1.Revised the type of MultiplierDecimal to string.
        2.Add Filter MAX_NUM_ORDERS and TRAILING_DELTA.
        3.remove type PercentPrice, add type PercentPriceBySide. Actually, PercentPriceBySide has replaced PercentPrice.
        4.remove type MinNotionalFilter.In fact, it should be removed when adding type Notional. Notional has replaced MinNotionalFilter.

    futures:
        1.Revised the type of MultiplierDecimal to string.

    delivery:
        1.Revised the type of MultiplierDecimal to string
        2.Add Filter MAX_NUM_ALGO_ORDERS

    option:
        1.remove type PercentPriceFilter/MarketLotSizeFilter/MaxNumOrdersFilter/MaxNumAlgoOrdersFilter/MinNotionalFilter.

          Because options currently only have two filters(PRICE_FILTER/LOT_SIZE).I don't think it's necessary to implement
          these non-existent things. What needs to be done is to maintain consistency with the official interface. It is
          also possible that the implementer of this module simply copied and modified a copy of the code from other
          modules before, without considering the actual situation.

exchange_info_service_test:
    Based on the above modifications, the complete testing of the filter has been improved. Of course, combined with my
    thoughts on existing code, after reviewing these test codes, I found that some of the previous submissions did not
    complete the testing of the filter. I speculate that there may be some potential unresolved issues and skip this
    section. At present, it has been repaired and in my opinion, it is relatively complete.
  • Loading branch information
xyq-c-cpp authored Nov 11, 2023
1 parent bb34461 commit a58ccd5
Show file tree
Hide file tree
Showing 11 changed files with 446 additions and 247 deletions.
19 changes: 10 additions & 9 deletions v2/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -153,15 +153,16 @@ const (
SymbolStatusTypeAuctionMatch SymbolStatusType = "AUCTION_MATCH"
SymbolStatusTypeBreak SymbolStatusType = "BREAK"

SymbolFilterTypeLotSize SymbolFilterType = "LOT_SIZE"
SymbolFilterTypePriceFilter SymbolFilterType = "PRICE_FILTER"
SymbolFilterTypePercentPrice SymbolFilterType = "PERCENT_PRICE"
// Deprecated: use SymbolFilterTypePercentPrice instead
SymbolFilterTypeMinNotional SymbolFilterType = "MIN_NOTIONAL"
SymbolFilterTypeNotional SymbolFilterType = "NOTIONAL"
SymbolFilterTypeIcebergParts SymbolFilterType = "ICEBERG_PARTS"
SymbolFilterTypeMarketLotSize SymbolFilterType = "MARKET_LOT_SIZE"
SymbolFilterTypeMaxNumAlgoOrders SymbolFilterType = "MAX_NUM_ALGO_ORDERS"
SymbolFilterTypeLotSize SymbolFilterType = "LOT_SIZE"
SymbolFilterTypePriceFilter SymbolFilterType = "PRICE_FILTER"
SymbolFilterTypePercentPriceBySide SymbolFilterType = "PERCENT_PRICE_BY_SIDE"
SymbolFilterTypeMinNotional SymbolFilterType = "MIN_NOTIONAL"
SymbolFilterTypeNotional SymbolFilterType = "NOTIONAL"
SymbolFilterTypeIcebergParts SymbolFilterType = "ICEBERG_PARTS"
SymbolFilterTypeMarketLotSize SymbolFilterType = "MARKET_LOT_SIZE"
SymbolFilterTypeMaxNumOrders SymbolFilterType = "MAX_NUM_ORDERS"
SymbolFilterTypeMaxNumAlgoOrders SymbolFilterType = "MAX_NUM_ALGO_ORDERS"
SymbolFilterTypeTrailingDelta SymbolFilterType = "TRAILING_DELTA"

UserDataEventTypeOutboundAccountPosition UserDataEventType = "outboundAccountPosition"
UserDataEventTypeBalanceUpdate UserDataEventType = "balanceUpdate"
Expand Down
27 changes: 25 additions & 2 deletions v2/common/helpers.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package common

import "math"
import "bytes"
import (
"bytes"
"fmt"
"math"
)

// AmountToLotSize converts an amount to a lot sized amount
func AmountToLotSize(lot float64, precision int, amount float64) float64 {
Expand All @@ -19,3 +22,23 @@ func ToJSONList(v []byte) []byte {
}
return v
}

func ToInt(digit interface{}) (i int, err error) {
if intVal, ok := digit.(int); ok {
return int(intVal), nil
}
if floatVal, ok := digit.(float64); ok {
return int(floatVal), nil
}
return 0, fmt.Errorf("unexpected digit: %v", digit)
}

func ToInt64(digit interface{}) (i int64, err error) {
if intVal, ok := digit.(int); ok {
return int64(intVal), nil
}
if floatVal, ok := digit.(float64); ok {
return int64(floatVal), nil
}
return 0, fmt.Errorf("unexpected digit: %v", digit)
}
11 changes: 6 additions & 5 deletions v2/delivery/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,11 +123,12 @@ const (
SymbolStatusTypeAuctionMatch SymbolStatusType = "AUCTION_MATCH"
SymbolStatusTypeBreak SymbolStatusType = "BREAK"

SymbolFilterTypeLotSize SymbolFilterType = "LOT_SIZE"
SymbolFilterTypePrice SymbolFilterType = "PRICE_FILTER"
SymbolFilterTypePercentPrice SymbolFilterType = "PERCENT_PRICE"
SymbolFilterTypeMarketLotSize SymbolFilterType = "MARKET_LOT_SIZE"
SymbolFilterTypeMaxNumOrders SymbolFilterType = "MAX_NUM_ORDERS"
SymbolFilterTypeLotSize SymbolFilterType = "LOT_SIZE"
SymbolFilterTypePrice SymbolFilterType = "PRICE_FILTER"
SymbolFilterTypePercentPrice SymbolFilterType = "PERCENT_PRICE"
SymbolFilterTypeMarketLotSize SymbolFilterType = "MARKET_LOT_SIZE"
SymbolFilterTypeMaxNumOrders SymbolFilterType = "MAX_NUM_ORDERS"
SymbolFilterTypeMaxNumAlgoOrders SymbolFilterType = "MAX_NUM_ALGO_ORDERS"

SideEffectTypeNoSideEffect SideEffectType = "NO_SIDE_EFFECT"
SideEffectTypeMarginBuy SideEffectType = "MARGIN_BUY"
Expand Down
31 changes: 28 additions & 3 deletions v2/delivery/exchange_info_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import (
"context"
"encoding/json"
"net/http"

"github.com/adshao/go-binance/v2/common"
)

// ExchangeInfoService exchange info service
Expand Down Expand Up @@ -91,7 +93,7 @@ type PriceFilter struct {

// PercentPriceFilter define percent price filter of symbol
type PercentPriceFilter struct {
MultiplierDecimal int `json:"multiplierDecimal"`
MultiplierDecimal string `json:"multiplierDecimal"`
MultiplierUp string `json:"multiplierUp"`
MultiplierDown string `json:"multiplierDown"`
}
Expand All @@ -108,6 +110,11 @@ type MaxNumOrdersFilter struct {
Limit int64 `json:"limit"`
}

// MaxNumAlgoOrdersFilter define max num orders filter of symbol of algo
type MaxNumAlgoOrdersFilter struct {
Limit int64 `json:"limit"`
}

// LotSizeFilter return lot size filter of symbol
func (s *Symbol) LotSizeFilter() *LotSizeFilter {
for _, filter := range s.Filters {
Expand Down Expand Up @@ -154,7 +161,7 @@ func (s *Symbol) PercentPriceFilter() *PercentPriceFilter {
if filter["filterType"].(string) == string(SymbolFilterTypePercentPrice) {
f := &PercentPriceFilter{}
if i, ok := filter["multiplierDecimal"]; ok {
f.MultiplierDecimal = int(i.(float64))
f.MultiplierDecimal = i.(string)
}
if i, ok := filter["multiplierUp"]; ok {
f.MultiplierUp = i.(string)
Expand Down Expand Up @@ -194,7 +201,25 @@ func (s *Symbol) MaxNumOrdersFilter() *MaxNumOrdersFilter {
if filter["filterType"].(string) == string(SymbolFilterTypeMaxNumOrders) {
f := &MaxNumOrdersFilter{}
if i, ok := filter["limit"]; ok {
f.Limit = int64(i.(float64))
if limit, okk := common.ToInt64(i); okk == nil {
f.Limit = limit
}
}
return f
}
}
return nil
}

// MaxNumAlgoOrdersFilter return max num orders filter of symbol
func (s *Symbol) MaxNumAlgoOrdersFilter() *MaxNumAlgoOrdersFilter {
for _, filter := range s.Filters {
if filter["filterType"].(string) == string(SymbolFilterTypeMaxNumAlgoOrders) {
f := &MaxNumAlgoOrdersFilter{}
if i, ok := filter["limit"]; ok {
if limit, okk := common.ToInt64(i); okk == nil {
f.Limit = limit
}
}
return f
}
Expand Down
55 changes: 51 additions & 4 deletions v2/delivery/exchange_info_service_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,15 @@ func (s *exchangeInfoServiceTestSuite) TestExchangeInfo() {
"filterType": "MAX_NUM_ORDERS",
"limit": 200
},
{
"limit": 20,
"filterType": "MAX_NUM_ALGO_ORDERS"
},
{
"filterType": "PERCENT_PRICE",
"multiplierUp": "1.0500",
"multiplierDown": "0.9500",
"multiplierDecimal": 4
"multiplierDecimal": "4"
}
],
"OrderType": [
Expand Down Expand Up @@ -146,37 +150,48 @@ func (s *exchangeInfoServiceTestSuite) TestExchangeInfo() {
{"filterType": "LOT_SIZE", "minQty": "1", "maxQty": "100000", "stepSize": "1"},
{"filterType": "MARKET_LOT_SIZE", "maxQty": "100000", "minQty": "1", "stepSize": "1"},
{"filterType": "MAX_NUM_ORDERS", "limit": 200},
{"filterType": "PERCENT_PRICE", "multiplierUp": "1.0500", "multiplierDown": "0.9500", "multiplierDecimal": 4},
{"filterType": "MAX_NUM_ALGO_ORDERS", "limit": 20},
{"filterType": "PERCENT_PRICE", "multiplierUp": "1.0500", "multiplierDown": "0.9500", "multiplierDecimal": "4"},
},
},
},
}
s.assertExchangeInfoEqual(ei, res)
s.r().Len(ei.Symbols[0].Filters, 5, "Filters")
s.r().Len(ei.Symbols[0].Filters, 6, "Filters")

ePriceFilter := &PriceFilter{
MaxPrice: "100000",
MinPrice: "0.1",
TickSize: "0.1",
}
s.assertPriceFilterEqual(ePriceFilter, res.Symbols[0].PriceFilter())

eLotSizeFilter := &LotSizeFilter{
MaxQuantity: "100000",
MinQuantity: "1",
StepSize: "1",
}
s.assertLotSizeFilterEqual(eLotSizeFilter, res.Symbols[0].LotSizeFilter())

eMarketLotSizeFilter := &MarketLotSizeFilter{
MaxQuantity: "100000",
MinQuantity: "1",
StepSize: "1",
}
s.assertMarketLotSizeFilterEqual(eMarketLotSizeFilter, res.Symbols[0].MarketLotSizeFilter())

eMaxNumOrdersFilter := &MaxNumOrdersFilter{
Limit: 200,
}
s.assertMaxNumOrdersFilterEqual(eMaxNumOrdersFilter, res.Symbols[0].MaxNumOrdersFilter())

eMaxNumAlgoOrdersFilter := &MaxNumAlgoOrdersFilter{
Limit: 20,
}
s.assertMaxNumAlgoOrdersFilterEqual(eMaxNumAlgoOrdersFilter, res.Symbols[0].MaxNumAlgoOrdersFilter())

ePercentPriceFilter := &PercentPriceFilter{
MultiplierDecimal: 4,
MultiplierDecimal: "4",
MultiplierUp: "1.0500",
MultiplierDown: "0.9500",
}
Expand Down Expand Up @@ -219,6 +234,33 @@ func (s *exchangeInfoServiceTestSuite) assertExchangeInfoEqual(e, a *ExchangeInf
r.Equal(e.Symbols[i].PricePrecision, a.Symbols[i].PricePrecision, "PricePrecision")
r.Equal(e.Symbols[i].QuantityPrecision, a.Symbols[i].QuantityPrecision, "QuantityPrecision")
r.Equal(e.Symbols[i].RequiredMarginPercent, a.Symbols[i].RequiredMarginPercent, "RequiredMarginPercent")

for fi, currentFilter := range a.Symbols[i].Filters {
r.Len(currentFilter, len(e.Symbols[i].Filters[fi]))
switch currentFilter["filterType"] {
case "PRICE_FILTER":
r.Equal(e.Symbols[i].PriceFilter().MinPrice, a.Symbols[i].PriceFilter().MinPrice, "MinPrice")
r.Equal(e.Symbols[i].PriceFilter().MaxPrice, a.Symbols[i].PriceFilter().MaxPrice, "MaxPrice")
r.Equal(e.Symbols[i].PriceFilter().TickSize, a.Symbols[i].PriceFilter().TickSize, "TickSize")
case "LOT_SIZE":
r.Equal(e.Symbols[i].LotSizeFilter().MinQuantity, a.Symbols[i].LotSizeFilter().MinQuantity, "MinQuantity")
r.Equal(e.Symbols[i].LotSizeFilter().MaxQuantity, a.Symbols[i].LotSizeFilter().MaxQuantity, "MaxQuantity")
r.Equal(e.Symbols[i].LotSizeFilter().StepSize, a.Symbols[i].LotSizeFilter().StepSize, "StepSize")
case "MARKET_LOT_SIZE":
r.Equal(e.Symbols[i].MarketLotSizeFilter().MinQuantity, a.Symbols[i].MarketLotSizeFilter().MinQuantity, "MinQuantity")
r.Equal(e.Symbols[i].MarketLotSizeFilter().MaxQuantity, a.Symbols[i].MarketLotSizeFilter().MaxQuantity, "MaxQuantity")
r.Equal(e.Symbols[i].MarketLotSizeFilter().StepSize, a.Symbols[i].MarketLotSizeFilter().StepSize, "StepSize")
case "MAX_NUM_ORDERS":
r.Equal(e.Symbols[i].MaxNumOrdersFilter().Limit, a.Symbols[i].MaxNumOrdersFilter().Limit, "Limit")
case "MAX_NUM_ALGO_ORDERS":
r.Equal(e.Symbols[i].MaxNumAlgoOrdersFilter().Limit, a.Symbols[i].MaxNumAlgoOrdersFilter().Limit, "Limit")
case "PERCENT_PRICE":
r.Equal(e.Symbols[i].PercentPriceFilter().MultiplierDecimal, a.Symbols[i].PercentPriceFilter().MultiplierDecimal, "MultiplierDecimal")
r.Equal(e.Symbols[i].PercentPriceFilter().MultiplierUp, a.Symbols[i].PercentPriceFilter().MultiplierUp, "MultiplierUp")
r.Equal(e.Symbols[i].PercentPriceFilter().MultiplierDown, a.Symbols[i].PercentPriceFilter().MultiplierDown, "MultiplierDown")
}
}

r.Len(a.Symbols[i].OrderType, len(e.Symbols[i].OrderType))
for j, orderType := range e.Symbols[i].OrderType {
r.Equal(orderType, a.Symbols[i].OrderType[j], "OrderType")
Expand Down Expand Up @@ -262,3 +304,8 @@ func (s *exchangeInfoServiceTestSuite) assertMaxNumOrdersFilterEqual(e, a *MaxNu
r := s.r()
r.Equal(e.Limit, a.Limit, "Limit")
}

func (s *exchangeInfoServiceTestSuite) assertMaxNumAlgoOrdersFilterEqual(e, a *MaxNumAlgoOrdersFilter) {
r := s.r()
r.Equal(e.Limit, a.Limit, "Limit")
}
Loading

0 comments on commit a58ccd5

Please sign in to comment.