Skip to content

Commit 3228c1a

Browse files
authored
Merge branch 'adshao:master' into master
2 parents 7274202 + dc7abf8 commit 3228c1a

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+4249
-363
lines changed

v2/client.go

+32-14
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
"github.com/adshao/go-binance/v2/common"
2121
"github.com/adshao/go-binance/v2/delivery"
2222
"github.com/adshao/go-binance/v2/futures"
23+
"github.com/adshao/go-binance/v2/options"
2324
)
2425

2526
// SideType define side type of order
@@ -102,9 +103,9 @@ type RateLimitInterval string
102103
type AccountType string
103104

104105
// Endpoints
105-
const (
106-
baseAPIMainURL = "https://api.binance.com"
107-
baseAPITestnetURL = "https://testnet.binance.vision"
106+
var (
107+
BaseAPIMainURL = "https://api.binance.com"
108+
BaseAPITestnetURL = "https://testnet.binance.vision"
108109
)
109110

110111
// UseTestnet switch all the API endpoints from production to the testnet
@@ -141,6 +142,7 @@ const (
141142
OrderStatusTypePendingCancel OrderStatusType = "PENDING_CANCEL"
142143
OrderStatusTypeRejected OrderStatusType = "REJECTED"
143144
OrderStatusTypeExpired OrderStatusType = "EXPIRED"
145+
OrderStatusExpiredInMatch OrderStatusType = "EXPIRED_IN_MATCH" // STP Expired
144146

145147
SymbolTypeSpot SymbolType = "SPOT"
146148

@@ -152,15 +154,16 @@ const (
152154
SymbolStatusTypeAuctionMatch SymbolStatusType = "AUCTION_MATCH"
153155
SymbolStatusTypeBreak SymbolStatusType = "BREAK"
154156

155-
SymbolFilterTypeLotSize SymbolFilterType = "LOT_SIZE"
156-
SymbolFilterTypePriceFilter SymbolFilterType = "PRICE_FILTER"
157-
SymbolFilterTypePercentPrice SymbolFilterType = "PERCENT_PRICE"
158-
// Deprecated: use SymbolFilterTypePercentPrice instead
159-
SymbolFilterTypeMinNotional SymbolFilterType = "MIN_NOTIONAL"
160-
SymbolFilterTypeNotional SymbolFilterType = "NOTIONAL"
161-
SymbolFilterTypeIcebergParts SymbolFilterType = "ICEBERG_PARTS"
162-
SymbolFilterTypeMarketLotSize SymbolFilterType = "MARKET_LOT_SIZE"
163-
SymbolFilterTypeMaxNumAlgoOrders SymbolFilterType = "MAX_NUM_ALGO_ORDERS"
157+
SymbolFilterTypeLotSize SymbolFilterType = "LOT_SIZE"
158+
SymbolFilterTypePriceFilter SymbolFilterType = "PRICE_FILTER"
159+
SymbolFilterTypePercentPriceBySide SymbolFilterType = "PERCENT_PRICE_BY_SIDE"
160+
SymbolFilterTypeMinNotional SymbolFilterType = "MIN_NOTIONAL"
161+
SymbolFilterTypeNotional SymbolFilterType = "NOTIONAL"
162+
SymbolFilterTypeIcebergParts SymbolFilterType = "ICEBERG_PARTS"
163+
SymbolFilterTypeMarketLotSize SymbolFilterType = "MARKET_LOT_SIZE"
164+
SymbolFilterTypeMaxNumOrders SymbolFilterType = "MAX_NUM_ORDERS"
165+
SymbolFilterTypeMaxNumAlgoOrders SymbolFilterType = "MAX_NUM_ALGO_ORDERS"
166+
SymbolFilterTypeTrailingDelta SymbolFilterType = "TRAILING_DELTA"
164167

165168
UserDataEventTypeOutboundAccountPosition UserDataEventType = "outboundAccountPosition"
166169
UserDataEventTypeBalanceUpdate UserDataEventType = "balanceUpdate"
@@ -258,9 +261,9 @@ func newJSON(data []byte) (j *simplejson.Json, err error) {
258261
// getAPIEndpoint return the base endpoint of the Rest API according the UseTestnet flag
259262
func getAPIEndpoint() string {
260263
if UseTestnet {
261-
return baseAPITestnetURL
264+
return BaseAPITestnetURL
262265
}
263-
return baseAPIMainURL
266+
return BaseAPIMainURL
264267
}
265268

266269
// NewClient initialize an API client instance with API key and secret key.
@@ -309,6 +312,11 @@ func NewDeliveryClient(apiKey, secretKey string) *delivery.Client {
309312
return delivery.NewClient(apiKey, secretKey)
310313
}
311314

315+
// NewOptionsClient initialize client for options API
316+
func NewOptionsClient(apiKey, secretKey string) *options.Client {
317+
return options.NewClient(apiKey, secretKey)
318+
}
319+
312320
type doFunc func(req *http.Request) (*http.Response, error)
313321

314322
// Client define API client
@@ -1009,3 +1017,13 @@ func (c *Client) NewManagedSubAccountAssetsService() *ManagedSubAccountAssetsSer
10091017
func (c *Client) NewSubAccountFuturesAccountService() *SubAccountFuturesAccountService {
10101018
return &SubAccountFuturesAccountService{c: c}
10111019
}
1020+
1021+
// NewSubAccountFuturesSummaryV1Service Get Summary of Sub-account's Futures Account (For Master Account)
1022+
func (c *Client) NewSubAccountFuturesSummaryV1Service() *SubAccountFuturesSummaryV1Service {
1023+
return &SubAccountFuturesSummaryV1Service{c: c}
1024+
}
1025+
1026+
// NewSubAccountFuturesTransferV1Service Futures Transfer for Sub-account (For Master Account)
1027+
func (c *Client) NewSubAccountFuturesTransferV1Service() *SubAccountFuturesTransferV1Service {
1028+
return &SubAccountFuturesTransferV1Service{c: c}
1029+
}

v2/common/helpers.go

+25-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
package common
22

3-
import "math"
4-
import "bytes"
3+
import (
4+
"bytes"
5+
"fmt"
6+
"math"
7+
)
58

69
// AmountToLotSize converts an amount to a lot sized amount
710
func AmountToLotSize(lot float64, precision int, amount float64) float64 {
@@ -19,3 +22,23 @@ func ToJSONList(v []byte) []byte {
1922
}
2023
return v
2124
}
25+
26+
func ToInt(digit interface{}) (i int, err error) {
27+
if intVal, ok := digit.(int); ok {
28+
return int(intVal), nil
29+
}
30+
if floatVal, ok := digit.(float64); ok {
31+
return int(floatVal), nil
32+
}
33+
return 0, fmt.Errorf("unexpected digit: %v", digit)
34+
}
35+
36+
func ToInt64(digit interface{}) (i int64, err error) {
37+
if intVal, ok := digit.(int); ok {
38+
return int64(intVal), nil
39+
}
40+
if floatVal, ok := digit.(float64); ok {
41+
return int64(floatVal), nil
42+
}
43+
return 0, fmt.Errorf("unexpected digit: %v", digit)
44+
}

v2/delivery/client.go

+6-5
Original file line numberDiff line numberDiff line change
@@ -123,11 +123,12 @@ const (
123123
SymbolStatusTypeAuctionMatch SymbolStatusType = "AUCTION_MATCH"
124124
SymbolStatusTypeBreak SymbolStatusType = "BREAK"
125125

126-
SymbolFilterTypeLotSize SymbolFilterType = "LOT_SIZE"
127-
SymbolFilterTypePrice SymbolFilterType = "PRICE_FILTER"
128-
SymbolFilterTypePercentPrice SymbolFilterType = "PERCENT_PRICE"
129-
SymbolFilterTypeMarketLotSize SymbolFilterType = "MARKET_LOT_SIZE"
130-
SymbolFilterTypeMaxNumOrders SymbolFilterType = "MAX_NUM_ORDERS"
126+
SymbolFilterTypeLotSize SymbolFilterType = "LOT_SIZE"
127+
SymbolFilterTypePrice SymbolFilterType = "PRICE_FILTER"
128+
SymbolFilterTypePercentPrice SymbolFilterType = "PERCENT_PRICE"
129+
SymbolFilterTypeMarketLotSize SymbolFilterType = "MARKET_LOT_SIZE"
130+
SymbolFilterTypeMaxNumOrders SymbolFilterType = "MAX_NUM_ORDERS"
131+
SymbolFilterTypeMaxNumAlgoOrders SymbolFilterType = "MAX_NUM_ALGO_ORDERS"
131132

132133
SideEffectTypeNoSideEffect SideEffectType = "NO_SIDE_EFFECT"
133134
SideEffectTypeMarginBuy SideEffectType = "MARGIN_BUY"

v2/delivery/exchange_info_service.go

+28-3
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import (
44
"context"
55
"encoding/json"
66
"net/http"
7+
8+
"github.com/adshao/go-binance/v2/common"
79
)
810

911
// ExchangeInfoService exchange info service
@@ -91,7 +93,7 @@ type PriceFilter struct {
9193

9294
// PercentPriceFilter define percent price filter of symbol
9395
type PercentPriceFilter struct {
94-
MultiplierDecimal int `json:"multiplierDecimal"`
96+
MultiplierDecimal string `json:"multiplierDecimal"`
9597
MultiplierUp string `json:"multiplierUp"`
9698
MultiplierDown string `json:"multiplierDown"`
9799
}
@@ -108,6 +110,11 @@ type MaxNumOrdersFilter struct {
108110
Limit int64 `json:"limit"`
109111
}
110112

113+
// MaxNumAlgoOrdersFilter define max num orders filter of symbol of algo
114+
type MaxNumAlgoOrdersFilter struct {
115+
Limit int64 `json:"limit"`
116+
}
117+
111118
// LotSizeFilter return lot size filter of symbol
112119
func (s *Symbol) LotSizeFilter() *LotSizeFilter {
113120
for _, filter := range s.Filters {
@@ -154,7 +161,7 @@ func (s *Symbol) PercentPriceFilter() *PercentPriceFilter {
154161
if filter["filterType"].(string) == string(SymbolFilterTypePercentPrice) {
155162
f := &PercentPriceFilter{}
156163
if i, ok := filter["multiplierDecimal"]; ok {
157-
f.MultiplierDecimal = int(i.(float64))
164+
f.MultiplierDecimal = i.(string)
158165
}
159166
if i, ok := filter["multiplierUp"]; ok {
160167
f.MultiplierUp = i.(string)
@@ -194,7 +201,25 @@ func (s *Symbol) MaxNumOrdersFilter() *MaxNumOrdersFilter {
194201
if filter["filterType"].(string) == string(SymbolFilterTypeMaxNumOrders) {
195202
f := &MaxNumOrdersFilter{}
196203
if i, ok := filter["limit"]; ok {
197-
f.Limit = int64(i.(float64))
204+
if limit, okk := common.ToInt64(i); okk == nil {
205+
f.Limit = limit
206+
}
207+
}
208+
return f
209+
}
210+
}
211+
return nil
212+
}
213+
214+
// MaxNumAlgoOrdersFilter return max num orders filter of symbol
215+
func (s *Symbol) MaxNumAlgoOrdersFilter() *MaxNumAlgoOrdersFilter {
216+
for _, filter := range s.Filters {
217+
if filter["filterType"].(string) == string(SymbolFilterTypeMaxNumAlgoOrders) {
218+
f := &MaxNumAlgoOrdersFilter{}
219+
if i, ok := filter["limit"]; ok {
220+
if limit, okk := common.ToInt64(i); okk == nil {
221+
f.Limit = limit
222+
}
198223
}
199224
return f
200225
}

v2/delivery/exchange_info_service_test.go

+51-4
Original file line numberDiff line numberDiff line change
@@ -57,11 +57,15 @@ func (s *exchangeInfoServiceTestSuite) TestExchangeInfo() {
5757
"filterType": "MAX_NUM_ORDERS",
5858
"limit": 200
5959
},
60+
{
61+
"limit": 20,
62+
"filterType": "MAX_NUM_ALGO_ORDERS"
63+
},
6064
{
6165
"filterType": "PERCENT_PRICE",
6266
"multiplierUp": "1.0500",
6367
"multiplierDown": "0.9500",
64-
"multiplierDecimal": 4
68+
"multiplierDecimal": "4"
6569
}
6670
],
6771
"OrderType": [
@@ -146,37 +150,48 @@ func (s *exchangeInfoServiceTestSuite) TestExchangeInfo() {
146150
{"filterType": "LOT_SIZE", "minQty": "1", "maxQty": "100000", "stepSize": "1"},
147151
{"filterType": "MARKET_LOT_SIZE", "maxQty": "100000", "minQty": "1", "stepSize": "1"},
148152
{"filterType": "MAX_NUM_ORDERS", "limit": 200},
149-
{"filterType": "PERCENT_PRICE", "multiplierUp": "1.0500", "multiplierDown": "0.9500", "multiplierDecimal": 4},
153+
{"filterType": "MAX_NUM_ALGO_ORDERS", "limit": 20},
154+
{"filterType": "PERCENT_PRICE", "multiplierUp": "1.0500", "multiplierDown": "0.9500", "multiplierDecimal": "4"},
150155
},
151156
},
152157
},
153158
}
154159
s.assertExchangeInfoEqual(ei, res)
155-
s.r().Len(ei.Symbols[0].Filters, 5, "Filters")
160+
s.r().Len(ei.Symbols[0].Filters, 6, "Filters")
161+
156162
ePriceFilter := &PriceFilter{
157163
MaxPrice: "100000",
158164
MinPrice: "0.1",
159165
TickSize: "0.1",
160166
}
161167
s.assertPriceFilterEqual(ePriceFilter, res.Symbols[0].PriceFilter())
168+
162169
eLotSizeFilter := &LotSizeFilter{
163170
MaxQuantity: "100000",
164171
MinQuantity: "1",
165172
StepSize: "1",
166173
}
167174
s.assertLotSizeFilterEqual(eLotSizeFilter, res.Symbols[0].LotSizeFilter())
175+
168176
eMarketLotSizeFilter := &MarketLotSizeFilter{
169177
MaxQuantity: "100000",
170178
MinQuantity: "1",
171179
StepSize: "1",
172180
}
173181
s.assertMarketLotSizeFilterEqual(eMarketLotSizeFilter, res.Symbols[0].MarketLotSizeFilter())
182+
174183
eMaxNumOrdersFilter := &MaxNumOrdersFilter{
175184
Limit: 200,
176185
}
177186
s.assertMaxNumOrdersFilterEqual(eMaxNumOrdersFilter, res.Symbols[0].MaxNumOrdersFilter())
187+
188+
eMaxNumAlgoOrdersFilter := &MaxNumAlgoOrdersFilter{
189+
Limit: 20,
190+
}
191+
s.assertMaxNumAlgoOrdersFilterEqual(eMaxNumAlgoOrdersFilter, res.Symbols[0].MaxNumAlgoOrdersFilter())
192+
178193
ePercentPriceFilter := &PercentPriceFilter{
179-
MultiplierDecimal: 4,
194+
MultiplierDecimal: "4",
180195
MultiplierUp: "1.0500",
181196
MultiplierDown: "0.9500",
182197
}
@@ -219,6 +234,33 @@ func (s *exchangeInfoServiceTestSuite) assertExchangeInfoEqual(e, a *ExchangeInf
219234
r.Equal(e.Symbols[i].PricePrecision, a.Symbols[i].PricePrecision, "PricePrecision")
220235
r.Equal(e.Symbols[i].QuantityPrecision, a.Symbols[i].QuantityPrecision, "QuantityPrecision")
221236
r.Equal(e.Symbols[i].RequiredMarginPercent, a.Symbols[i].RequiredMarginPercent, "RequiredMarginPercent")
237+
238+
for fi, currentFilter := range a.Symbols[i].Filters {
239+
r.Len(currentFilter, len(e.Symbols[i].Filters[fi]))
240+
switch currentFilter["filterType"] {
241+
case "PRICE_FILTER":
242+
r.Equal(e.Symbols[i].PriceFilter().MinPrice, a.Symbols[i].PriceFilter().MinPrice, "MinPrice")
243+
r.Equal(e.Symbols[i].PriceFilter().MaxPrice, a.Symbols[i].PriceFilter().MaxPrice, "MaxPrice")
244+
r.Equal(e.Symbols[i].PriceFilter().TickSize, a.Symbols[i].PriceFilter().TickSize, "TickSize")
245+
case "LOT_SIZE":
246+
r.Equal(e.Symbols[i].LotSizeFilter().MinQuantity, a.Symbols[i].LotSizeFilter().MinQuantity, "MinQuantity")
247+
r.Equal(e.Symbols[i].LotSizeFilter().MaxQuantity, a.Symbols[i].LotSizeFilter().MaxQuantity, "MaxQuantity")
248+
r.Equal(e.Symbols[i].LotSizeFilter().StepSize, a.Symbols[i].LotSizeFilter().StepSize, "StepSize")
249+
case "MARKET_LOT_SIZE":
250+
r.Equal(e.Symbols[i].MarketLotSizeFilter().MinQuantity, a.Symbols[i].MarketLotSizeFilter().MinQuantity, "MinQuantity")
251+
r.Equal(e.Symbols[i].MarketLotSizeFilter().MaxQuantity, a.Symbols[i].MarketLotSizeFilter().MaxQuantity, "MaxQuantity")
252+
r.Equal(e.Symbols[i].MarketLotSizeFilter().StepSize, a.Symbols[i].MarketLotSizeFilter().StepSize, "StepSize")
253+
case "MAX_NUM_ORDERS":
254+
r.Equal(e.Symbols[i].MaxNumOrdersFilter().Limit, a.Symbols[i].MaxNumOrdersFilter().Limit, "Limit")
255+
case "MAX_NUM_ALGO_ORDERS":
256+
r.Equal(e.Symbols[i].MaxNumAlgoOrdersFilter().Limit, a.Symbols[i].MaxNumAlgoOrdersFilter().Limit, "Limit")
257+
case "PERCENT_PRICE":
258+
r.Equal(e.Symbols[i].PercentPriceFilter().MultiplierDecimal, a.Symbols[i].PercentPriceFilter().MultiplierDecimal, "MultiplierDecimal")
259+
r.Equal(e.Symbols[i].PercentPriceFilter().MultiplierUp, a.Symbols[i].PercentPriceFilter().MultiplierUp, "MultiplierUp")
260+
r.Equal(e.Symbols[i].PercentPriceFilter().MultiplierDown, a.Symbols[i].PercentPriceFilter().MultiplierDown, "MultiplierDown")
261+
}
262+
}
263+
222264
r.Len(a.Symbols[i].OrderType, len(e.Symbols[i].OrderType))
223265
for j, orderType := range e.Symbols[i].OrderType {
224266
r.Equal(orderType, a.Symbols[i].OrderType[j], "OrderType")
@@ -262,3 +304,8 @@ func (s *exchangeInfoServiceTestSuite) assertMaxNumOrdersFilterEqual(e, a *MaxNu
262304
r := s.r()
263305
r.Equal(e.Limit, a.Limit, "Limit")
264306
}
307+
308+
func (s *exchangeInfoServiceTestSuite) assertMaxNumAlgoOrdersFilterEqual(e, a *MaxNumAlgoOrdersFilter) {
309+
r := s.r()
310+
r.Equal(e.Limit, a.Limit, "Limit")
311+
}

v2/delivery/position_service.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ func (s *UpdatePositionMarginService) Amount(amount string) *UpdatePositionMargi
119119
return s
120120
}
121121

122-
// Type set action type: 1: Add postion margin,2: Reduce postion margin
122+
// Type set action type: 1: Add position margin,2: Reduce position margin
123123
func (s *UpdatePositionMarginService) Type(actionType int) *UpdatePositionMarginService {
124124
s.actionType = actionType
125125
return s

v2/delivery/ticker_service.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ type PriceChangeStats struct {
171171
BaseVolume string `json:"baseVolume"`
172172
OpenTime int64 `json:"openTime"`
173173
CloseTime int64 `json:"closeTime"`
174-
FristID int64 `json:"firstId"`
174+
FirstID int64 `json:"firstId"`
175175
LastID int64 `json:"lastId"`
176176
Count int64 `json:"count"`
177177
}

v2/delivery/ticker_service_test.go

+6-6
Original file line numberDiff line numberDiff line change
@@ -345,7 +345,7 @@ func (s *tickerServiceTestSuite) TestListPriceChangeStats() {
345345
BaseVolume: "138965.76942775",
346346
OpenTime: 1623748920000,
347347
CloseTime: 1623835355736,
348-
FristID: 172749700,
348+
FirstID: 172749700,
349349
LastID: 173464362,
350350
Count: 714658,
351351
}
@@ -364,7 +364,7 @@ func (s *tickerServiceTestSuite) TestListPriceChangeStats() {
364364
BaseVolume: "648179.55304919",
365365
OpenTime: 1623748920000,
366366
CloseTime: 1623835355187,
367-
FristID: 138575549,
367+
FirstID: 138575549,
368368
LastID: 139103143,
369369
Count: 527595,
370370
}
@@ -423,7 +423,7 @@ func (s *tickerServiceTestSuite) TestSinglePriceChangeStats() {
423423
BaseVolume: "137750.93213717",
424424
OpenTime: 1623752520000,
425425
CloseTime: 1623838964257,
426-
FristID: 172782522,
426+
FirstID: 172782522,
427427
LastID: 173490102,
428428
Count: 707576,
429429
}
@@ -498,7 +498,7 @@ func (s *tickerServiceTestSuite) TestPriceChangeStatsWithPair() {
498498
BaseVolume: "8300.32545198",
499499
OpenTime: 1623755580000,
500500
CloseTime: 1623842010140,
501-
FristID: 7516015,
501+
FirstID: 7516015,
502502
LastID: 7591268,
503503
Count: 75254,
504504
}
@@ -517,7 +517,7 @@ func (s *tickerServiceTestSuite) TestPriceChangeStatsWithPair() {
517517
BaseVolume: "13637.88521626",
518518
OpenTime: 1623755580000,
519519
CloseTime: 1623842010656,
520-
FristID: 32157829,
520+
FirstID: 32157829,
521521
LastID: 32307537,
522522
Count: 149709,
523523
}
@@ -541,7 +541,7 @@ func (s *tickerServiceTestSuite) assertPriceChangeStatsEqual(e, a *PriceChangeSt
541541
r.Equal(e.BaseVolume, a.BaseVolume, "BaseVolume")
542542
r.Equal(e.OpenTime, a.OpenTime, "OpenTime")
543543
r.Equal(e.CloseTime, a.CloseTime, "CloseTime")
544-
r.Equal(e.FristID, a.FristID, "FristID")
544+
r.Equal(e.FirstID, a.FirstID, "FirstID")
545545
r.Equal(e.LastID, a.LastID, "LastID")
546546
r.Equal(e.Count, a.Count, "Count")
547547
}

0 commit comments

Comments
 (0)