diff --git a/.github/workflows/connector.yml b/.github/workflows/connector.yml new file mode 100644 index 0000000..46c49b5 --- /dev/null +++ b/.github/workflows/connector.yml @@ -0,0 +1,26 @@ +name: Run Tests + +on: + push: + branches: + - master + pull_request: + branches: + - master + - rc-** + +jobs: + UnitTest: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Setup Go + uses: actions/setup-go@v3 + with: + go-version-file: './go.mod' + - name: Format + run: ./scripts/checks.sh format + - name: Vet + run: ./scripts/checks.sh vet + - name: UnitTest + run: go test -v . diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7b5c4fb --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +coverage.txt +*.DS_Store diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..2322310 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,5 @@ +# Change log + +## v0.1.0 - 2023-03-31 + +- First release diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..2733eee --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,9 @@ +MIT License + +Copyright (c) 2023 Binance + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..2661939 --- /dev/null +++ b/README.md @@ -0,0 +1,217 @@ +# Binance Spot Go Connector + +This is a lightweight library that works as a connector to [Binance public API](https://github.com/binance/binance-spot-api-docs) + +## Supported API Endpoints: +- Account/Trade: `account.go` +- Wallet: `wallet.go` +- Margin Account/Trade: `margin.go` +- Market Data: `market.go` +- Sub-Accounts: `subaccount.go` +- Websocket Market/User Data Stream: `websocket.go` +- Websocket User Data Stream: `user_stream.go` + +## Installation +```shell +go get github.com/binance/binance-connector-go +``` + +To reference the package in your code, use the following import statement: +```golang +import ( + "github.com/binance/binance-connector-go" +) +``` +## Authentication +```go +// The Client can be initiated with apiKey, secretKey and baseURL. +// The baseURL is optional. If not specified, it will default to "https://api.binance.com". +client := binance_connector.NewClient("yourApiKey", "yourSecretKey") +``` + +## Extra Options +```go +client := binance_connector.NewClient("yourApiKey", "yourSecretKey", "https://api.binance.com") + +// Debug Mode +client.Debug = true + +// TimeOffset (in milliseconds) - used to adjust the request timestamp by subtracting/adding the current time with it: +client.TimeOffset = -1000 // implies adding: request timestamp = current time - (-1000) +``` + +## REST API + +Create an order example + +```go +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + apiKey := "yourApiKey" + secretKey := "yourSecretKey" + baseURL := "https://testnet.binance.vision" + + // Initialise the client + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // Create new order + newOrder, err := client.NewCreateOrderService().Symbol("BTCUSDT"). + Side("BUY").Type("MARKET").Quantity(0.001). + Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(newOrder)) +} +``` + +Please find more examples for each supported endpoint in the `examples` folder. + +## Websocket API + +Diff. Depth Stream Example + +```go +package main + +import ( + "fmt" + "time" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + wsDepthHandler := func(event *binance_connector.WsDepthEvent) { + fmt.Println(binance_connector.PrettyPrint(event)) + } + + errHandler := func(err error) { + fmt.Println(err) + } + + // Depth stream subscription + doneCh, stopCh, err := binance_connector.WsDepthServe("BNBUSDT", wsDepthHandler, errHandler) + if err != nil { + fmt.Println(err) + return + } + + go func() { + time.Sleep(30 * time.Second) + stopCh <- struct{}{} // use stopC to stop streaming + }() + + <-doneCh +} +``` + +## Base URL +- Binance provides alternative Production URLs in case of performance issues: + - https://api1.binance.com + - https://api2.binance.com + - https://api3.binance.com + +## Testnet Support +- In order to use the Testnet, simply set the `baseURL` to "https://testnet.binance.vision" +- You can find step-by-step instructions on how to use the get a Testnet API and Secret Key [here](https://dev.binance.vision/t/binance-testnet-environments/99) + +## Pretty Print vs PrintLn +- The `fmt.Println()` function will print the struct in a single line, which is not very readable. +- The `fmt.Println(binance_connector.PrettyPrint())` function will print the struct, including both the key and value, in a multi-line format which is more easily readable. + +### Regular PrintLn Example Output +```bash +&{depthUpdate 1680092520368 LTCBTC 1989614201 1989614210 [{0.00322300 70.96700000} {0.00322200 52.57100000} {0.00322000 248.64000000} {0.00321900 34.98300000}] [{0.00322600 71.52600000} {0.00323400 53.88900000} {0.00323500 27.37000000}]} +&{depthUpdate 1680092521368 LTCBTC 1989614211 1989614212 [{0.00320700 197.10100000} {0.00320100 15.76800000}] []} +&{depthUpdate 1680092522368 LTCBTC 1989614213 1989614224 [{0.00322300 86.15400000} {0.00322200 37.38400000} {0.00322100 252.53900000} {0.00322000 60.01300000}] [{0.00322800 75.48400000} {0.00322900 254.84500000} {0.00323000 8.74700000} {0.00323100 37.42800000}]} +&{depthUpdate 1680092523369 LTCBTC 1989614225 1989614226 [{0.00322300 103.57400000}] [{0.00399500 11.75400000}]} +&{depthUpdate 1680092524369 LTCBTC 1989614227 1989614276 [{0.00322500 0.00000000} {0.00322400 101.32700000} {0.00322300 138.82600000} {0.00322200 58.49100000} {0.00322100 249.65400000} {0.00321900 47.34800000} {0.00317800 16.08500000} {0.00317500 38.36500000}] [{0.00322500 75.14300000} {0.00322600 48.19100000} {0.00322700 44.97900000} {0.00322800 242.74300000} {0.00322900 20.73400000} {0.00532700 0.18900000} {0.00779700 0.05600000}]} +``` + +### binance_connector.PrettyPrint Example Output +```bash +{ + "e": "depthUpdate", + "E": 1680092041346, + "s": "LTCBTC", + "U": 1989606566, + "u": 1989606596, + "b": [ + { + "Price": "0.00322800", + "Quantity": "83.05100000" + }, + { + "Price": "0.00322700", + "Quantity": "12.50200000" + }, + { + "Price": "0.00322500", + "Quantity": "48.53700000" + }, + { + "Price": "0.00322400", + "Quantity": "244.13500000" + } + ], + "a": [ + { + "Price": "0.00322900", + "Quantity": "79.52900000" + }, + { + "Price": "0.00323000", + "Quantity": "42.68400000" + }, + { + "Price": "0.00323100", + "Quantity": "68.75500000" + } + ] +} +{ + "e": "depthUpdate", + "E": 1680092042346, + "s": "LTCBTC", + "U": 1989606597, + "u": 1989606611, + "b": [ + { + "Price": "0.00321400", + "Quantity": "0.24700000" + }, + { + "Price": "0.00318000", + "Quantity": "1.91600000" + } + ], + "a": [ + { + "Price": "0.00322900", + "Quantity": "79.27900000" + } + ] +} +``` + +## Limitations +Futures and European Options APIs are not supported: +- /fapi/* +- /dapi/* +- /vapi/* +- Associated Websocket Market and User Data Streams + +## Contributing +Contributions are welcome.
+If you've found a bug within this project, please open an issue to discuss what you would like to change.
+If it's an issue with the API, please open a topic at [Binance Developer Community](https://dev.binance.vision) diff --git a/account.go b/account.go new file mode 100644 index 0000000..9b73b56 --- /dev/null +++ b/account.go @@ -0,0 +1,1698 @@ +package binance_connector + +import ( + "context" + "encoding/json" + "net/http" +) + +// Binance Test New Order endpoint (POST /api/v3/order/test) +type TestNewOrder struct { + c *Client + symbol string + side string + orderType string + timeInForce *string + quantity *float64 + quoteOrderQty *float64 + price *float64 + newClientOrderId *string + strategyId *int + stopPrice *float64 + trailingDelta *int + icebergQty *float64 + newOrderRespType *string + selfTradePrevention *string +} + +// Symbol set symbol +func (s *TestNewOrder) Symbol(symbol string) *TestNewOrder { + s.symbol = symbol + return s +} + +// Side set side +func (s *TestNewOrder) Side(side string) *TestNewOrder { + s.side = side + return s +} + +// OrderType set orderType +func (s *TestNewOrder) OrderType(orderType string) *TestNewOrder { + s.orderType = orderType + return s +} + +// TimeInForce set timeInForce +func (s *TestNewOrder) TimeInForce(timeInForce string) *TestNewOrder { + s.timeInForce = &timeInForce + return s +} + +// Quantity set quantity +func (s *TestNewOrder) Quantity(quantity float64) *TestNewOrder { + s.quantity = &quantity + return s +} + +// QuoteOrderQty set quoteOrderQty +func (s *TestNewOrder) QuoteOrderQty(quoteOrderQty float64) *TestNewOrder { + s.quoteOrderQty = "eOrderQty + return s +} + +// Price set price +func (s *TestNewOrder) Price(price float64) *TestNewOrder { + s.price = &price + return s +} + +// NewClientOrderId set newClientOrderId +func (s *TestNewOrder) NewClientOrderId(newClientOrderId string) *TestNewOrder { + s.newClientOrderId = &newClientOrderId + return s +} + +// StrategyId set strategyId +func (s *TestNewOrder) StrategyId(strategyId int) *TestNewOrder { + s.strategyId = &strategyId + return s +} + +// StopPrice set stopPrice +func (s *TestNewOrder) StopPrice(stopPrice float64) *TestNewOrder { + s.stopPrice = &stopPrice + return s +} + +// TrailingDelta set trailingDelta +func (s *TestNewOrder) TrailingDelta(trailingDelta int) *TestNewOrder { + s.trailingDelta = &trailingDelta + return s +} + +// IcebergQty set icebergQty +func (s *TestNewOrder) IcebergQty(icebergQty float64) *TestNewOrder { + s.icebergQty = &icebergQty + return s +} + +// NewOrderRespType set newOrderRespType +func (s *TestNewOrder) NewOrderRespType(newOrderRespType string) *TestNewOrder { + s.newOrderRespType = &newOrderRespType + return s +} + +// SelfTradePrevention set selfTradePrevention +func (s *TestNewOrder) SelfTradePrevention(selfTradePrevention string) *TestNewOrder { + s.selfTradePrevention = &selfTradePrevention + return s +} + +// Send the request +func (s *TestNewOrder) Do(ctx context.Context, opts ...RequestOption) (res *AccountOrderBookResponse, err error) { + r := &request{ + method: http.MethodPost, + endpoint: "/api/v3/order/test", + secType: secTypeNone, + } + r.setParam("symbol", s.symbol) + r.setParam("side", s.side) + r.setParam("type", s.orderType) + if s.timeInForce != nil { + r.setParam("timeInForce", *s.timeInForce) + } + if s.quantity != nil { + r.setParam("quantity", *s.quantity) + } + if s.quoteOrderQty != nil { + r.setParam("quoteOrderQty", *s.quoteOrderQty) + } + if s.price != nil { + r.setParam("price", *s.price) + } + if s.newClientOrderId != nil { + r.setParam("newClientOrderId", *s.newClientOrderId) + } + if s.strategyId != nil { + r.setParam("strategyId", *s.strategyId) + } + if s.stopPrice != nil { + r.setParam("stopPrice", *s.stopPrice) + } + if s.trailingDelta != nil { + r.setParam("trailingDelta", *s.trailingDelta) + } + if s.icebergQty != nil { + r.setParam("icebergQty", *s.icebergQty) + } + if s.newOrderRespType != nil { + r.setParam("newOrderRespType", *s.newOrderRespType) + } + if s.selfTradePrevention != nil { + r.setParam("selfTradePreventionMode", *s.selfTradePrevention) + } + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return nil, err + } + res = new(AccountOrderBookResponse) + err = json.Unmarshal(data, res) + if err != nil { + return nil, err + } + return res, nil +} + +// Create AccountOrderBookResponse +type AccountOrderBookResponse struct { +} + +// Binance New Order endpoint (POST /api/v3/order) +// CreateOrderService create order +type CreateOrderService struct { + c *Client + symbol string + side string + orderType string + timeInForce *string + quantity *float64 + quoteOrderQty *float64 + price *float64 + newClientOrderId *string + strategyId *int + stopPrice *float64 + trailingDelta *int + icebergQty *float64 + newOrderRespType *string + selfTradePreventionMode *string +} + +// Symbol set symbol +func (s *CreateOrderService) Symbol(symbol string) *CreateOrderService { + s.symbol = symbol + return s +} + +// Side set side +func (s *CreateOrderService) Side(side string) *CreateOrderService { + s.side = side + return s +} + +// Type set type +func (s *CreateOrderService) Type(orderType string) *CreateOrderService { + s.orderType = orderType + return s +} + +// TimeInForce set timeInForce +func (s *CreateOrderService) TimeInForce(timeInForce string) *CreateOrderService { + s.timeInForce = &timeInForce + return s +} + +// Quantity set quantity +func (s *CreateOrderService) Quantity(quantity float64) *CreateOrderService { + s.quantity = &quantity + return s +} + +// QuoteOrderQty set quoteOrderQty +func (s *CreateOrderService) QuoteOrderQty(quoteOrderQty float64) *CreateOrderService { + s.quoteOrderQty = "eOrderQty + return s +} + +// Price set price +func (s *CreateOrderService) Price(price float64) *CreateOrderService { + s.price = &price + return s +} + +// NewClientOrderId set newClientOrderId +func (s *CreateOrderService) NewClientOrderId(newClientOrderId string) *CreateOrderService { + s.newClientOrderId = &newClientOrderId + return s +} + +// StopPrice set stopPrice +func (s *CreateOrderService) StopPrice(stopPrice float64) *CreateOrderService { + s.stopPrice = &stopPrice + return s +} + +// TrailingDelta set trailingDelta +func (s *CreateOrderService) TrailingDelta(trailingDelta int) *CreateOrderService { + s.trailingDelta = &trailingDelta + return s +} + +// IcebergQuantity set icebergQuantity +func (s *CreateOrderService) IcebergQuantity(icebergQty float64) *CreateOrderService { + s.icebergQty = &icebergQty + return s +} + +// NewOrderRespType set icebergQuantity +func (s *CreateOrderService) NewOrderRespType(newOrderRespType string) *CreateOrderService { + s.newOrderRespType = &newOrderRespType + return s +} + +// SelfTradePreventionMode set selfTradePreventionMode +func (s *CreateOrderService) SelfTradePreventionMode(selfTradePreventionMode string) *CreateOrderService { + s.selfTradePreventionMode = &selfTradePreventionMode + return s +} + +// Do send request +func (s *CreateOrderService) Do(ctx context.Context, opts ...RequestOption) (res *CreateOrderResponse, err error) { + r := &request{ + method: http.MethodPost, + endpoint: "/api/v3/order", + secType: secTypeSigned, + } + r.setParam("symbol", s.symbol) + r.setParam("side", s.side) + r.setParam("type", s.orderType) + if s.timeInForce != nil { + r.setParam("timeInForce", *s.timeInForce) + } + if s.quantity != nil { + r.setParam("quantity", *s.quantity) + } + if s.quoteOrderQty != nil { + r.setParam("quoteOrderQty", *s.quoteOrderQty) + } + if s.price != nil { + r.setParam("price", *s.price) + } + if s.newClientOrderId != nil { + r.setParam("newClientOrderId", *s.newClientOrderId) + } + if s.strategyId != nil { + r.setParam("strategyId", *s.strategyId) + } + if s.stopPrice != nil { + r.setParam("stopPrice", *s.stopPrice) + } + if s.trailingDelta != nil { + r.setParam("trailingDelta", *s.trailingDelta) + } + if s.icebergQty != nil { + r.setParam("icebergQty", *s.icebergQty) + } + if s.newOrderRespType != nil { + r.setParam("newOrderRespType", *s.newOrderRespType) + } + if s.selfTradePreventionMode != nil { + r.setParam("selfTradePreventionMode", *s.selfTradePreventionMode) + } + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return nil, err + } + res = new(CreateOrderResponse) + err = json.Unmarshal(data, res) + if err != nil { + return nil, err + } + return res, nil +} + +// Create CreateOrderResponse +type CreateOrderResponse struct { + Symbol string `json:"symbol"` + OrderId int64 `json:"orderId"` + OrderIdList []int64 `json:"orderIdList"` + ClientOrderId string `json:"clientOrderId"` + TransactTime uint64 `json:"transactTime"` +} + +// Binance Cancel Order endpoint (DELETE /api/v3/order) +// CancelOrderService cancel order +type CancelOrderService struct { + c *Client + symbol string + orderId *int64 + origClientOrderId *string + newClientOrderId *string + cancelRestrictions *string +} + +// Symbol set symbol +func (s *CancelOrderService) Symbol(symbol string) *CancelOrderService { + s.symbol = symbol + return s +} + +// OrderId set orderId +func (s *CancelOrderService) OrderId(orderId int64) *CancelOrderService { + s.orderId = &orderId + return s +} + +// OrigClientOrderId set origClientOrderId +func (s *CancelOrderService) OrigClientOrderId(origClientOrderId string) *CancelOrderService { + s.origClientOrderId = &origClientOrderId + return s +} + +// NewClientOrderId set newClientOrderId +func (s *CancelOrderService) NewClientOrderId(newClientOrderId string) *CancelOrderService { + s.newClientOrderId = &newClientOrderId + return s +} + +// CancelRestrictions set cancelRestrictions +func (s *CancelOrderService) CancelRestrictions(cancelRestrictions string) *CancelOrderService { + s.cancelRestrictions = &cancelRestrictions + return s +} + +// Do send request +func (s *CancelOrderService) Do(ctx context.Context, opts ...RequestOption) (res *CancelOrderResponse, err error) { + r := &request{ + method: http.MethodDelete, + endpoint: "/api/v3/order", + secType: secTypeSigned, + } + m := params{ + "symbol": s.symbol, + } + if s.orderId != nil { + m["orderId"] = *s.orderId + } + if s.origClientOrderId != nil { + m["origClientOrderId"] = *s.origClientOrderId + } + if s.newClientOrderId != nil { + m["newClientOrderId"] = *s.newClientOrderId + } + if s.cancelRestrictions != nil { + m["cancelRestrictions"] = *s.cancelRestrictions + } + r.setParams(m) + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return nil, err + } + res = new(CancelOrderResponse) + err = json.Unmarshal(data, res) + if err != nil { + return nil, err + } + return res, nil +} + +// Binance Cancel all open orders on a symbol (DELETE /api/v3/openOrders) +// CancelOpenOrdersService cancel open orders +type CancelOpenOrdersService struct { + c *Client + symbol string +} + +// Symbol set symbol +func (s *CancelOpenOrdersService) Symbol(symbol string) *CancelOpenOrdersService { + s.symbol = symbol + return s +} + +// Do send request +func (s *CancelOpenOrdersService) Do(ctx context.Context, opts ...RequestOption) (res []*CancelOrderResponse, err error) { + r := &request{ + method: http.MethodDelete, + endpoint: "/api/v3/openOrders", + secType: secTypeSigned, + } + m := params{ + "symbol": s.symbol, + } + r.setParams(m) + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return nil, err + } + res = make([]*CancelOrderResponse, 0) + err = json.Unmarshal(data, &res) + if err != nil { + return nil, err + } + return res, nil +} + +// Create CancelOrderResponse +type CancelOrderResponse struct { + Symbol string `json:"symbol"` + OrigClientOrderId string `json:"origClientOrderId"` + OrderId int64 `json:"orderId"` + OrderListId int64 `json:"orderListId"` + ClientOrderId string `json:"clientOrderId"` + Price string `json:"price"` + OrigQty string `json:"origQty"` + ExecutedQty string `json:"executedQty"` + CumulativeQuoteQty string `json:"cumulativeQuoteQty"` + Status string `json:"status"` + TimeInForce string `json:"timeInForce"` + Type string `json:"type"` + Side string `json:"side"` + SelfTradePrevention string `json:"selfTradePrevention"` +} + +// Query Order (USER_DATA) +// Binance Query Order (USER_DATA) (GET /api/v3/order) +// GetOrderService get order +type GetOrderService struct { + c *Client + symbol string + orderId *int64 + origClientOrderId *string +} + +// Symbol set symbol +func (s *GetOrderService) Symbol(symbol string) *GetOrderService { + s.symbol = symbol + return s +} + +// OrderId set orderId +func (s *GetOrderService) OrderId(orderId int64) *GetOrderService { + s.orderId = &orderId + return s +} + +// OrigClientOrderId set origClientOrderId +func (s *GetOrderService) OrigClientOrderId(origClientOrderId string) *GetOrderService { + s.origClientOrderId = &origClientOrderId + return s +} + +// Do send request +func (s *GetOrderService) Do(ctx context.Context, opts ...RequestOption) (res *GetOrderResponse, err error) { + r := &request{ + method: http.MethodGet, + endpoint: "/api/v3/order", + secType: secTypeSigned, + } + m := params{ + "symbol": s.symbol, + } + if s.orderId != nil { + m["orderId"] = *s.orderId + } + if s.origClientOrderId != nil { + m["origClientOrderId"] = *s.origClientOrderId + } + r.setParams(m) + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return nil, err + } + res = new(GetOrderResponse) + err = json.Unmarshal(data, &res) + if err != nil { + return nil, err + } + return res, nil +} + +// Create GetOrderResponse +type GetOrderResponse struct { + Symbol string `json:"symbol"` + OrderId int64 `json:"orderId"` + OrderListId int64 `json:"orderListId"` + ClientOrderId string `json:"clientOrderId"` + Price string `json:"price"` + OrigQty string `json:"origQty"` + ExecutedQty string `json:"executedQty"` + CumulativeQuoteQty string `json:"cumulativeQuoteQty"` + Status string `json:"status"` + TimeInForce string `json:"timeInForce"` + Type string `json:"type"` + Side string `json:"side"` + StopPrice string `json:"stopPrice"` + IcebergQty string `json:"icebergQty"` + Time uint64 `json:"time"` + UpdateTime uint64 `json:"updateTime"` + IsWorking bool `json:"isWorking"` + WorkingTime uint64 `json:"workingTime"` + OrigQuoteOrderQty string `json:"origQuoteOrderQty"` + SelfTradePreventionMode string `json:"selfTradePreventionMode"` + PreventedMatchId string `json:"preventedMatchId"` + PreventedQuantity string `json:"preventedQuantity"` +} + +// Cancel an Existing Order and Send a New Order (TRADE) +type CancelReplaceService struct { + c *Client + symbol string + side string + orderType string + cancelReplaceMode string + timeInForce *string + quantity *float64 + quoteOrderQty *float64 + price *float64 + cancelNewClientOrderId *string + cancelOrigClientOrderId *string + cancelOrderId *int64 + newClientOrderId *string + strategyId *int32 + strategyType *int32 + stopPrice *float64 + trailingDelta *int64 + icebergQty *float64 + newOrderRespType *string + selfTradePreventionMode *string + cancelRestrictions *string +} + +// Symbol set symbol +func (s *CancelReplaceService) Symbol(symbol string) *CancelReplaceService { + s.symbol = symbol + return s +} + +// Side set side +func (s *CancelReplaceService) Side(side string) *CancelReplaceService { + s.side = side + return s +} + +// OrderType set orderType +func (s *CancelReplaceService) OrderType(orderType string) *CancelReplaceService { + s.orderType = orderType + return s +} + +// CancelReplaceMode set cancelReplaceMode +func (s *CancelReplaceService) CancelReplaceMode(cancelReplaceMode string) *CancelReplaceService { + s.cancelReplaceMode = cancelReplaceMode + return s +} + +// TimeInForce set timeInForce +func (s *CancelReplaceService) TimeInForce(timeInForce string) *CancelReplaceService { + s.timeInForce = &timeInForce + return s +} + +// Quantity set quantity +func (s *CancelReplaceService) Quantity(quantity float64) *CancelReplaceService { + s.quantity = &quantity + return s +} + +// QuoteOrderQty set quoteOrderQty +func (s *CancelReplaceService) QuoteOrderQty(quoteOrderQty float64) *CancelReplaceService { + s.quoteOrderQty = "eOrderQty + return s +} + +// Price set price +func (s *CancelReplaceService) Price(price float64) *CancelReplaceService { + s.price = &price + return s +} + +// CancelNewClientOrderId set cancelNewClientOrderId +func (s *CancelReplaceService) CancelNewClientOrderId(cancelNewClientOrderId string) *CancelReplaceService { + s.cancelNewClientOrderId = &cancelNewClientOrderId + return s +} + +// CancelOrigClientOrderId set cancelOrigClientOrderId +func (s *CancelReplaceService) CancelOrigClientOrderId(cancelOrigClientOrderId string) *CancelReplaceService { + s.cancelOrigClientOrderId = &cancelOrigClientOrderId + return s +} + +// CancelOrderId set cancelOrderId +func (s *CancelReplaceService) CancelOrderId(cancelOrderId int64) *CancelReplaceService { + s.cancelOrderId = &cancelOrderId + return s +} + +// NewClientOrderId set newClientOrderId +func (s *CancelReplaceService) NewClientOrderId(newClientOrderId string) *CancelReplaceService { + s.newClientOrderId = &newClientOrderId + return s +} + +// StrategyId set strategyId +func (s *CancelReplaceService) StrategyId(strategyId int32) *CancelReplaceService { + s.strategyId = &strategyId + return s +} + +// StrategyType set strategyType +func (s *CancelReplaceService) StrategyType(strategyType int32) *CancelReplaceService { + s.strategyType = &strategyType + return s +} + +// StopPrice set stopPrice +func (s *CancelReplaceService) StopPrice(stopPrice float64) *CancelReplaceService { + s.stopPrice = &stopPrice + return s +} + +// TrailingDelta set trailingDelta +func (s *CancelReplaceService) TrailingDelta(trailingDelta int64) *CancelReplaceService { + s.trailingDelta = &trailingDelta + return s +} + +// IcebergQty set icebergQty +func (s *CancelReplaceService) IcebergQty(icebergQty float64) *CancelReplaceService { + s.icebergQty = &icebergQty + return s +} + +// NewOrderRespType set newOrderRespType +func (s *CancelReplaceService) NewOrderRespType(newOrderRespType string) *CancelReplaceService { + s.newOrderRespType = &newOrderRespType + return s +} + +// SelfTradePreventionMode set selfTradePreventionMode +func (s *CancelReplaceService) SelfTradePreventionMode(selfTradePreventionMode string) *CancelReplaceService { + s.selfTradePreventionMode = &selfTradePreventionMode + return s +} + +// CancelRestrictions set cancelRestrictions +func (s *CancelReplaceService) CancelRestrictions(cancelRestrictions string) *CancelReplaceService { + s.cancelRestrictions = &cancelRestrictions + return s +} + +// Do send request +func (s *CancelReplaceService) Do(ctx context.Context, opts ...RequestOption) (res *CancelReplaceResponse, err error) { + r := &request{ + method: http.MethodPost, + endpoint: "/api/v3/order/cancelReplace", + secType: secTypeSigned, + } + m := params{ + "symbol": s.symbol, + "side": s.side, + "type": s.orderType, + "cancelReplaceMode": s.cancelReplaceMode, + } + if s.timeInForce != nil { + m["timeInForce"] = *s.timeInForce + } + if s.quantity != nil { + m["quantity"] = *s.quantity + } + if s.quoteOrderQty != nil { + m["quoteOrderQty"] = *s.quoteOrderQty + } + if s.price != nil { + m["price"] = *s.price + } + if s.cancelNewClientOrderId != nil { + m["cancelNewClientOrderId"] = *s.cancelNewClientOrderId + } + if s.cancelOrigClientOrderId != nil { + m["cancelOrigClientOrderId"] = *s.cancelOrigClientOrderId + } + if s.cancelOrderId != nil { + m["cancelOrderId"] = *s.cancelOrderId + } + if s.newClientOrderId != nil { + m["newClientOrderId"] = *s.newClientOrderId + } + if s.strategyId != nil { + m["strategyId"] = *s.strategyId + } + if s.strategyType != nil { + m["strategyType"] = *s.strategyType + } + if s.stopPrice != nil { + m["stopPrice"] = *s.stopPrice + } + if s.trailingDelta != nil { + m["trailingDelta"] = *s.trailingDelta + } + if s.icebergQty != nil { + m["icebergQty"] = *s.icebergQty + } + if s.newOrderRespType != nil { + m["newOrderRespType"] = *s.newOrderRespType + } + if s.selfTradePreventionMode != nil { + m["selfTradePreventionMode"] = *s.selfTradePreventionMode + } + if s.cancelRestrictions != nil { + m["cancelRestrictions"] = *s.cancelRestrictions + } + r.setParams(m) + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return nil, err + } + res = new(CancelReplaceResponse) + err = json.Unmarshal(data, res) + if err != nil { + return nil, err + } + return res, nil +} + +// Create CancelReplaceResponse +type CancelReplaceResponse struct { + CancelResult string `json:"cancelResult"` + NewOrderResult string `json:"newOrderResult"` + CancelResponse struct { + Symbol string `json:"symbol"` + OrigClientOrderId string `json:"origClientOrderId"` + OrderId int64 `json:"orderId"` + OrderListId int64 `json:"orderListId"` + ClientOrderId string `json:"clientOrderId"` + Price string `json:"price"` + OrigQty string `json:"origQty"` + ExecutedQty string `json:"executedQty"` + CumulativeQuoteQty string `json:"cumulativeQuoteQty"` + Status string `json:"status"` + TimeInForce string `json:"timeInForce"` + Type string `json:"type"` + Side string `json:"side"` + SelfTradePreventionMode string `json:"selfTradePreventionMode"` + } `json:"cancelResponse"` + NewOrderResponse struct { + Symbol string `json:"symbol"` + OrderId int64 `json:"orderId"` + OrderListId int64 `json:"orderListId"` + ClientOrderId string `json:"clientOrderId"` + TransactTime uint64 `json:"transactTime"` + Price string `json:"price"` + OrigQty string `json:"origQty"` + ExecutedQty string `json:"executedQty"` + CumulativeQuoteQty string `json:"cumulativeQuoteQty"` + Status string `json:"status"` + TimeInForce string `json:"timeInForce"` + Type string `json:"type"` + Side string `json:"side"` + Fills []string `json:"fills"` + SelfTradePreventionMode string `json:"selfTradePreventionMode"` + } `json:"newOrderResponse"` +} + +// Binance Get current open orders (GET /api/v3/openOrders) +// GetOpenOrdersService get open orders +type GetOpenOrdersService struct { + c *Client + symbol *string +} + +// Symbol set symbol +func (s *GetOpenOrdersService) Symbol(symbol string) *GetOpenOrdersService { + s.symbol = &symbol + return s +} + +// Do send request +func (s *GetOpenOrdersService) Do(ctx context.Context, opts ...RequestOption) (res []*NewOpenOrdersResponse, err error) { + r := &request{ + method: http.MethodGet, + endpoint: "/api/v3/openOrders", + secType: secTypeSigned, + } + if s.symbol != nil { + r.setParam("symbol", *s.symbol) + } + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return nil, err + } + res = make([]*NewOpenOrdersResponse, 0) + err = json.Unmarshal(data, &res) + if err != nil { + return nil, err + } + return res, nil +} + +// Create NewOpenOrdersResponse +type NewOpenOrdersResponse struct { + Symbol string `json:"symbol"` + OrderId int64 `json:"orderId"` + OrderListId int64 `json:"orderListId"` + ClientOrderId string `json:"clientOrderId"` + Price string `json:"price"` + OrigQty string `json:"origQty"` + ExecutedQty string `json:"executedQty"` + CumulativeQuoteQty string `json:"cumulativeQuoteQty"` + Status string `json:"status"` + TimeInForce string `json:"timeInForce"` + Type string `json:"type"` + Side string `json:"side"` + StopPrice string `json:"stopPrice"` + IcebergQty string `json:"icebergQty"` + Time uint64 `json:"time"` + UpdateTime uint64 `json:"updateTime"` + IsWorking bool `json:"isWorking"` + WorkingTime uint64 `json:"workingTime"` + OrigQuoteOrderQty string `json:"origQuoteOrderQty"` + SelfTradePreventionMode string `json:"selfTradePreventionMode"` +} + +// Binance Get all account orders; active, canceled, or filled (GET /api/v3/allOrders) +// GetAllOrdersService get all orders +type GetAllOrdersService struct { + c *Client + symbol string + orderId *int64 + startTime *uint64 + endTime *uint64 + limit *int +} + +// Symbol set symbol +func (s *GetAllOrdersService) Symbol(symbol string) *GetAllOrdersService { + s.symbol = symbol + return s +} + +// OrderId set orderId +func (s *GetAllOrdersService) OrderId(orderId int64) *GetAllOrdersService { + s.orderId = &orderId + return s +} + +// StartTime set startTime +func (s *GetAllOrdersService) StartTime(startTime uint64) *GetAllOrdersService { + s.startTime = &startTime + return s +} + +// EndTime set endTime +func (s *GetAllOrdersService) EndTime(endTime uint64) *GetAllOrdersService { + s.endTime = &endTime + return s +} + +// Limit set limit +func (s *GetAllOrdersService) Limit(limit int) *GetAllOrdersService { + s.limit = &limit + return s +} + +// Do send request +func (s *GetAllOrdersService) Do(ctx context.Context, opts ...RequestOption) (res []*NewAllOrdersResponse, err error) { + r := &request{ + method: http.MethodGet, + endpoint: "/api/v3/allOrders", + secType: secTypeSigned, + } + m := params{ + "symbol": s.symbol, + } + if s.orderId != nil { + m["orderId"] = *s.orderId + } + if s.startTime != nil { + m["startTime"] = *s.startTime + } + if s.endTime != nil { + m["endTime"] = *s.endTime + } + if s.limit != nil { + m["limit"] = *s.limit + } + r.setParams(m) + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return nil, err + } + res = make([]*NewAllOrdersResponse, 0) + err = json.Unmarshal(data, &res) + if err != nil { + return nil, err + } + return res, nil +} + +// Create NewAllOrdersResponse +type NewAllOrdersResponse struct { + Symbol string `json:"symbol"` + ListClientOrderId string `json:"listClientOrderId"` + OrderId int64 `json:"orderId"` + OrderListId int64 `json:"orderListId"` + ClientOrderId string `json:"clientOrderId"` + Price string `json:"price"` + OrigQty string `json:"origQty"` + ExecutedQty string `json:"executedQty"` + CumulativeQuoteQty string `json:"cumulativeQuoteQty"` + Status string `json:"status"` + TimeInForce string `json:"timeInForce"` + Type string `json:"type"` + Side string `json:"side"` + StopPrice string `json:"stopPrice"` + IcebergQty string `json:"icebergQty"` + Time uint64 `json:"time"` + UpdateTime uint64 `json:"updateTime"` + IsWorking bool `json:"isWorking"` + OrigQuoteOrderQty string `json:"origQuoteOrderQty"` + WorkingTime uint64 `json:"workingTime"` + SelfTradePreventionMode string `json:"selfTradePreventionMode"` + PreventedMatchId int64 `json:"preventedMatchId"` + PreventedQuantity string `json:"preventedQuantity"` +} + +// Binance New OCO (TRADE) (POST /api/v3/order/oco) +// NewOCOService create new OCO order +type NewOCOService struct { + c *Client + symbol string + listClientOrderId *string + side string + quantity float64 + limitClientOrderId *string + limitStrategyId *int + limitStrategyType *int + price float64 + limitIcebergQty *float64 + trailingDelta *int + stopClientOrderId *string + stopPrice float64 + stopStrategyId *int + stopStrategyType *int + stopLimitPrice *float64 + stopIcebergQty *float64 + stopLimitTimeInForce *string + newOrderRespType *string + selfTradePreventionMode *string +} + +// Symbol set symbol +func (s *NewOCOService) Symbol(symbol string) *NewOCOService { + s.symbol = symbol + return s +} + +// ListClientOrderId set listClientOrderId +func (s *NewOCOService) ListClientOrderId(listClientOrderId string) *NewOCOService { + s.listClientOrderId = &listClientOrderId + return s +} + +// Side set side +func (s *NewOCOService) Side(side string) *NewOCOService { + s.side = side + return s +} + +// Quantity set quantity +func (s *NewOCOService) Quantity(quantity float64) *NewOCOService { + s.quantity = quantity + return s +} + +// LimitClientOrderId set limitClientOrderId +func (s *NewOCOService) LimitClientOrderId(limitClientOrderId string) *NewOCOService { + s.limitClientOrderId = &limitClientOrderId + return s +} + +// LimitStrategyId set limitStrategyId +func (s *NewOCOService) LimitStrategyId(limitStrategyId int) *NewOCOService { + s.limitStrategyId = &limitStrategyId + return s +} + +// LimitStrategyType set limitStrategyType +func (s *NewOCOService) LimitStrategyType(limitStrategyType int) *NewOCOService { + s.limitStrategyType = &limitStrategyType + return s +} + +// Price set price +func (s *NewOCOService) Price(price float64) *NewOCOService { + s.price = price + return s +} + +// LimitIcebergQty set limitIcebergQty +func (s *NewOCOService) LimitIcebergQty(limitIcebergQty float64) *NewOCOService { + s.limitIcebergQty = &limitIcebergQty + return s +} + +// TrailingDelta set trailingDelta +func (s *NewOCOService) TrailingDelta(trailingDelta int) *NewOCOService { + s.trailingDelta = &trailingDelta + return s +} + +// StopClientOrderId set stopClientOrderId +func (s *NewOCOService) StopClientOrderId(stopClientOrderId string) *NewOCOService { + s.stopClientOrderId = &stopClientOrderId + return s +} + +// StopPrice set stopPrice +func (s *NewOCOService) StopPrice(stopPrice float64) *NewOCOService { + s.stopPrice = stopPrice + return s +} + +// StopStrategyId set stopStrategyId +func (s *NewOCOService) StopStrategyId(stopStrategyId int) *NewOCOService { + s.stopStrategyId = &stopStrategyId + return s +} + +// StopStrategyType set stopStrategyType +func (s *NewOCOService) StopStrategyType(stopStrategyType int) *NewOCOService { + s.stopStrategyType = &stopStrategyType + return s +} + +// StopLimitPrice set stopLimitPrice +func (s *NewOCOService) StopLimitPrice(stopLimitPrice float64) *NewOCOService { + s.stopLimitPrice = &stopLimitPrice + return s +} + +// StopIcebergQty set stopIcebergQty +func (s *NewOCOService) StopIcebergQty(stopIcebergQty float64) *NewOCOService { + s.stopIcebergQty = &stopIcebergQty + return s +} + +// StopLimitTimeInForce set stopLimitTimeInForce +func (s *NewOCOService) StopLimitTimeInForce(stopLimitTimeInForce string) *NewOCOService { + s.stopLimitTimeInForce = &stopLimitTimeInForce + return s +} + +// NewOrderRespType set newOrderRespType +func (s *NewOCOService) NewOrderRespType(newOrderRespType string) *NewOCOService { + s.newOrderRespType = &newOrderRespType + return s +} + +// selfTradePreventionMode set selfTradePreventionMode +func (s *NewOCOService) SelfTradePreventionMode(selfTradePreventionMode string) *NewOCOService { + s.selfTradePreventionMode = &selfTradePreventionMode + return s +} + +// Do send request +func (s *NewOCOService) Do(ctx context.Context, opts ...RequestOption) (res *OrderOCOResponse, err error) { + r := &request{ + method: http.MethodPost, + endpoint: "/api/v3/order/oco", + secType: secTypeSigned, + } + m := params{ + "symbol": s.symbol, + "side": s.side, + "quantity": s.quantity, + "price": s.price, + "stopPrice": s.stopPrice, + } + if s.listClientOrderId != nil { + m["listClientOrderId"] = *s.listClientOrderId + } + if s.limitClientOrderId != nil { + m["limitClientOrderId"] = *s.limitClientOrderId + } + if s.limitStrategyId != nil { + m["limitStrategyId"] = *s.limitStrategyId + } + if s.limitStrategyType != nil { + m["limitStrategyType"] = *s.limitStrategyType + } + if s.limitIcebergQty != nil { + m["limitIcebergQty"] = *s.limitIcebergQty + } + if s.trailingDelta != nil { + m["trailingDelta"] = *s.trailingDelta + } + if s.stopClientOrderId != nil { + m["stopClientOrderId"] = *s.stopClientOrderId + } + if s.stopStrategyId != nil { + m["stopStrategyId"] = *s.stopStrategyId + } + if s.stopStrategyType != nil { + m["stopStrategyType"] = *s.stopStrategyType + } + if s.stopLimitPrice != nil { + m["stopLimitPrice"] = *s.stopLimitPrice + } + if s.stopIcebergQty != nil { + m["stopIcebergQty"] = *s.stopIcebergQty + } + if s.stopLimitTimeInForce != nil { + m["stopLimitTimeInForce"] = *s.stopLimitTimeInForce + } + if s.newOrderRespType != nil { + m["newOrderRespType"] = *s.newOrderRespType + } + if s.selfTradePreventionMode != nil { + m["selfTradePreventionMode"] = *s.selfTradePreventionMode + } + r.setParams(m) + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return nil, err + } + res = new(OrderOCOResponse) + err = json.Unmarshal(data, res) + if err != nil { + return nil, err + } + return res, nil +} + +type OrderOCOResponse struct { + OrderListId int64 `json:"orderListId"` + ContingencyType string `json:"contingencyType"` + ListStatusType string `json:"listStatusType"` + ListOrderStatus string `json:"listOrderStatus"` + ListClientOrderId string `json:"listClientOrderId"` + TransactionTime uint64 `json:"transactionTime"` + Symbol string `json:"symbol"` + Orders []struct { + Symbol string `json:"symbol"` + OrderId int64 `json:"orderId"` + ClientOrderId string `json:"clientOrderId"` + } `json:"orders"` + OrderReports []struct { + Symbol string `json:"symbol"` + OrderId int64 `json:"orderId"` + OrderListId int64 `json:"orderListId"` + ClientOrderId string `json:"clientOrderId"` + TransactTime uint64 `json:"transactTime"` + Price float64 `json:"price"` + OrigQty float64 `json:"origQty"` + ExecutedQty float64 `json:"executedQty"` + CummulativeQuoteQty float64 `json:"cummulativeQuoteQty"` + Status string `json:"status"` + TimeInForce string `json:"timeInForce"` + Type string `json:"type"` + Side string `json:"side"` + StopPrice string `json:"stopPrice"` + WorkingTime uint64 `json:"workingTime"` + SelfTradePreventionMode string `json:"selfTradePreventionMode"` + } `json:"orderReports"` +} + +// Binance Cancel OCO (TRADE) (DELETE /api/v3/orderList) +// CancelOCOService cancel OCO order +type CancelOCOService struct { + c *Client + symbol string + orderListId *int + listClientOrderId *string + newClientOrderId *string +} + +// Symbol set symbol +func (s *CancelOCOService) Symbol(symbol string) *CancelOCOService { + s.symbol = symbol + return s +} + +// OrderListId set orderListId +func (s *CancelOCOService) OrderListId(orderListId int) *CancelOCOService { + s.orderListId = &orderListId + return s +} + +// ListClientId set listClientId +func (s *CancelOCOService) ListClientOrderId(ListClientOrderId string) *CancelOCOService { + s.listClientOrderId = &ListClientOrderId + return s +} + +// NewClientOrderId set newClientOrderId +func (s *CancelOCOService) NewClientOrderId(newClientOrderId string) *CancelOCOService { + s.newClientOrderId = &newClientOrderId + return s +} + +// Do send request +func (s *CancelOCOService) Do(ctx context.Context, opts ...RequestOption) (res *OrderOCOResponse, err error) { + r := &request{ + method: http.MethodDelete, + endpoint: "/api/v3/orderList", + secType: secTypeSigned, + } + m := params{ + "symbol": s.symbol, + } + if s.orderListId != nil { + m["orderListId"] = *s.orderListId + } + if s.listClientOrderId != nil { + m["listClientOrderId"] = *s.listClientOrderId + } + if s.newClientOrderId != nil { + m["newClientOrderId"] = *s.newClientOrderId + } + r.setParams(m) + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return nil, err + } + res = new(OrderOCOResponse) + err = json.Unmarshal(data, res) + if err != nil { + return nil, err + } + return res, nil +} + +// Binance Query OCO (USER_DATA) (GET /api/v3/orderList) +// QueryOCOService query OCO order +type QueryOCOService struct { + c *Client + orderListId *int64 + origClientOrderId *string +} + +// OrderListId set orderListId +func (s *QueryOCOService) OrderListId(orderListId int64) *QueryOCOService { + s.orderListId = &orderListId + return s +} + +// OrigClientOrderId set origClientOrderId +func (s *QueryOCOService) OrigClientOrderId(origClientOrderId string) *QueryOCOService { + s.origClientOrderId = &origClientOrderId + return s +} + +// Do send request +func (s *QueryOCOService) Do(ctx context.Context, opts ...RequestOption) (res *OCOResponse, err error) { + r := &request{ + method: http.MethodGet, + endpoint: "/api/v3/orderList", + secType: secTypeSigned, + } + if s.orderListId != nil { + r.setParam("orderListId", *s.orderListId) + } + if s.origClientOrderId != nil { + r.setParam("origClientOrderId", s.origClientOrderId) + } + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return nil, err + } + res = new(OCOResponse) + err = json.Unmarshal(data, res) + if err != nil { + return nil, err + } + return res, nil +} + +// Binance Query all OCO (USER_DATA) (GET /api/v3/allOrderList) +// QueryAllOCOService query all OCO order +type QueryAllOCOService struct { + c *Client + fromId *int64 + startTime *uint64 + endTime *uint64 + limit *int +} + +// FromId set fromId +func (s *QueryAllOCOService) FromId(fromId int64) *QueryAllOCOService { + s.fromId = &fromId + return s +} + +// StartTime set startTime +func (s *QueryAllOCOService) StartTime(startTime uint64) *QueryAllOCOService { + s.startTime = &startTime + return s +} + +// EndTime set endTime +func (s *QueryAllOCOService) EndTime(endTime uint64) *QueryAllOCOService { + s.endTime = &endTime + return s +} + +// Limit set limit +func (s *QueryAllOCOService) Limit(limit int) *QueryAllOCOService { + s.limit = &limit + return s +} + +// Do send request +func (s *QueryAllOCOService) Do(ctx context.Context, opts ...RequestOption) (res *OCOResponse, err error) { + r := &request{ + method: http.MethodGet, + endpoint: "/api/v3/allOrderList", + secType: secTypeSigned, + } + if s.fromId != nil { + r.setParam("fromId", *s.fromId) + } + if s.startTime != nil { + r.setParam("startTime", *s.startTime) + } + if s.endTime != nil { + r.setParam("endTime", *s.endTime) + } + if s.limit != nil { + r.setParam("limit", *s.limit) + } + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return nil, err + } + res = new(OCOResponse) + err = json.Unmarshal(data, res) + if err != nil { + return nil, err + } + return res, nil +} + +// Create OCOResponse +type OCOResponse struct { + OrderListId int64 `json:"orderListId"` + ContingencyType string `json:"contingencyType"` + ListStatusType string `json:"listStatusType"` + ListOrderStatus string `json:"listOrderStatus"` + ListClientOrderId string `json:"listClientOrderId"` + TransactionTime uint64 `json:"transactionTime"` + Symbol string `json:"symbol"` + Orders []struct { + Symbol string `json:"symbol"` + OrderId int64 `json:"orderId"` + ClientOrderId string `json:"clientOrderId"` + } `json:"orders"` +} + +// Binance Query open OCO (USER_DATA) (GET /api/v3/openOrderList) +// QueryOpenOCOService query open OCO order +type QueryOpenOCOService struct { + c *Client +} + +// Do send request +func (s *QueryOpenOCOService) Do(ctx context.Context, opts ...RequestOption) (res *OCOResponse, err error) { + r := &request{ + method: http.MethodGet, + endpoint: "/api/v3/openOrderList", + secType: secTypeSigned, + } + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return nil, err + } + res = new(OCOResponse) + err = json.Unmarshal(data, res) + if err != nil { + return nil, err + } + return res, nil +} + +// Binance Account Information (USER_DATA) (GET /api/v3/account) +// GetAccountService get account information +type GetAccountService struct { + c *Client +} + +// Do send request +func (s *GetAccountService) Do(ctx context.Context, opts ...RequestOption) (res *AccountResponse, err error) { + r := &request{ + method: http.MethodGet, + endpoint: "/api/v3/account", + secType: secTypeSigned, + } + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return nil, err + } + res = new(AccountResponse) + err = json.Unmarshal(data, res) + if err != nil { + return nil, err + } + return res, nil +} + +// Create AccountResponse +type AccountResponse struct { + MakerCommission int64 `json:"makerCommission"` + TakerCommission int64 `json:"takerCommission"` + BuyerCommission int64 `json:"buyerCommission"` + SellerCommission int64 `json:"sellerCommission"` + CanTrade bool `json:"canTrade"` + CanWithdraw bool `json:"canWithdraw"` + CanDeposit bool `json:"canDeposit"` + UpdateTime uint64 `json:"updateTime"` + AccountType string `json:"accountType"` + Balances []Balance `json:"balances"` + Permissions []string `json:"permissions"` +} + +// Balance define user balance of your account +type Balance struct { + Asset string `json:"asset"` + Free string `json:"free"` + Locked string `json:"locked"` +} + +// Binance Get trades for a specific account and symbol (USER_DATA) (GET /api/v3/myTrades) +// GetMyTradesService get trades for a specific account and symbol +type GetMyTradesService struct { + c *Client + symbol string + orderId *int64 + startTime *uint64 + endTime *uint64 + fromId *int64 + limit *int +} + +// Symbol set symbol +func (s *GetMyTradesService) Symbol(symbol string) *GetMyTradesService { + s.symbol = symbol + return s +} + +// OrderId set orderId +func (s *GetMyTradesService) OrderId(orderId int64) *GetMyTradesService { + s.orderId = &orderId + return s +} + +// StartTime set startTime +func (s *GetMyTradesService) StartTime(startTime uint64) *GetMyTradesService { + s.startTime = &startTime + return s +} + +// EndTime set endTime +func (s *GetMyTradesService) EndTime(endTime uint64) *GetMyTradesService { + s.endTime = &endTime + return s +} + +// FromId set fromId +func (s *GetMyTradesService) FromId(fromId int64) *GetMyTradesService { + s.fromId = &fromId + return s +} + +// Limit set limit +func (s *GetMyTradesService) Limit(limit int) *GetMyTradesService { + s.limit = &limit + return s +} + +// Do send request +func (s *GetMyTradesService) Do(ctx context.Context, opts ...RequestOption) (res []*AccountTradeListResponse, err error) { + r := &request{ + method: http.MethodGet, + endpoint: "/api/v3/myTrades", + secType: secTypeSigned, + } + m := params{ + "symbol": s.symbol, + } + if s.orderId != nil { + m["orderId"] = *s.orderId + } + if s.startTime != nil { + m["startTime"] = *s.startTime + } + if s.endTime != nil { + m["endTime"] = *s.endTime + } + if s.fromId != nil { + m["fromId"] = *s.fromId + } + if s.limit != nil { + m["limit"] = *s.limit + } + r.setParams(m) + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return []*AccountTradeListResponse{}, err + } + res = make([]*AccountTradeListResponse, 0) + err = json.Unmarshal(data, &res) + if err != nil { + return []*AccountTradeListResponse{}, err + } + return res, nil +} + +//type AccountTradeListResponse []AccountTrade + +type AccountTradeListResponse struct { + Id int64 `json:"id"` + Symbol string `json:"symbol"` + OrderId int64 `json:"orderId"` + OrderListId int64 `json:"orderListId"` + Price string `json:"price"` + Quantity string `json:"qty"` + QuoteQuantity string `json:"quoteQty"` + Commission string `json:"commission"` + CommissionAsset string `json:"commissionAsset"` + Time uint64 `json:"time"` + IsBuyer bool `json:"isBuyer"` + IsMaker bool `json:"isMaker"` + IsBestMatch bool `json:"isBestMatch"` +} + +// Query Current Order Count Usage (TRADE) +// GetQueryCurrentOrderCountUsageService query current order count usage +type GetQueryCurrentOrderCountUsageService struct { + c *Client +} + +// Do send request +func (s *GetQueryCurrentOrderCountUsageService) Do(ctx context.Context, opts ...RequestOption) (res []*QueryCurrentOrderCountUsageResponse, err error) { + r := &request{ + method: http.MethodGet, + endpoint: "/api/v3/rateLimit/order", + secType: secTypeSigned, + } + res = make([]*QueryCurrentOrderCountUsageResponse, 0) + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return res, err + } + err = json.Unmarshal(data, &res) + if err != nil { + return res, err + } + return res, nil +} + +// Create QueryCurrentOrderCountUsageResponse +type QueryCurrentOrderCountUsageResponse struct { + RateLimitType string `json:"rateLimitType"` + Interval string `json:"interval"` + IntervalNum int `json:"intervalNum"` + Limit int `json:"limit"` + Count int `json:"count"` +} + +// Query Prevented Matches (USER_DATA) +// GetQueryPreventedMatchesService query prevented matches +type GetQueryPreventedMatchesService struct { + c *Client + symbol string + preventMatchId *int64 + orderId *int64 + fromPreventedMatchId *int64 + limit *int +} + +// Symbol set symbol +func (s *GetQueryPreventedMatchesService) Symbol(symbol string) *GetQueryPreventedMatchesService { + s.symbol = symbol + return s +} + +// PreventMatchId set preventMatchId +func (s *GetQueryPreventedMatchesService) PreventMatchId(preventMatchId int64) *GetQueryPreventedMatchesService { + s.preventMatchId = &preventMatchId + return s +} + +// OrderId set orderId +func (s *GetQueryPreventedMatchesService) OrderId(orderId int64) *GetQueryPreventedMatchesService { + s.orderId = &orderId + return s +} + +// FromPreventedMatchId set fromPreventedMatchId +func (s *GetQueryPreventedMatchesService) FromPreventedMatchId(fromPreventedMatchId int64) *GetQueryPreventedMatchesService { + s.fromPreventedMatchId = &fromPreventedMatchId + return s +} + +// Limit set limit +func (s *GetQueryPreventedMatchesService) Limit(limit int) *GetQueryPreventedMatchesService { + s.limit = &limit + return s +} + +// Do send request +func (s *GetQueryPreventedMatchesService) Do(ctx context.Context, opts ...RequestOption) (res *QueryPreventedMatchesResponse, err error) { + r := &request{ + method: http.MethodGet, + endpoint: "/api/v3/myPreventedMatches", + secType: secTypeSigned, + } + m := params{ + "symbol": s.symbol, + } + if s.preventMatchId != nil { + m["preventedMatchId"] = *s.preventMatchId + } + if s.orderId != nil { + m["orderId"] = *s.orderId + } + if s.fromPreventedMatchId != nil { + m["fromPreventedMatchId"] = *s.fromPreventedMatchId + } + if s.limit != nil { + m["limit"] = *s.limit + } + r.setParams(m) + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return nil, err + } + res = new(QueryPreventedMatchesResponse) + err = json.Unmarshal(data, res) + if err != nil { + return nil, err + } + return res, nil +} + +// Create QueryPreventedMatchesResponse +type QueryPreventedMatchesResponse struct { + PreventedMatches []struct { + Symbol string `json:"symbol"` + PreventedMatchId int64 `json:"preventedMatchId"` + TakerOrderId int64 `json:"takerOrderId"` + MakerOrderId int64 `json:"makerOrderId"` + TradeGroupId int64 `json:"tradeGroupId"` + SelfTradePreventionMode string `json:"selfTradePreventionMode"` + Price string `json:"price"` + MakerPreventedQuantity string `json:"makerPreventedQuantity"` + TransactTime uint64 `json:"transactTime"` + } `json:"preventedMatches"` +} diff --git a/account_test.go b/account_test.go new file mode 100644 index 0000000..b954659 --- /dev/null +++ b/account_test.go @@ -0,0 +1,803 @@ +package binance_connector + +import ( + "context" + "testing" + + "github.com/stretchr/testify/suite" +) + +type accountTestSuite struct { + baseTestSuite +} + +func TestAccount(t *testing.T) { + suite.Run(t, new(accountTestSuite)) +} + +func (s *accountTestSuite) TestGetAccountInfo() { + data := []byte(`{ + "makerCommission": 15, + "takerCommission": 15, + "buyerCommission": 0, + "sellerCommission": 0, + "canTrade": true, + "canWithdraw": true, + "canDeposit": true, + "updateTime": 123456789, + "accountType": "SPOT", + "balances": [ + { + "asset": "BTC", + "free": "4723846.89208129", + "locked": "0.00000000" + }, + { + "asset": "LTC", + "free": "4763368.68006011", + "locked": "0.00000000" + } + ], + "permissions": [ + "SPOT" + ] + }`) + s.mockDo(data, nil) + defer s.assertDo() + s.assertReq(func(r *request) { + e := newSignedRequest() + s.assertRequestEqual(e, r) + }) + + res, err := s.client.NewGetAccountService().Do(newContext()) + s.r().NoError(err) + e := &AccountResponse{ + MakerCommission: 15, + TakerCommission: 15, + BuyerCommission: 0, + SellerCommission: 0, + CanTrade: true, + CanWithdraw: true, + CanDeposit: true, + UpdateTime: 123456789, + AccountType: "SPOT", + Balances: []Balance{ + { + Asset: "BTC", + Free: "4723846.89208129", + Locked: "0.00000000", + }, + { + Asset: "LTC", + Free: "4763368.68006011", + Locked: "0.00000000", + }, + }, + Permissions: []string{"SPOT"}, + } + s.assertAccountEqual(e, res) +} + +func (s *accountTestSuite) assertAccountEqual(e, a *AccountResponse) { + r := s.r() + r.Equal(e.MakerCommission, a.MakerCommission, "MakerCommission") + r.Equal(e.TakerCommission, a.TakerCommission, "TakerCommission") + r.Equal(e.BuyerCommission, a.BuyerCommission, "BuyerCommission") + r.Equal(e.SellerCommission, a.SellerCommission, "SellerCommission") + r.Equal(e.CanTrade, a.CanTrade, "CanTrade") + r.Equal(e.CanWithdraw, a.CanWithdraw, "CanWithdraw") + r.Equal(e.CanDeposit, a.CanDeposit, "CanDeposit") + r.Len(a.Balances, len(e.Balances)) + for i := 0; i < len(a.Balances); i++ { + r.Equal(e.Balances[i].Asset, a.Balances[i].Asset, "Asset") + r.Equal(e.Balances[i].Free, a.Balances[i].Free, "Free") + r.Equal(e.Balances[i].Locked, a.Balances[i].Locked, "Locked") + } +} + +func (s *accountTestSuite) TestGetMyTrades() { + data := []byte(`[ + { + "symbol": "BNBBTC", + "id": 28457, + "orderId": 12345, + "orderListId": -1, + "price": "4.00000100", + "qty": "12.00000000", + "quoteQty": "48.000012", + "commission": "10.10000000", + "commissionAsset": "BNB", + "time": 1499865549590, + "isBuyer": true, + "isMaker": false, + "isBestMatch": true + } + ]`) + s.mockDo(data, nil) + defer s.assertDo() + + symbol := "BNBBTC" + limit := 3 + fromID := int64(1) + startTime := uint64(1499865549590) + endTime := uint64(1499865549590) + s.assertReq(func(r *request) { + e := newSignedRequest().setParams(params{ + "symbol": symbol, + "startTime": startTime, + "endTime": endTime, + "limit": limit, + "fromId": fromID, + }) + s.assertRequestEqual(e, r) + }) + + trades, err := s.client.NewGetMyTradesService().Symbol(symbol). + StartTime(startTime).EndTime(endTime). + Limit(limit).FromId(fromID).Do(newContext()) + r := s.r() + r.NoError(err) + r.Len(trades, 1) + e := &AccountTradeListResponse{ + Id: 28457, + Symbol: "BNBBTC", + OrderId: 12345, + OrderListId: -1, + Price: "4.00000100", + Quantity: "12.00000000", + QuoteQuantity: "48.000012", + Commission: "10.10000000", + CommissionAsset: "BNB", + Time: 1499865549590, + IsBuyer: true, + IsMaker: false, + IsBestMatch: true, + } + s.assertMyTradesEqual(e, trades[0]) +} + +func (s *baseTestSuite) assertMyTradesEqual(e, a *AccountTradeListResponse) { + r := s.r() + r.Equal(e.Id, a.Id, "ID") + r.Equal(e.Symbol, a.Symbol, "Symbol") + r.Equal(e.OrderId, a.OrderId, "OrderID") + r.Equal(e.OrderListId, a.OrderListId, "OrderListId") + r.Equal(e.Price, a.Price, "Price") + r.Equal(e.Quantity, a.Quantity, "Quantity") + r.Equal(e.QuoteQuantity, a.QuoteQuantity, "QuoteQuantity") + r.Equal(e.Commission, a.Commission, "Commission") + r.Equal(e.CommissionAsset, a.CommissionAsset, "CommissionAsset") + r.Equal(e.Time, a.Time, "Time") + r.Equal(e.IsBuyer, a.IsBuyer, "IsBuyer") + r.Equal(e.IsMaker, a.IsMaker, "IsMaker") + r.Equal(e.IsBestMatch, a.IsBestMatch, "IsBestMatch") +} + +func (s *accountTestSuite) TestNewOrder() { + data := []byte(`{ + "symbol": "BTCUSDT", + "orderId": 28 + }`) + s.mockDo(data, nil) + defer s.assertDo() + + s.assertReq(func(r *request) { + e := newSignedRequest() + e.setParam("symbol", "BTCUSDT") + e.setParam("side", "BUY") + e.setParam("type", "LIMIT") + e.setParam("quantity", 1) + e.setParam("price", 100) + s.assertRequestEqual(e, r) + }) + + ctx := context.Background() + res, err := s.client.NewCreateOrderService(). + Symbol("BTCUSDT"). + Side("BUY"). + Type("LIMIT"). + Quantity(1). + Price(100). + Do(ctx) + + s.r().NoError(err) + e := &CreateOrderResponse{ + Symbol: "BTCUSDT", + OrderId: 28, + } + s.assertCreateOrderResponseEqual(e, res) +} + +func (s *accountTestSuite) assertCreateOrderResponseEqual(e, a *CreateOrderResponse) { + r := s.r() + r.Equal(e.Symbol, a.Symbol, "Symbol") + r.Equal(e.OrderId, a.OrderId, "OrderId") +} + +func (s *accountTestSuite) TestCancelOrder() { + data := []byte(`{ + "symbol": "BTCUSDT", + "origClientOrderId": "my_order_id_123", + "orderId": 123456789, + "orderListId": 10, + "clientOrderId": "cancel_order_id_456", + "price": "0.001", + "origQty": "1.00000000", + "executedQty": "0.00000000", + "cumulativeQuoteQty": "0.00000000", + "status": "CANCELED", + "timeInForce": "GTC", + "type": "LIMIT", + "side": "BUY", + "selfTradePrevention": "DECREMENT_AND_CANCEL" + }`) + + s.mockDo(data, nil) + defer s.assertDo() + + s.assertReq(func(r *request) { + e := newSignedRequest() + e.setParam("symbol", "BTCUSDT") + e.setParam("origClientOrderId", "my_order_id_123") + e.setParam("newClientOrderId", "cancel_order_id_456") + s.assertRequestEqual(e, r) + }) + ctx := context.Background() + res, err := s.client.NewCancelOrderService().Symbol("BTCUSDT").OrigClientOrderId("my_order_id_123").NewClientOrderId("cancel_order_id_456").Do(ctx) + s.r().NoError(err) + + e := &CancelOrderResponse{ + Symbol: "BTCUSDT", + OrigClientOrderId: "my_order_id_123", + OrderId: 123456789, + OrderListId: 10, + ClientOrderId: "cancel_order_id_456", + Price: "0.001", + OrigQty: "1.00000000", + ExecutedQty: "0.00000000", + CumulativeQuoteQty: "0.00000000", + Status: "CANCELED", + TimeInForce: "GTC", + Type: "LIMIT", + Side: "BUY", + SelfTradePrevention: "DECREMENT_AND_CANCEL", + } + s.assertCancelOrderEqual(e, res) +} + +func (s *accountTestSuite) assertCancelOrderEqual(e, a *CancelOrderResponse) { + r := s.r() + r.Equal(e.Symbol, a.Symbol, "Symbol") + r.Equal(e.OrigClientOrderId, a.OrigClientOrderId, "OrigClientOrderId") + r.Equal(e.OrderId, a.OrderId, "OrderId") + r.Equal(e.OrderListId, a.OrderListId, "OrderListId") + r.Equal(e.ClientOrderId, a.ClientOrderId, "ClientOrderId") + r.Equal(e.Price, a.Price, "Price") + r.Equal(e.OrigQty, a.OrigQty, "OrigQty") + r.Equal(e.ExecutedQty, a.ExecutedQty, "ExecutedQty") + r.Equal(e.CumulativeQuoteQty, a.CumulativeQuoteQty, "CumulativeQuoteQty") + r.Equal(e.Status, a.Status, "Status") + r.Equal(e.TimeInForce, a.TimeInForce, "TimeInForce") + r.Equal(e.Type, a.Type, "Type") + r.Equal(e.Side, a.Side, "Side") + r.Equal(e.SelfTradePrevention, a.SelfTradePrevention, "SelfTradePrevention") +} + +func (s *accountTestSuite) TestListRateLimit() { + data := []byte(` + [ + { + "rateLimitType": "ORDERS", + "interval": "SECOND", + "intervalNum": 10, + "limit": 10000, + "count": 0 + }, + { + "rateLimitType": "RAW_REQUESTS", + "interval": "MINUTE", + "intervalNum": 5, + "limit": 5000, + "count": 100 + } + ] + `) + + s.mockDo(data, nil) + defer s.assertDo() + + limits, err := s.client.NewGetQueryCurrentOrderCountUsageService().Do(context.Background()) + s.r().NoError(err) + rows := limits + + s.Len(rows, 2) + s.assertRateLimitServiceEqual(&QueryCurrentOrderCountUsageResponse{ + RateLimitType: "ORDERS", + Interval: "SECOND", + IntervalNum: 10, + Limit: 10000, + Count: 0, + }, + rows[0]) + s.assertRateLimitServiceEqual(&QueryCurrentOrderCountUsageResponse{ + RateLimitType: "RAW_REQUESTS", + Interval: "MINUTE", + IntervalNum: 5, + Limit: 5000, + Count: 100, + }, + rows[1]) +} + +func (a *accountTestSuite) assertRateLimitServiceEqual(expected, other *QueryCurrentOrderCountUsageResponse) { + r := a.r() + + r.EqualValues(expected, other) +} + +func (s *accountTestSuite) TestGetOrder() { + data := []byte(`{ + "symbol": "BTCUSDT", + "orderId": 12345, + "orderListId": -1, + "clientOrderId": "abcde12345", + "price": "100.00", + "origQty": "10.00", + "executedQty": "0.00", + "cumulativeQuoteQty": "0.00", + "status": "NEW", + "timeInForce": "GTC", + "type": "LIMIT", + "side": "BUY", + "stopPrice": "0.00", + "icebergQty": "0.00", + "time": 1499827319559, + "updateTime": 1499827319559, + "isWorking": true, + "origQuoteOrderQty": "0.000000" + }`) + + s.mockDo(data, nil) + defer s.assertDo() + + res, err := s.client.NewGetOrderService().Symbol("BTCUSDT").OrderId(12345).Do(context.Background()) + s.r().NoError(err) + + s.assertGetOrderResponseEqual(&GetOrderResponse{ + Symbol: "BTCUSDT", + OrderId: 12345, + OrderListId: -1, + ClientOrderId: "abcde12345", + Price: "100.00", + OrigQty: "10.00", + ExecutedQty: "0.00", + CumulativeQuoteQty: "0.00", + Status: "NEW", + TimeInForce: "GTC", + Type: "LIMIT", + Side: "BUY", + StopPrice: "0.00", + IcebergQty: "0.00", + Time: 1499827319559, + UpdateTime: 1499827319559, + IsWorking: true, + OrigQuoteOrderQty: "0.000000", + }, res) +} + +func (s *accountTestSuite) assertGetOrderResponseEqual(expected, other *GetOrderResponse) { + r := s.r() + + r.EqualValues(expected, other) +} + +func (s *accountTestSuite) TestQueryOCOService() { + data := []byte(`{ + "orderListId": 10, + "contingencyType": "OCO", + "listStatusType": "EXEC_STARTED", + "listOrderStatus": "ALL_DONE", + "listClientOrderId": "test-list-client-order-id", + "transactionTime": 123456789, + "symbol": "BTCUSDT", + "orders": [ + { + "symbol": "BTCUSDT", + "orderId": 1001, + "clientOrderId": "test-client-order-id-1" + }, + { + "symbol": "BTCUSDT", + "orderId": 1002, + "clientOrderId": "test-client-order-id-2" + } + ] + }`) + + s.mockDo(data, nil) + defer s.assertDo() + + expected := &OCOResponse{ + OrderListId: 10, + ContingencyType: "OCO", + ListStatusType: "EXEC_STARTED", + ListOrderStatus: "ALL_DONE", + ListClientOrderId: "test-list-client-order-id", + TransactionTime: 123456789, + Symbol: "BTCUSDT", + Orders: []struct { + Symbol string `json:"symbol"` + OrderId int64 `json:"orderId"` + ClientOrderId string `json:"clientOrderId"` + }{ + { + Symbol: "BTCUSDT", + OrderId: 1001, + ClientOrderId: "test-client-order-id-1", + }, + { + Symbol: "BTCUSDT", + OrderId: 1002, + ClientOrderId: "test-client-order-id-2", + }, + }, + } + + oco, err := s.client.NewQueryOCOService(). + OrderListId(10). + OrigClientOrderId("test-client-order-id"). + Do(context.Background()) + + s.r().NoError(err) + s.r().Equal(expected, oco) +} + +func (s *accountTestSuite) TestQueryAllOCOService() { + data := []byte(`{ + "orderListId": 123456, + "contingencyType": "OCO", + "listStatusType": "EXEC_STARTED", + "listOrderStatus": "EXECUTING", + "listClientOrderId": "myListClientOrderId", + "transactionTime": 1616976140402, + "symbol": "BTCUSDT", + "orders": [ + { + "symbol": "BTCUSDT", + "orderId": 654321, + "clientOrderId": "myClientOrderId" + } + ] + }`) + + s.mockDo(data, nil) + defer s.assertDo() + + response, err := s.client.NewQueryAllOCOService().FromId(123456).StartTime(1616976140402).Limit(100).Do(context.Background()) + s.r().NoError(err) + + s.assertOCOResponseEqual(&OCOResponse{ + OrderListId: 123456, + ContingencyType: "OCO", + ListStatusType: "EXEC_STARTED", + ListOrderStatus: "EXECUTING", + ListClientOrderId: "myListClientOrderId", + TransactionTime: 1616976140402, + Symbol: "BTCUSDT", + Orders: []struct { + Symbol string `json:"symbol"` + OrderId int64 `json:"orderId"` + ClientOrderId string `json:"clientOrderId"` + }{ + { + Symbol: "BTCUSDT", + OrderId: 654321, + ClientOrderId: "myClientOrderId", + }, + }, + }, response) +} + +func (s *accountTestSuite) assertOCOResponseEqual(expected, other *OCOResponse) { + r := s.r() + + r.EqualValues(expected.OrderListId, other.OrderListId) + r.EqualValues(expected.ContingencyType, other.ContingencyType) + r.EqualValues(expected.ListStatusType, other.ListStatusType) + r.EqualValues(expected.ListOrderStatus, other.ListOrderStatus) + r.EqualValues(expected.ListClientOrderId, other.ListClientOrderId) + r.EqualValues(expected.TransactionTime, other.TransactionTime) + r.EqualValues(expected.Symbol, other.Symbol) + + r.Len(other.Orders, len(expected.Orders)) + for i, order := range expected.Orders { + r.EqualValues(order.Symbol, other.Orders[i].Symbol) + r.EqualValues(order.OrderId, other.Orders[i].OrderId) + r.EqualValues(order.ClientOrderId, other.Orders[i].ClientOrderId) + } +} + +func (s *accountTestSuite) TestGetOpenOrders() { + data := []byte(` + [ + { + "symbol": "BTCUSDT", + "orderId": 10, + "clientOrderId": "my-order-id", + "price": "100.0", + "origQty": "1.0", + "executedQty": "0.0", + "status": "NEW", + "timeInForce": "GTC", + "type": "LIMIT", + "side": "BUY", + "stopPrice": "0.0", + "icebergQty": "0.0", + "time": 1613450271000, + "updateTime": 1613450271000, + "isWorking": true, + "origQuoteOrderQty": "100.0", + "selfTradePreventionMode": "DECREMENT_AND_CANCEL" + } + ] + `) + + s.mockDo(data, nil) + defer s.assertDo() + + resp, err := s.client.NewGetOpenOrdersService(). + Symbol("BTCUSDT"). + Do(context.Background()) + + s.r().NoError(err) + s.Len(resp, 1) + s.Equal("BTCUSDT", resp[0].Symbol) + s.Equal(int64(10), resp[0].OrderId) + s.Equal("my-order-id", resp[0].ClientOrderId) + s.Equal("100.0", resp[0].Price) + s.Equal("1.0", resp[0].OrigQty) + s.Equal("0.0", resp[0].ExecutedQty) + s.Equal("NEW", resp[0].Status) + s.Equal("GTC", resp[0].TimeInForce) + s.Equal("LIMIT", resp[0].Type) + s.Equal("BUY", resp[0].Side) + s.Equal("0.0", resp[0].StopPrice) + s.Equal("0.0", resp[0].IcebergQty) + s.Equal(uint64(1613450271000), resp[0].Time) + s.Equal(uint64(1613450271000), resp[0].UpdateTime) + s.True(resp[0].IsWorking) + s.Equal("100.0", resp[0].OrigQuoteOrderQty) + s.Equal("DECREMENT_AND_CANCEL", resp[0].SelfTradePreventionMode) +} + +func (s *accountTestSuite) TestGetAllOrders() { + data := []byte(` + [ + { + "symbol": "BTCUSDT", + "orderId": 3127658, + "orderListId": -1, + "clientOrderId": "U3BbvrQe2upXyv9qgPUByL", + "price": "25000.00000000", + "origQty": "1.00000000", + "executedQty": "0.00000000", + "cumulativeQuoteQty": "0.00000000", + "status": "NEW", + "timeInForce": "GTC", + "type": "LIMIT", + "side": "BUY", + "stopPrice": "0.00000000", + "icebergQty": "0.00000000", + "time": 1617167610255, + "updateTime": 1617167610255, + "isWorking": true, + "origQuoteOrderQty": "25000.00000000", + "workingTime": 0, + "selfTradePreventionMode": "DECREMENT_AND_CANCEL", + "preventedQuantity": "0.00000000", + "preventedMatchId": 0 + } + ] + `) + + s.mockDo(data, nil) + defer s.assertDo() + + resp, err := s.client.NewGetAllOrdersService(). + Symbol("BTCUSDT"). + OrderId(3127658). + StartTime(1617167610000). + EndTime(1617254010000). + Limit(1000). + Do(context.Background()) + + s.r().NoError(err) + s.Len(resp, 1) + s.Equal("BTCUSDT", resp[0].Symbol) + s.Equal(int64(3127658), resp[0].OrderId) + s.Equal(int64(-1), resp[0].OrderListId) + s.Equal("U3BbvrQe2upXyv9qgPUByL", resp[0].ClientOrderId) + s.Equal("25000.00000000", resp[0].Price) + s.Equal("1.00000000", resp[0].OrigQty) + s.Equal("0.00000000", resp[0].ExecutedQty) + s.Equal("0.00000000", resp[0].CumulativeQuoteQty) + s.Equal("NEW", resp[0].Status) + s.Equal("GTC", resp[0].TimeInForce) + s.Equal("LIMIT", resp[0].Type) + s.Equal("BUY", resp[0].Side) + s.Equal("0.00000000", resp[0].StopPrice) + s.Equal("0.00000000", resp[0].IcebergQty) + s.Equal(uint64(1617167610255), resp[0].Time) + s.Equal(uint64(1617167610255), resp[0].UpdateTime) + s.True(resp[0].IsWorking) + s.Equal("25000.00000000", resp[0].OrigQuoteOrderQty) + s.Equal(uint64(0), resp[0].WorkingTime) + s.Equal("DECREMENT_AND_CANCEL", resp[0].SelfTradePreventionMode) + s.Equal("0.00000000", resp[0].PreventedQuantity) + s.Equal(int64(0), resp[0].PreventedMatchId) +} + +func (s *accountTestSuite) TestCancelOpenOrders() { + data := []byte(`[ + { + "symbol": "BTCUSDT", + "origClientOrderId": "1uL7mdU6TlTzTqTddTfNhV", + "orderId": 123456, + "orderListId": -1, + "clientOrderId": "pXLV6Hz6mprAcVYpLkd1KH", + "price": "0.00000000", + "origQty": "1.00000000", + "executedQty": "0.00000000", + "cumulativeQuoteQty": "0.00000000", + "status": "CANCELED", + "timeInForce": "GTC", + "type": "LIMIT", + "side": "BUY", + "selfTradePrevention": "DECREASE_AND_CANCEL" + }, + { + "symbol": "ETHUSDT", + "origClientOrderId": "2uL7mdU6TlTzTqTddTfNhV", + "orderId": 123457, + "orderListId": -1, + "clientOrderId": "qXLV6Hz6mprAcVYpLkd1KH", + "price": "0.00000000", + "origQty": "2.00000000", + "executedQty": "0.00000000", + "cumulativeQuoteQty": "0.00000000", + "status": "CANCELED", + "timeInForce": "GTC", + "type": "LIMIT", + "side": "SELL", + "selfTradePrevention": "DECREASE_AND_CANCEL" + } + ]`) + + s.mockDo(data, nil) + defer s.assertDo() + + res, err := s.client.NewCancelOpenOrdersService(). + Symbol("BTCUSDT"). + Do(context.Background()) + + s.r().NoError(err) + s.Len(res, 2) + s.Equal("BTCUSDT", res[0].Symbol) + s.Equal("1uL7mdU6TlTzTqTddTfNhV", res[0].OrigClientOrderId) + s.Equal(int64(123456), res[0].OrderId) + s.Equal(int64(-1), res[0].OrderListId) + s.Equal("pXLV6Hz6mprAcVYpLkd1KH", res[0].ClientOrderId) + s.Equal("0.00000000", res[0].Price) + s.Equal("1.00000000", res[0].OrigQty) + s.Equal("0.00000000", res[0].ExecutedQty) + s.Equal("0.00000000", res[0].CumulativeQuoteQty) + s.Equal("CANCELED", res[0].Status) + s.Equal("GTC", res[0].TimeInForce) + s.Equal("LIMIT", res[0].Type) + s.Equal("BUY", res[0].Side) + s.Equal("DECREASE_AND_CANCEL", res[0].SelfTradePrevention) + + s.Equal("ETHUSDT", res[1].Symbol) + s.Equal("2uL7mdU6TlTzTqTddTfNhV", res[1].OrigClientOrderId) + s.Equal(int64(123457), res[1].OrderId) + s.Equal(int64(-1), res[1].OrderListId) + s.Equal("qXLV6Hz6mprAcVYpLkd1KH", res[1].ClientOrderId) + s.Equal("0.00000000", res[1].Price) + s.Equal("2.00000000", res[1].OrigQty) + s.Equal("0.00000000", res[1].ExecutedQty) + s.Equal("0.00000000", res[1].CumulativeQuoteQty) + s.Equal("CANCELED", res[1].Status) + s.Equal("GTC", res[1].TimeInForce) + s.Equal("LIMIT", res[1].Type) + s.Equal("SELL", res[1].Side) + s.Equal("DECREASE_AND_CANCEL", res[1].SelfTradePrevention) +} + +func (s *accountTestSuite) TestQueryOpenOCOService() { + data := []byte(` + { + "orderListId": 1, + "contingencyType": "OCO", + "listStatusType": "EXEC_STARTED", + "listOrderStatus": "EXECUTING", + "listClientOrderId": "test-list-client-order-id", + "transactionTime": 1613450271000, + "symbol": "BTCUSDT", + "orders": [ + { + "symbol": "BTCUSDT", + "orderId": 123, + "clientOrderId": "test-client-order-id-1" + }, + { + "symbol": "BTCUSDT", + "orderId": 456, + "clientOrderId": "test-client-order-id-2" + } + ] + } + `) + + s.mockDo(data, nil) + defer s.assertDo() + + resp, err := s.client.NewQueryOpenOCOService().Do(context.Background()) + + s.r().NoError(err) + s.NotNil(resp) + s.Equal(int64(1), resp.OrderListId) + s.Equal("OCO", resp.ContingencyType) + s.Equal("EXEC_STARTED", resp.ListStatusType) + s.Equal("EXECUTING", resp.ListOrderStatus) + s.Equal("test-list-client-order-id", resp.ListClientOrderId) + s.Equal(uint64(1613450271000), resp.TransactionTime) + s.Equal("BTCUSDT", resp.Symbol) + s.Len(resp.Orders, 2) + s.Equal("BTCUSDT", resp.Orders[0].Symbol) + s.Equal(int64(123), resp.Orders[0].OrderId) + s.Equal("test-client-order-id-1", resp.Orders[0].ClientOrderId) + s.Equal("BTCUSDT", resp.Orders[1].Symbol) + s.Equal(int64(456), resp.Orders[1].OrderId) + s.Equal("test-client-order-id-2", resp.Orders[1].ClientOrderId) +} + +func (s *accountTestSuite) TestGetQueryPreventedMatches() { + data := []byte(`{ + "preventedMatches": [ + { + "symbol": "BTCUSDT", + "preventedMatchId": 123, + "takerOrderId": 456, + "makerOrderId": 789, + "tradeGroupId": 101112, + "selfTradePreventionMode": "CANCEL_BOTH", + "price": "65000.00", + "makerPreventedQuantity": "0.00005", + "transactTime": 1613450271000 + } + ] + }`) + + s.mockDo(data, nil) + defer s.assertDo() + + resp, err := s.client.NewGetQueryPreventedMatchesService(). + Symbol("BTCUSDT"). + PreventMatchId(123). + OrderId(456). + FromPreventedMatchId(789). + Limit(500). + Do(context.Background()) + + s.r().NoError(err) + s.Len(resp.PreventedMatches, 1) + s.Equal("BTCUSDT", resp.PreventedMatches[0].Symbol) + s.Equal(int64(123), resp.PreventedMatches[0].PreventedMatchId) + s.Equal(int64(456), resp.PreventedMatches[0].TakerOrderId) + s.Equal(int64(789), resp.PreventedMatches[0].MakerOrderId) + s.Equal(int64(101112), resp.PreventedMatches[0].TradeGroupId) + s.Equal("CANCEL_BOTH", resp.PreventedMatches[0].SelfTradePreventionMode) + s.Equal("65000.00", resp.PreventedMatches[0].Price) + s.Equal("0.00005", resp.PreventedMatches[0].MakerPreventedQuantity) + s.Equal(uint64(1613450271000), resp.PreventedMatches[0].TransactTime) +} diff --git a/client.go b/client.go new file mode 100644 index 0000000..536fa53 --- /dev/null +++ b/client.go @@ -0,0 +1,808 @@ +package binance_connector + +import ( + "bytes" + "context" + "crypto/hmac" + "crypto/sha256" + "encoding/json" + "fmt" + "io/ioutil" + "log" + "net/http" + "net/url" + "os" + "time" + + "github.com/binance/binance-connector-go/handlers" + "github.com/bitly/go-simplejson" +) + +// TimeInForceType define time in force type of order +type TimeInForceType string + +// UserDataEventType define spot user data event type +type UserDataEventType string + +// Client define API client +type Client struct { + APIKey string + SecretKey string + BaseURL string + HTTPClient *http.Client + Debug bool + Logger *log.Logger + TimeOffset int64 + do doFunc +} + +type doFunc func(req *http.Request) (*http.Response, error) + +// Globals +const ( + baseAPIMainURL = "https://api.binance.com" + baseAPITestnetURL = "https://testnet.binance.vision" + timestampKey = "timestamp" + signatureKey = "signature" + recvWindowKey = "recvWindow" +) + +func currentTimestamp() int64 { + return FormatTimestamp(time.Now()) +} + +// FormatTimestamp formats a time into Unix timestamp in milliseconds, as requested by Binance. +func FormatTimestamp(t time.Time) int64 { + return t.UnixNano() / int64(time.Millisecond) +} + +func PrettyPrint(i interface{}) string { + s, _ := json.MarshalIndent(i, "", "\t") + return string(s) +} + +func (c *Client) debug(format string, v ...interface{}) { + if c.Debug { + c.Logger.Printf(format, v...) + } +} + +func NewClient(apiKey string, secretKey string, baseURL ...string) *Client { + url := "https://api.binance.com" + + if len(baseURL) > 0 { + url = baseURL[0] + } + + return &Client{ + APIKey: apiKey, + SecretKey: secretKey, + BaseURL: url, + HTTPClient: http.DefaultClient, + Logger: log.New(os.Stderr, Name, log.LstdFlags), + } +} + +// Create client function for initialising new Binance client: +func (c *Client) parseRequest(r *request, opts ...RequestOption) (err error) { + // set request options from user + for _, opt := range opts { + opt(r) + } + err = r.validate() + if err != nil { + return err + } + + fullURL := fmt.Sprintf("%s%s", c.BaseURL, r.endpoint) + if r.recvWindow > 0 { + r.setParam(recvWindowKey, r.recvWindow) + } + if r.secType == secTypeSigned { + r.setParam(timestampKey, currentTimestamp()-c.TimeOffset) + } + queryString := r.query.Encode() + body := &bytes.Buffer{} + bodyString := r.form.Encode() + header := http.Header{} + if r.header != nil { + header = r.header.Clone() + } + header.Set("User-Agent", fmt.Sprintf("%s/%s", Name, Version)) + if bodyString != "" { + header.Set("Content-Type", "application/x-www-form-urlencoded") + body = bytes.NewBufferString(bodyString) + } + if r.secType == secTypeAPIKey || r.secType == secTypeSigned { + header.Set("X-MBX-APIKEY", c.APIKey) + } + + if r.secType == secTypeSigned { + raw := fmt.Sprintf("%s%s", queryString, bodyString) + mac := hmac.New(sha256.New, []byte(c.SecretKey)) + _, err = mac.Write([]byte(raw)) + if err != nil { + return err + } + v := url.Values{} + v.Set(signatureKey, fmt.Sprintf("%x", (mac.Sum(nil)))) + if queryString == "" { + queryString = v.Encode() + } else { + queryString = fmt.Sprintf("%s&%s", queryString, v.Encode()) + } + } + if queryString != "" { + fullURL = fmt.Sprintf("%s?%s", fullURL, queryString) + } + c.debug("full url: %s, body: %s", fullURL, bodyString) + r.fullURL = fullURL + r.header = header + r.body = body + return nil +} + +func (c *Client) callAPI(ctx context.Context, r *request, opts ...RequestOption) (data []byte, err error) { + err = c.parseRequest(r, opts...) + if err != nil { + return []byte{}, err + } + req, err := http.NewRequest(r.method, r.fullURL, r.body) + if err != nil { + return []byte{}, err + } + req = req.WithContext(ctx) + req.Header = r.header + c.debug("request: %#v", req) + f := c.do + if f == nil { + f = c.HTTPClient.Do + } + res, err := f(req) + if err != nil { + return []byte{}, err + } + data, err = ioutil.ReadAll(res.Body) + if err != nil { + return []byte{}, err + } + defer func() { + cerr := res.Body.Close() + // Only overwrite the retured error if the original error was nil and an + // error occurred while closing the body. + if err == nil && cerr != nil { + err = cerr + } + }() + c.debug("response: %#v", res) + c.debug("response body: %s", string(data)) + c.debug("response status code: %d", res.StatusCode) + + if res.StatusCode >= http.StatusBadRequest { + apiErr := new(handlers.APIError) + e := json.Unmarshal(data, apiErr) + if e != nil { + c.debug("failed to unmarshal json: %s", e) + } + return nil, apiErr + } + return data, nil +} + +func newJSON(data []byte) (j *simplejson.Json, err error) { + j, err = simplejson.NewJson(data) + if err != nil { + return nil, err + } + return j, nil +} + +// Account Endpoints: +func (c *Client) NewTestNewOrder() *TestNewOrder { + return &TestNewOrder{c: c} +} + +func (c *Client) NewCreateOrderService() *CreateOrderService { + return &CreateOrderService{c: c} +} + +func (c *Client) NewCancelOrderService() *CancelOrderService { + return &CancelOrderService{c: c} +} + +func (c *Client) NewCancelOpenOrdersService() *CancelOpenOrdersService { + return &CancelOpenOrdersService{c: c} +} + +func (c *Client) NewGetOrderService() *GetOrderService { + return &GetOrderService{c: c} +} + +func (c *Client) NewCancelReplaceService() *CancelReplaceService { + return &CancelReplaceService{c: c} +} + +func (c *Client) NewGetOpenOrdersService() *GetOpenOrdersService { + return &GetOpenOrdersService{c: c} +} + +func (c *Client) NewGetAllOrdersService() *GetAllOrdersService { + return &GetAllOrdersService{c: c} +} + +func (c *Client) NewNewOCOService() *NewOCOService { + return &NewOCOService{c: c} +} + +func (c *Client) NewCancelOCOService() *CancelOCOService { + return &CancelOCOService{c: c} +} + +func (c *Client) NewQueryOCOService() *QueryOCOService { + return &QueryOCOService{c: c} +} + +func (c *Client) NewQueryAllOCOService() *QueryAllOCOService { + return &QueryAllOCOService{c: c} +} + +func (c *Client) NewQueryOpenOCOService() *QueryOpenOCOService { + return &QueryOpenOCOService{c: c} +} + +func (c *Client) NewGetAccountService() *GetAccountService { + return &GetAccountService{c: c} +} + +func (c *Client) NewGetMyTradesService() *GetMyTradesService { + return &GetMyTradesService{c: c} +} + +func (c *Client) NewGetQueryCurrentOrderCountUsageService() *GetQueryCurrentOrderCountUsageService { + return &GetQueryCurrentOrderCountUsageService{c: c} +} + +func (c *Client) NewGetQueryPreventedMatchesService() *GetQueryPreventedMatchesService { + return &GetQueryPreventedMatchesService{c: c} +} + +// Market Endpoints: +func (c *Client) NewPingService() *Ping { + return &Ping{c: c} +} + +func (c *Client) NewServerTimeService() *ServerTime { + return &ServerTime{c: c} +} + +func (c *Client) NewExchangeInfoService() *ExchangeInfo { + return &ExchangeInfo{c: c} +} + +func (c *Client) NewOrderBookService() *OrderBook { + return &OrderBook{c: c} +} + +func (c *Client) NewRecentTradesListService() *RecentTradesList { + return &RecentTradesList{c: c} +} + +func (c *Client) NewHistoricalTradeLookupService() *HistoricalTradeLookup { + return &HistoricalTradeLookup{c: c} +} + +func (c *Client) NewAggTradesListService() *AggTradesList { + return &AggTradesList{c: c} +} + +func (c *Client) NewKlinesService() *Klines { + return &Klines{c: c} +} + +func (c *Client) NewUIKlinesService() *UiKlines { + return &UiKlines{c: c} +} + +func (c *Client) NewAvgPriceService() *AvgPrice { + return &AvgPrice{c: c} +} + +func (c *Client) NewTicker24hrService() *Ticker24hr { + return &Ticker24hr{c: c} +} + +func (c *Client) NewTickerPriceService() *TickerPrice { + return &TickerPrice{c: c} +} + +func (c *Client) NewTickerBookTickerService() *TickerBookTicker { + return &TickerBookTicker{c: c} +} + +func (c *Client) NewTickerService() *Ticker { + return &Ticker{c: c} +} + +// Margin Endpoints: +func (c *Client) NewTransferService() *TransferService { + return &TransferService{c: c} +} + +func (c *Client) NewBorrowService() *BorrowService { + return &BorrowService{c: c} +} + +func (c *Client) NewRepayService() *RepayService { + return &RepayService{c: c} +} + +func (c *Client) NewQueryMarginAssetService() *QueryMarginAssetService { + return &QueryMarginAssetService{c: c} +} + +func (c *Client) NewQueryCrossMarginPairService() *QueryCrossMarginPairService { + return &QueryCrossMarginPairService{c: c} +} + +func (c *Client) NewGetAllMarginAssetsService() *GetAllMarginAssetsService { + return &GetAllMarginAssetsService{c: c} +} + +func (c *Client) NewGetAllMarginPairsService() *GetAllMarginPairsService { + return &GetAllMarginPairsService{c: c} +} + +func (c *Client) NewQueryMarginPriceIndexService() *QueryMarginPriceIndexService { + return &QueryMarginPriceIndexService{c: c} +} + +func (c *Client) NewMarginAccountNewOrderService() *MarginAccountNewOrderService { + return &MarginAccountNewOrderService{c: c} +} + +func (c *Client) NewMarginAccountCancelOrderService() *MarginAccountCancelOrderService { + return &MarginAccountCancelOrderService{c: c} +} + +func (c *Client) NewMarginAccountCancelAllOrdersService() *MarginAccountCancelAllOrdersService { + return &MarginAccountCancelAllOrdersService{c: c} +} + +func (c *Client) NewCrossMarginTransferHistoryService() *CrossMarginTransferHistoryService { + return &CrossMarginTransferHistoryService{c: c} +} + +func (c *Client) NewLoanRecordService() *LoanRecordService { + return &LoanRecordService{c: c} +} + +func (c *Client) NewRepayRecordService() *RepayRecordService { + return &RepayRecordService{c: c} +} + +func (c *Client) NewInterestHistoryService() *InterestHistoryService { + return &InterestHistoryService{c: c} +} + +func (c *Client) NewForceLiquidationRecordService() *ForceLiquidationRecordService { + return &ForceLiquidationRecordService{c: c} +} + +func (c *Client) NewCrossMarginAccountDetailService() *CrossMarginAccountDetailService { + return &CrossMarginAccountDetailService{c: c} +} + +func (c *Client) NewMarginAccountOrderService() *MarginAccountOrderService { + return &MarginAccountOrderService{c: c} +} + +func (c *Client) NewMarginAccountOpenOrderService() *MarginAccountOpenOrderService { + return &MarginAccountOpenOrderService{c: c} +} + +func (c *Client) NewMarginAccountAllOrderService() *MarginAccountAllOrderService { + return &MarginAccountAllOrderService{c: c} +} + +func (c *Client) NewMarginAccountNewOCOService() *MarginAccountNewOCOService { + return &MarginAccountNewOCOService{c: c} +} + +func (c *Client) NewMarginAccountCancelOCOService() *MarginAccountCancelOCOService { + return &MarginAccountCancelOCOService{c: c} +} + +func (c *Client) NewMarginAccountQueryOCOService() *MarginAccountQueryOCOService { + return &MarginAccountQueryOCOService{c: c} +} + +func (c *Client) NewMarginAccountQueryAllOCOService() *MarginAccountQueryAllOCOService { + return &MarginAccountQueryAllOCOService{c: c} +} + +func (c *Client) NewMarginAccountQueryOpenOCOService() *MarginAccountQueryOpenOCOService { + return &MarginAccountQueryOpenOCOService{c: c} +} + +func (c *Client) NewMarginAccountQueryTradeListService() *MarginAccountQueryTradeListService { + return &MarginAccountQueryTradeListService{c: c} +} + +func (c *Client) NewMarginAccountQueryMaxBorrowService() *MarginAccountQueryMaxBorrowService { + return &MarginAccountQueryMaxBorrowService{c: c} +} + +func (c *Client) NewMarginAccountQueryMaxTransferOutAmountService() *MarginAccountQueryMaxTransferOutAmountService { + return &MarginAccountQueryMaxTransferOutAmountService{c: c} +} + +func (c *Client) NewMarginAccountSummaryService() *MarginAccountSummaryService { + return &MarginAccountSummaryService{c: c} +} + +func (c *Client) NewMarginIsolatedAccountTransferService() *MarginIsolatedAccountTransferService { + return &MarginIsolatedAccountTransferService{c: c} +} + +func (c *Client) NewMarginIsolatedAccountTransferHistoryService() *MarginIsolatedAccountTransferHistoryService { + return &MarginIsolatedAccountTransferHistoryService{c: c} +} + +func (c *Client) NewMarginIsolatedAccountInfoService() *MarginIsolatedAccountInfoService { + return &MarginIsolatedAccountInfoService{c: c} +} + +func (c *Client) NewMarginIsolatedAccountDisableService() *MarginIsolatedAccountDisableService { + return &MarginIsolatedAccountDisableService{c: c} +} + +func (c *Client) NewMarginIsolatedAccountEnableService() *MarginIsolatedAccountEnableService { + return &MarginIsolatedAccountEnableService{c: c} +} + +func (c *Client) NewMarginIsolatedAccountLimitService() *MarginIsolatedAccountLimitService { + return &MarginIsolatedAccountLimitService{c: c} +} + +func (c *Client) NewMarginIsolatedSymbolService() *MarginIsolatedSymbolService { + return &MarginIsolatedSymbolService{c: c} +} + +func (c *Client) NewAllIsolatedMarginSymbolService() *AllIsolatedMarginSymbolService { + return &AllIsolatedMarginSymbolService{c: c} +} + +func (c *Client) NewMarginToggleBnbBurnService() *MarginToggleBnbBurnService { + return &MarginToggleBnbBurnService{c: c} +} + +func (c *Client) NewMarginBnbBurnStatusService() *MarginBnbBurnStatusService { + return &MarginBnbBurnStatusService{c: c} +} + +func (c *Client) NewMarginInterestRateHistoryService() *MarginInterestRateHistoryService { + return &MarginInterestRateHistoryService{c: c} +} + +func (c *Client) NewMarginCrossMarginFeeService() *MarginCrossMarginFeeService { + return &MarginCrossMarginFeeService{c: c} +} + +func (c *Client) NewMarginIsolatedMarginFeeService() *MarginIsolatedMarginFeeService { + return &MarginIsolatedMarginFeeService{c: c} +} + +func (c *Client) NewMarginIsolatedMarginTierService() *MarginIsolatedMarginTierService { + return &MarginIsolatedMarginTierService{c: c} +} + +func (c *Client) NewMarginCurrentOrderCountService() *MarginCurrentOrderCountService { + return &MarginCurrentOrderCountService{c: c} +} + +func (c *Client) NewMarginDustlogService() *MarginDustlogService { + return &MarginDustlogService{c: c} +} + +func (c *Client) NewMarginCrossCollateralRatioService() *MarginCrossCollateralRatioService { + return &MarginCrossCollateralRatioService{c: c} +} + +func (c *Client) NewMarginSmallLiabilityExchangeCoinListService() *MarginSmallLiabilityExchangeCoinListService { + return &MarginSmallLiabilityExchangeCoinListService{c: c} +} + +func (c *Client) NewMarginSmallLiabilityExchangeService() *MarginSmallLiabilityExchangeService { + return &MarginSmallLiabilityExchangeService{c: c} +} + +func (c *Client) NewMarginSmallLiabilityExchangeHistoryService() *MarginSmallLiabilityExchangeHistoryService { + return &MarginSmallLiabilityExchangeHistoryService{c: c} +} + +// Sub-Account Endpoints: +func (c *Client) NewCreateSubAccountService() *CreateSubAccountService { + return &CreateSubAccountService{c: c} +} + +func (c *Client) NewQuerySubAccountListService() *QuerySubAccountListService { + return &QuerySubAccountListService{c: c} +} + +func (c *Client) NewQuerySubAccountSpotAssetTransferHistoryService() *QuerySubAccountSpotAssetTransferHistoryService { + return &QuerySubAccountSpotAssetTransferHistoryService{c: c} +} + +func (c *Client) NewQuerySubAccountFuturesAssetTransferHistoryService() *QuerySubAccountFuturesAssetTransferHistoryService { + return &QuerySubAccountFuturesAssetTransferHistoryService{c: c} +} + +func (c *Client) NewSubAccountFuturesAssetTransferService() *SubAccountFuturesAssetTransferService { + return &SubAccountFuturesAssetTransferService{c: c} +} + +func (c *Client) NewQuerySubAccountAssetsService() *QuerySubAccountAssetsService { + return &QuerySubAccountAssetsService{c: c} +} + +func (c *Client) NewQuerySubAccountSpotAssetsSummaryService() *QuerySubAccountSpotAssetsSummaryService { + return &QuerySubAccountSpotAssetsSummaryService{c: c} +} + +func (c *Client) NewGetSubAccountDepositAddressService() *GetSubAccountDepositAddressService { + return &GetSubAccountDepositAddressService{c: c} +} + +func (c *Client) NewGetSubAccountDepositHistoryService() *GetSubAccountDepositHistoryService { + return &GetSubAccountDepositHistoryService{c: c} +} + +func (c *Client) NewGetSubAccountStatusService() *GetSubAccountStatusService { + return &GetSubAccountStatusService{c: c} +} + +func (c *Client) NewEnableMarginForSubAccountService() *EnableMarginForSubAccountService { + return &EnableMarginForSubAccountService{c: c} +} + +func (c *Client) NewGetDetailOnSubAccountMarginAccountService() *GetDetailOnSubAccountMarginAccountService { + return &GetDetailOnSubAccountMarginAccountService{c: c} +} + +func (c *Client) NewGetSummaryOfSubAccountMarginAccountService() *GetSummaryOfSubAccountMarginAccountService { + return &GetSummaryOfSubAccountMarginAccountService{c: c} +} + +func (c *Client) NewEnableFuturesForSubAccountService() *EnableFuturesForSubAccountService { + return &EnableFuturesForSubAccountService{c: c} +} + +func (c *Client) NewGetDetailOnSubAccountFuturesAccountService() *GetDetailOnSubAccountFuturesAccountService { + return &GetDetailOnSubAccountFuturesAccountService{c: c} +} + +func (c *Client) NewGetSummaryOfSubAccountFuturesAccountService() *GetSummaryOfSubAccountFuturesAccountService { + return &GetSummaryOfSubAccountFuturesAccountService{c: c} +} + +func (c *Client) NewGetFuturesPositionRiskOfSubAccountService() *GetFuturesPositionRiskOfSubAccountService { + return &GetFuturesPositionRiskOfSubAccountService{c: c} +} + +func (c *Client) NewFuturesTransferForSubAccountService() *FuturesTransferForSubAccountService { + return &FuturesTransferForSubAccountService{c: c} +} + +func (c *Client) NewMarginTransferForSubAccountService() *MarginTransferForSubAccountService { + return &MarginTransferForSubAccountService{c: c} +} + +func (c *Client) NewTransferToSubAccountOfSameMasterService() *TransferToSubAccountOfSameMasterService { + return &TransferToSubAccountOfSameMasterService{c: c} +} + +func (c *Client) NewTransferToMasterService() *TransferToMasterService { + return &TransferToMasterService{c: c} +} + +func (c *Client) NewSubAccountTransferHistoryService() *SubAccountTransferHistoryService { + return &SubAccountTransferHistoryService{c: c} +} + +func (c *Client) NewUniversalTransferService() *UniversalTransferService { + return &UniversalTransferService{c: c} +} + +func (c *Client) NewQueryUniversalTransferHistoryService() *QueryUniversalTransferHistoryService { + return &QueryUniversalTransferHistoryService{c: c} +} + +func (c *Client) NewGetDetailOnSubAccountFuturesAccountV2Service() *GetDetailOnSubAccountFuturesAccountV2Service { + return &GetDetailOnSubAccountFuturesAccountV2Service{c: c} +} + +func (c *Client) NewGetSummaryOfSubAccountFuturesAccountV2Service() *GetSummaryOfSubAccountFuturesAccountV2Service { + return &GetSummaryOfSubAccountFuturesAccountV2Service{c: c} +} + +func (c *Client) NewGetFuturesPositionRiskOfSubAccountV2Service() *GetFuturesPositionRiskOfSubAccountV2Service { + return &GetFuturesPositionRiskOfSubAccountV2Service{c: c} +} + +func (c *Client) NewEnableLeverageTokenForSubAccountService() *EnableLeverageTokenForSubAccountService { + return &EnableLeverageTokenForSubAccountService{c: c} +} + +func (c *Client) NewGetIPRestrictionForSubAccountAPIKeyService() *GetIPRestrictionForSubAccountAPIKeyService { + return &GetIPRestrictionForSubAccountAPIKeyService{c: c} +} + +func (c *Client) NewDeleteIPListForSubAccountAPIKeyService() *DeleteIPListForSubAccountAPIKeyService { + return &DeleteIPListForSubAccountAPIKeyService{c: c} +} + +func (c *Client) NewUpdateIPRestrictionForSubAccountAPIKeyService() *UpdateIPRestrictionForSubAccountAPIKeyService { + return &UpdateIPRestrictionForSubAccountAPIKeyService{c: c} +} + +func (c *Client) NewDepositAssetsIntoManagedSubAccountService() *DepositAssetsIntoTheManagedSubAccountService { + return &DepositAssetsIntoTheManagedSubAccountService{c: c} +} + +func (c *Client) NewQueryManagedSubAccountAssetDetailsService() *QueryManagedSubAccountAssetDetailsService { + return &QueryManagedSubAccountAssetDetailsService{c: c} +} + +func (c *Client) NewWithdrawAssetsFromTheManagedSubAccountService() *WithdrawAssetsFromTheManagedSubAccountService { + return &WithdrawAssetsFromTheManagedSubAccountService{c: c} +} + +func (c *Client) NewQueryManagedSubAccountSnapshotService() *QueryManagedSubAccountSnapshotService { + return &QueryManagedSubAccountSnapshotService{c: c} +} + +func (c *Client) NewQueryManagedSubAccountTransferLogService() *QueryManagedSubAccountTransferLogService { + return &QueryManagedSubAccountTransferLogService{c: c} +} + +func (c *Client) NewQueryManagedSubAccountFuturesAssetDetailsService() *QueryManagedSubAccountFuturesAssetDetailsService { + return &QueryManagedSubAccountFuturesAssetDetailsService{c: c} +} + +func (c *Client) NewQueryManagedSubAccountMarginAssetDetailsService() *QueryManagedSubAccountMarginAssetDetailsService { + return &QueryManagedSubAccountMarginAssetDetailsService{c: c} +} + +func (c *Client) NewQueryManagedSubAccountTransferLogForTradingTeamService() *QueryManagedSubAccountTransferLogForTradingTeamService { + return &QueryManagedSubAccountTransferLogForTradingTeamService{c: c} +} + +func (c *Client) NewQuerySubAccountAssetsForMasterAccountService() *QuerySubAccountAssetsForMasterAccountService { + return &QuerySubAccountAssetsForMasterAccountService{c: c} +} + +func (c *Client) NewQueryManagedSubAccountList() *QueryManagedSubAccountList { + return &QueryManagedSubAccountList{c: c} +} + +func (c *Client) NewQuerySubAccountTransactionTatistics() *QuerySubAccountTransactionTatistics { + return &QuerySubAccountTransactionTatistics{c: c} +} + +// Wallet Endpoints: +func (c *Client) NewGetSystemStatusService() *GetSystemStatusService { + return &GetSystemStatusService{c: c} +} + +func (c *Client) NewGetAllCoinsInfoService() *GetAllCoinsInfoService { + return &GetAllCoinsInfoService{c: c} +} + +func (c *Client) NewGetAccountSnapshotService() *GetAccountSnapshotService { + return &GetAccountSnapshotService{c: c} +} + +func (c *Client) NewDisableFastWithdrawSwitchService() *DisableFastWithdrawSwitchService { + return &DisableFastWithdrawSwitchService{c: c} +} + +func (c *Client) NewEnableFastWithdrawSwitchService() *EnableFastWithdrawSwitchService { + return &EnableFastWithdrawSwitchService{c: c} +} + +func (c *Client) NewWithdrawService() *WithdrawService { + return &WithdrawService{c: c} +} + +func (c *Client) NewDepositHistoryService() *DepositHistoryService { + return &DepositHistoryService{c: c} +} + +func (c *Client) NewWithdrawHistoryService() *WithdrawHistoryService { + return &WithdrawHistoryService{c: c} +} + +func (c *Client) NewDepositAddressService() *DepositAddressService { + return &DepositAddressService{c: c} +} + +func (c *Client) NewAccountStatusService() *AccountStatusService { + return &AccountStatusService{c: c} +} + +func (c *Client) NewAccountApiTradingStatusService() *AccountApiTradingStatusService { + return &AccountApiTradingStatusService{c: c} +} + +func (c *Client) NewDustLogService() *DustLogService { + return &DustLogService{c: c} +} + +func (c *Client) NewAssetDetailService() *AssetDetailService { + return &AssetDetailService{c: c} +} + +func (c *Client) NewDustTransferService() *DustTransferService { + return &DustTransferService{c: c} +} + +func (c *Client) NewAssetDividendRecordService() *AssetDividendRecordService { + return &AssetDividendRecordService{c: c} +} + +func (c *Client) NewAssetDetailV2Service() *AssetDetailV2Service { + return &AssetDetailV2Service{c: c} +} + +func (c *Client) NewTradeFeeService() *TradeFeeService { + return &TradeFeeService{c: c} +} + +func (c *Client) NewUserUniversalTransferService() *UserUniversalTransferService { + return &UserUniversalTransferService{c: c} +} + +func (c *Client) NewUserUniversalTransferHistoryService() *UserUniversalTransferHistoryService { + return &UserUniversalTransferHistoryService{c: c} +} + +func (c *Client) NewFundingWalletService() *FundingWalletService { + return &FundingWalletService{c: c} +} + +func (c *Client) NewUserAssetService() *UserAssetService { + return &UserAssetService{c: c} +} + +func (c *Client) NewBUSDConvertService() *BUSDConvertService { + return &BUSDConvertService{c: c} +} + +func (c *Client) NewBUSDConvertHistoryService() *BUSDConvertHistoryService { + return &BUSDConvertHistoryService{c: c} +} + +func (c *Client) NewCloudMiningPaymentHistoryService() *CloudMiningPaymentHistoryService { + return &CloudMiningPaymentHistoryService{c: c} +} + +func (c *Client) NewAPIKeyPermissionService() *APIKeyPermissionService { + return &APIKeyPermissionService{c: c} +} + +func (c *Client) NewAutoConvertStableCoinService() *AutoConvertStableCoinService { + return &AutoConvertStableCoinService{c: c} +} + +// User Data Streams: +func (c *Client) NewCreateListenKeyService() *CreateListenKey { + return &CreateListenKey{c: c} +} + +func (c *Client) NewPingUserStream() *PingUserStream { + return &PingUserStream{c: c} +} + +func (c *Client) NewCloseUserStream() *CloseUserStream { + return &CloseUserStream{c: c} +} diff --git a/consts.go b/consts.go new file mode 100644 index 0000000..7997b9f --- /dev/null +++ b/consts.go @@ -0,0 +1,5 @@ +package binance_connector + +const Name = "binance-connector-go" + +const Version = "0.1.0" diff --git a/examples/account/CancelOCO/CancelOCO.go b/examples/account/CancelOCO/CancelOCO.go new file mode 100644 index 0000000..2b987f6 --- /dev/null +++ b/examples/account/CancelOCO/CancelOCO.go @@ -0,0 +1,29 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + CancelOCO() +} + +func CancelOCO() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // Binance Cancel OCO (TRADE) - DELETE /api/v3/orderList + cancelOCO, err := client.NewCancelOCOService().Symbol("BTCUSDT"). + Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(cancelOCO)) +} diff --git a/examples/account/CancelOpenOrders/CancelOpenOrders.go b/examples/account/CancelOpenOrders/CancelOpenOrders.go new file mode 100644 index 0000000..701625c --- /dev/null +++ b/examples/account/CancelOpenOrders/CancelOpenOrders.go @@ -0,0 +1,29 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + CancelOpenOrders() +} + +func CancelOpenOrders() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // Binance Cancel all open orders on a symbol - DELETE /api/v3/openOrders + cancelOpenOrders, err := client.NewCancelOpenOrdersService().Symbol("BTCUSDT"). + Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(cancelOpenOrders)) +} diff --git a/examples/account/CancelOrder/CancelOrder.go b/examples/account/CancelOrder/CancelOrder.go new file mode 100644 index 0000000..c30434a --- /dev/null +++ b/examples/account/CancelOrder/CancelOrder.go @@ -0,0 +1,29 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + CancelOrder() +} + +func CancelOrder() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // Binance Cancel Order endpoint - DELETE /api/v3/order + cancelOrder, err := client.NewCancelOrderService().Symbol("BTCUSDT"). + Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(cancelOrder)) +} diff --git a/examples/account/CancelReplace/CancelReplace.go b/examples/account/CancelReplace/CancelReplace.go new file mode 100644 index 0000000..6ae9a44 --- /dev/null +++ b/examples/account/CancelReplace/CancelReplace.go @@ -0,0 +1,30 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + CancelReplace() +} + +func CancelReplace() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // Cancel an Existing Order and Send a New Order (TRADE) - POST /api/v3/order/cancelReplace + cancelReplace, err := client.NewCancelReplaceService(). + Symbol("BTCUSDT").Side("BUY").OrderType("LIMIT").CancelReplaceMode("STOP_ON_FAILURE"). + TimeInForce("GTC").Quantity(0.001).Price(20000.0).Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(cancelReplace)) +} diff --git a/examples/account/CreateOrder/CreateOrder.go b/examples/account/CreateOrder/CreateOrder.go new file mode 100644 index 0000000..86f0a82 --- /dev/null +++ b/examples/account/CreateOrder/CreateOrder.go @@ -0,0 +1,30 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + NewOrder() +} + +func NewOrder() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // Binance New Order endpoint - POST /api/v3/order + newOrder, err := client.NewCreateOrderService().Symbol("BTCUSDT"). + Side("BUY").Type("MARKET").Quantity(0.001). + Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(newOrder)) +} diff --git a/examples/account/GetAccount/GetAccount.go b/examples/account/GetAccount/GetAccount.go new file mode 100644 index 0000000..19a209a --- /dev/null +++ b/examples/account/GetAccount/GetAccount.go @@ -0,0 +1,28 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + AccountInformation() +} + +func AccountInformation() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // Binance Account Information (USER_DATA) - GET /api/v3/account + accountInformation, err := client.NewGetAccountService().Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(accountInformation)) +} diff --git a/examples/account/GetAllOrders/GetAllOrders.go b/examples/account/GetAllOrders/GetAllOrders.go new file mode 100644 index 0000000..8dddba0 --- /dev/null +++ b/examples/account/GetAllOrders/GetAllOrders.go @@ -0,0 +1,29 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + GetAllOrders() +} + +func GetAllOrders() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // Binance Get all account orders; active, canceled, or filled - GET /api/v3/allOrders + getAllOrders, err := client.NewGetAllOrdersService().Symbol("BTCUSDT"). + Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(getAllOrders)) +} diff --git a/examples/account/GetMyTrades/GetMyTrades.go b/examples/account/GetMyTrades/GetMyTrades.go new file mode 100644 index 0000000..5cafffe --- /dev/null +++ b/examples/account/GetMyTrades/GetMyTrades.go @@ -0,0 +1,29 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + GetMyTrades() +} + +func GetMyTrades() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // Binance Get trades for a specific account and symbol (USER_DATA) - GET /api/v3/myTrades + getMyTradesService, err := client.NewGetMyTradesService(). + Symbol("BTCUSDT").Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(getMyTradesService)) +} diff --git a/examples/account/GetOpenOrders/GetOpenOrders.go b/examples/account/GetOpenOrders/GetOpenOrders.go new file mode 100644 index 0000000..a1d834d --- /dev/null +++ b/examples/account/GetOpenOrders/GetOpenOrders.go @@ -0,0 +1,29 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + GetCurrentOpenOrders() +} + +func GetCurrentOpenOrders() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // Binance Get current open orders - GET /api/v3/openOrders + getCurrentOpenOrders, err := client.NewGetOpenOrdersService().Symbol("BTCUSDT"). + Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(getCurrentOpenOrders)) +} diff --git a/examples/account/GetOrder/GetOrder.go b/examples/account/GetOrder/GetOrder.go new file mode 100644 index 0000000..e6ea1b5 --- /dev/null +++ b/examples/account/GetOrder/GetOrder.go @@ -0,0 +1,29 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + QueryOrder() +} + +func QueryOrder() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // Binance Query Order (USER_DATA) - GET /api/v3/order + queryOrder, err := client.NewGetOrderService().Symbol("BTCUSDT"). + OrderId(20064739).Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(queryOrder)) +} diff --git a/examples/account/NewOCO/NewOCO.go b/examples/account/NewOCO/NewOCO.go new file mode 100644 index 0000000..2d9a1ad --- /dev/null +++ b/examples/account/NewOCO/NewOCO.go @@ -0,0 +1,30 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + NewOCO() +} + +func NewOCO() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // Binance New OCO (TRADE) - POST /api/v3/order/oco + newOCO, err := client.NewNewOCOService().Symbol("LTCBNB"). + Side("BUY").Quantity(0.1).Price(0.28).StopPrice(0.22). + Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(newOCO)) +} diff --git a/examples/account/QueryAllOCO/QueryAllOCO.go b/examples/account/QueryAllOCO/QueryAllOCO.go new file mode 100644 index 0000000..29cd46c --- /dev/null +++ b/examples/account/QueryAllOCO/QueryAllOCO.go @@ -0,0 +1,29 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + QueryAllOCO() +} + +func QueryAllOCO() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // Binance Query all OCO (USER_DATA) (GET /api/v3/allOrderList) + queryAllOCO, err := client.NewQueryAllOCOService(). + Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(queryAllOCO)) +} diff --git a/examples/account/QueryCurrentOrderCountUsage/QueryCurrentOrderCountUsage.go b/examples/account/QueryCurrentOrderCountUsage/QueryCurrentOrderCountUsage.go new file mode 100644 index 0000000..7b35dea --- /dev/null +++ b/examples/account/QueryCurrentOrderCountUsage/QueryCurrentOrderCountUsage.go @@ -0,0 +1,29 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + QueryCurrentOrderCountUsage() +} + +func QueryCurrentOrderCountUsage() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // Query Current Order Count Usage (TRADE) + getQueryCurrentOrderCountUsageService, err := client.NewGetQueryCurrentOrderCountUsageService(). + Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(getQueryCurrentOrderCountUsageService)) +} diff --git a/examples/account/QueryOCO/QueryOCO.go b/examples/account/QueryOCO/QueryOCO.go new file mode 100644 index 0000000..a847942 --- /dev/null +++ b/examples/account/QueryOCO/QueryOCO.go @@ -0,0 +1,28 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + QueryOCO() +} + +func QueryOCO() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // Binance Query OCO (USER_DATA) - GET /api/v3/orderList + queryOCO, err := client.NewQueryOCOService().Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(queryOCO)) +} diff --git a/examples/account/QueryOpenOCO/QueryOpenOCO.go b/examples/account/QueryOpenOCO/QueryOpenOCO.go new file mode 100644 index 0000000..6270914 --- /dev/null +++ b/examples/account/QueryOpenOCO/QueryOpenOCO.go @@ -0,0 +1,28 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + QueryOpenOCO() +} + +func QueryOpenOCO() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // Binance Query open OCO (USER_DATA) - GET /api/v3/openOrderList + queryOpenOCO, err := client.NewQueryOpenOCOService().Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(queryOpenOCO)) +} diff --git a/examples/account/QueryPreventedMatches/QueryPreventedMatches.go b/examples/account/QueryPreventedMatches/QueryPreventedMatches.go new file mode 100644 index 0000000..e4dd133 --- /dev/null +++ b/examples/account/QueryPreventedMatches/QueryPreventedMatches.go @@ -0,0 +1,29 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + QueryPreventedMatches() +} + +func QueryPreventedMatches() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // Query Prevented Matches (USER_DATA) - GET /api/v3/preventedMatches + getQueryPreventedMatchesService, err := client.NewGetQueryPreventedMatchesService(). + Symbol("BTCUSDT").Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(getQueryPreventedMatchesService)) +} diff --git a/examples/account/TestNewOrder/TestNewOrder.go b/examples/account/TestNewOrder/TestNewOrder.go new file mode 100644 index 0000000..c848ec0 --- /dev/null +++ b/examples/account/TestNewOrder/TestNewOrder.go @@ -0,0 +1,30 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + TestNewOrder() +} + +func TestNewOrder() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // Binance Test New Order endpoint - POST /api/v3/order/test + testNewOrder, err := client.NewTestNewOrder().Symbol("BTCUSDT"). + Side("BUY").OrderType("MARKET").Quantity(0.001). + Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(testNewOrder)) +} diff --git a/examples/margin/AllIsolatedMarginSymbol/AllIsolatedMarginSymbol.go b/examples/margin/AllIsolatedMarginSymbol/AllIsolatedMarginSymbol.go new file mode 100644 index 0000000..ec0e05b --- /dev/null +++ b/examples/margin/AllIsolatedMarginSymbol/AllIsolatedMarginSymbol.go @@ -0,0 +1,29 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + AllIsolatedMarginSymbol() +} + +func AllIsolatedMarginSymbol() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // AllIsolatedMarginSymbolService - /sapi/v1/margin/isolated/allPairs + allIsolatedMarginSymbol, err := client.NewAllIsolatedMarginSymbolService(). + Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(allIsolatedMarginSymbol)) +} diff --git a/examples/margin/Borrow/Borrow.go b/examples/margin/Borrow/Borrow.go new file mode 100644 index 0000000..e110218 --- /dev/null +++ b/examples/margin/Borrow/Borrow.go @@ -0,0 +1,29 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + Borrow() +} + +func Borrow() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // BorrowService - /sapi/v1/margin/loan + borrow, err := client.NewBorrowService().Asset("USDT").Amount(50.0). + Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(borrow)) +} diff --git a/examples/margin/CrossMarginAccountDetail/CrossMarginAccountDetail.go b/examples/margin/CrossMarginAccountDetail/CrossMarginAccountDetail.go new file mode 100644 index 0000000..fb9429c --- /dev/null +++ b/examples/margin/CrossMarginAccountDetail/CrossMarginAccountDetail.go @@ -0,0 +1,28 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + CrossMarginAccountDetail() +} + +func CrossMarginAccountDetail() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // CrossMarginAccountDetailService - /sapi/v1/margin/account + crossMarginAccountDetail, err := client.NewCrossMarginAccountDetailService().Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(crossMarginAccountDetail)) +} diff --git a/examples/margin/CrossMarginTransferHistory/CrossMarginTransferHistory.go b/examples/margin/CrossMarginTransferHistory/CrossMarginTransferHistory.go new file mode 100644 index 0000000..88ecebe --- /dev/null +++ b/examples/margin/CrossMarginTransferHistory/CrossMarginTransferHistory.go @@ -0,0 +1,29 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + CrossMarginTransferHistory() +} + +func CrossMarginTransferHistory() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // CrossMarginTransferHistoryService - /sapi/v1/margin/transfer + crossMarginTransferHistory, err := client.NewCrossMarginTransferHistoryService(). + Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(crossMarginTransferHistory)) +} diff --git a/examples/margin/ForceLiquidationRecord/ForceLiquidationRecord.go b/examples/margin/ForceLiquidationRecord/ForceLiquidationRecord.go new file mode 100644 index 0000000..26f0e72 --- /dev/null +++ b/examples/margin/ForceLiquidationRecord/ForceLiquidationRecord.go @@ -0,0 +1,29 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + ForceLiquidationRecord() +} + +func ForceLiquidationRecord() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // ForceLiquidationRecordService - /sapi/v1/margin/forceLiquidationRec + forceLiquidationRecord, err := client.NewForceLiquidationRecordService(). + Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(forceLiquidationRecord)) +} diff --git a/examples/margin/GetAllMarginAssets/GetAllMarginAssets.go b/examples/margin/GetAllMarginAssets/GetAllMarginAssets.go new file mode 100644 index 0000000..cfbfcc5 --- /dev/null +++ b/examples/margin/GetAllMarginAssets/GetAllMarginAssets.go @@ -0,0 +1,28 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + GetAllMarginAssets() +} + +func GetAllMarginAssets() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // GetAllMarginAssetsService - /sapi/v1/margin/allAssets + getAllMarginAssets, err := client.NewGetAllMarginAssetsService().Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(getAllMarginAssets)) +} diff --git a/examples/margin/GetAllMarginPairs/GetAllMarginPairs.go b/examples/margin/GetAllMarginPairs/GetAllMarginPairs.go new file mode 100644 index 0000000..0655ea9 --- /dev/null +++ b/examples/margin/GetAllMarginPairs/GetAllMarginPairs.go @@ -0,0 +1,28 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + GetAllMarginPairs() +} + +func GetAllMarginPairs() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // GetAllMarginPairsService - /sapi/v1/margin/allPairs + getAllMarginPairs, err := client.NewGetAllMarginPairsService().Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(getAllMarginPairs)) +} diff --git a/examples/margin/InterestHistory/InterestHistory.go b/examples/margin/InterestHistory/InterestHistory.go new file mode 100644 index 0000000..f7b38f6 --- /dev/null +++ b/examples/margin/InterestHistory/InterestHistory.go @@ -0,0 +1,28 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + InterestHistory() +} + +func InterestHistory() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // InterestHistoryService - /sapi/v1/margin/interestHistory + interestHistory, err := client.NewInterestHistoryService().Asset("USDT").Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(interestHistory)) +} diff --git a/examples/margin/LoanRecord/LoanRecord.go b/examples/margin/LoanRecord/LoanRecord.go new file mode 100644 index 0000000..5af57ef --- /dev/null +++ b/examples/margin/LoanRecord/LoanRecord.go @@ -0,0 +1,28 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + LoanRecord() +} + +func LoanRecord() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // LoanRecordService - /sapi/v1/margin/loan + loanRecord, err := client.NewLoanRecordService().Asset("BTC").Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(loanRecord)) +} diff --git a/examples/margin/MarginAccountAllOrder/MarginAccountAllOrder.go b/examples/margin/MarginAccountAllOrder/MarginAccountAllOrder.go new file mode 100644 index 0000000..73c726d --- /dev/null +++ b/examples/margin/MarginAccountAllOrder/MarginAccountAllOrder.go @@ -0,0 +1,29 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + MarginAccountAllOrder() +} + +func MarginAccountAllOrder() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // MarginAccountAllOrderService - /sapi/v1/margin/allOrders + marginAccountAllOrder, err := client.NewMarginAccountAllOrderService().Symbol("BTCUSDT"). + Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(marginAccountAllOrder)) +} diff --git a/examples/margin/MarginAccountCancelAllOrders/MarginAccountCancelAllOrders.go b/examples/margin/MarginAccountCancelAllOrders/MarginAccountCancelAllOrders.go new file mode 100644 index 0000000..e3666d3 --- /dev/null +++ b/examples/margin/MarginAccountCancelAllOrders/MarginAccountCancelAllOrders.go @@ -0,0 +1,29 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + MarginAccountCancelAllOrders() +} + +func MarginAccountCancelAllOrders() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // MarginAccountCancelAllOrdersService - /sapi/v1/margin/openOrders + marginAccountCancelAllOrders, err := client.NewMarginAccountCancelAllOrdersService().Symbol("BTCUSDT"). + Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(marginAccountCancelAllOrders)) +} diff --git a/examples/margin/MarginAccountCancelOCO/MarginAccountCancelOCO.go b/examples/margin/MarginAccountCancelOCO/MarginAccountCancelOCO.go new file mode 100644 index 0000000..71338f9 --- /dev/null +++ b/examples/margin/MarginAccountCancelOCO/MarginAccountCancelOCO.go @@ -0,0 +1,29 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + MarginAccountCancelOCO() +} + +func MarginAccountCancelOCO() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // MarginAccountCancelOCOService - /sapi/v1/margin/orderList + marginAccountCancelOCO, err := client.NewMarginAccountCancelOCOService().Symbol("BTCUSDT"). + Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(marginAccountCancelOCO)) +} diff --git a/examples/margin/MarginAccountCancelOrder/MarginAccountCancelOrder.go b/examples/margin/MarginAccountCancelOrder/MarginAccountCancelOrder.go new file mode 100644 index 0000000..ccbd423 --- /dev/null +++ b/examples/margin/MarginAccountCancelOrder/MarginAccountCancelOrder.go @@ -0,0 +1,29 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + MarginAccountCancelOrder() +} + +func MarginAccountCancelOrder() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // MarginAccountCancelOrderService - /sapi/v1/margin/order + marginAccountCancelOrder, err := client.NewMarginAccountCancelOrderService().Symbol("BTCUSDT"). + Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(marginAccountCancelOrder)) +} diff --git a/examples/margin/MarginAccountNewOCO/MarginAccountNewOCO.go b/examples/margin/MarginAccountNewOCO/MarginAccountNewOCO.go new file mode 100644 index 0000000..6d2a9c6 --- /dev/null +++ b/examples/margin/MarginAccountNewOCO/MarginAccountNewOCO.go @@ -0,0 +1,30 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + MarginAccountNewOCO() +} + +func MarginAccountNewOCO() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // MarginAccountNewOCOService - /sapi/v1/margin/order/oco + marginAccountNewOCO, err := client.NewMarginAccountNewOCOService().Symbol("BTCUSDT"). + Side("BUY").Quantity(0.01).Price(20000).StopPrice(18000). + Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(marginAccountNewOCO)) +} diff --git a/examples/margin/MarginAccountNewOrder/MarginAccountNewOrder.go b/examples/margin/MarginAccountNewOrder/MarginAccountNewOrder.go new file mode 100644 index 0000000..4b368ee --- /dev/null +++ b/examples/margin/MarginAccountNewOrder/MarginAccountNewOrder.go @@ -0,0 +1,29 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + MarginAccountNewOrder() +} + +func MarginAccountNewOrder() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // MarginAccountNewOrderService - /sapi/v1/margin/order + marginAccountNewOrder, err := client.NewMarginAccountNewOrderService().Symbol("BTCUSDT"). + Side("BUY").OrderType("MARKET").Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(marginAccountNewOrder)) +} diff --git a/examples/margin/MarginAccountOpenOrder/MarginAccountOpenOrder.go b/examples/margin/MarginAccountOpenOrder/MarginAccountOpenOrder.go new file mode 100644 index 0000000..732d898 --- /dev/null +++ b/examples/margin/MarginAccountOpenOrder/MarginAccountOpenOrder.go @@ -0,0 +1,29 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + MarginAccountOpenOrder() +} + +func MarginAccountOpenOrder() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // MarginAccountOpenOrderService - /sapi/v1/margin/openOrders + marginAccountOpenOrder, err := client.NewMarginAccountOpenOrderService().Symbol("BTCUSDT"). + Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(marginAccountOpenOrder)) +} diff --git a/examples/margin/MarginAccountOrder/MarginAccountOrder.go b/examples/margin/MarginAccountOrder/MarginAccountOrder.go new file mode 100644 index 0000000..6842fec --- /dev/null +++ b/examples/margin/MarginAccountOrder/MarginAccountOrder.go @@ -0,0 +1,29 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + MarginAccountOrder() +} + +func MarginAccountOrder() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // MarginAccountOrderService - /sapi/v1/margin/order + marginAccountOrder, err := client.NewMarginAccountOrderService().Symbol("BTCUSDT"). + Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(marginAccountOrder)) +} diff --git a/examples/margin/MarginAccountQueryAllOCO/MarginAccountQueryAllOCO.go b/examples/margin/MarginAccountQueryAllOCO/MarginAccountQueryAllOCO.go new file mode 100644 index 0000000..88cc16c --- /dev/null +++ b/examples/margin/MarginAccountQueryAllOCO/MarginAccountQueryAllOCO.go @@ -0,0 +1,29 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + MarginAccountQueryAllOCO() +} + +func MarginAccountQueryAllOCO() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // MarginAccountQueryAllOCOService - /sapi/v1/margin/allOrderList + marginAccountQueryAllOCO, err := client.NewMarginAccountQueryAllOCOService(). + Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(marginAccountQueryAllOCO)) +} diff --git a/examples/margin/MarginAccountQueryMaxBorrow/MarginAccountQueryMaxBorrow.go b/examples/margin/MarginAccountQueryMaxBorrow/MarginAccountQueryMaxBorrow.go new file mode 100644 index 0000000..ecdf447 --- /dev/null +++ b/examples/margin/MarginAccountQueryMaxBorrow/MarginAccountQueryMaxBorrow.go @@ -0,0 +1,29 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + MarginAccountQueryMaxBorrow() +} + +func MarginAccountQueryMaxBorrow() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // MarginAccountQueryMaxBorrowService - /sapi/v1/margin/maxBorrowable + marginAccountQueryMaxBorrow, err := client.NewMarginAccountQueryMaxBorrowService().Asset("USDT"). + Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(marginAccountQueryMaxBorrow)) +} diff --git a/examples/margin/MarginAccountQueryMaxTransferOutAmount/MarginAccountQueryMaxTransferOut.go b/examples/margin/MarginAccountQueryMaxTransferOutAmount/MarginAccountQueryMaxTransferOut.go new file mode 100644 index 0000000..1a55a2e --- /dev/null +++ b/examples/margin/MarginAccountQueryMaxTransferOutAmount/MarginAccountQueryMaxTransferOut.go @@ -0,0 +1,29 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + MarginAccountQueryMaxTransferOutAmount() +} + +func MarginAccountQueryMaxTransferOutAmount() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // MarginAccountQueryMaxTransferOutAmountService - /sapi/v1/margin/maxTransferable + marginAccountQueryMaxTransferOutAmount, err := client.NewMarginAccountQueryMaxTransferOutAmountService(). + Asset("USDT").Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(marginAccountQueryMaxTransferOutAmount)) +} diff --git a/examples/margin/MarginAccountQueryOCO/MarginAccountQueryOCO.go b/examples/margin/MarginAccountQueryOCO/MarginAccountQueryOCO.go new file mode 100644 index 0000000..fb27430 --- /dev/null +++ b/examples/margin/MarginAccountQueryOCO/MarginAccountQueryOCO.go @@ -0,0 +1,29 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + MarginAccountQueryOCO() +} + +func MarginAccountQueryOCO() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // MarginAccountQueryOCOService - /sapi/v1/margin/orderList + marginAccountQueryOCO, err := client.NewMarginAccountQueryOCOService(). + Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(marginAccountQueryOCO)) +} diff --git a/examples/margin/MarginAccountQueryOpenOCO/MarginAccountQueryOpenOCO.go b/examples/margin/MarginAccountQueryOpenOCO/MarginAccountQueryOpenOCO.go new file mode 100644 index 0000000..29027d1 --- /dev/null +++ b/examples/margin/MarginAccountQueryOpenOCO/MarginAccountQueryOpenOCO.go @@ -0,0 +1,29 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + MarginAccountQueryOpenOCO() +} + +func MarginAccountQueryOpenOCO() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // MarginAccountQueryOpenOCOService - /sapi/v1/margin/openOrderList + marginAccountQueryOpenOCO, err := client.NewMarginAccountQueryOpenOCOService(). + Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(marginAccountQueryOpenOCO)) +} diff --git a/examples/margin/MarginAccountQueryTradeList/MarginAccountQueryTradeList.go b/examples/margin/MarginAccountQueryTradeList/MarginAccountQueryTradeList.go new file mode 100644 index 0000000..bbfc3df --- /dev/null +++ b/examples/margin/MarginAccountQueryTradeList/MarginAccountQueryTradeList.go @@ -0,0 +1,29 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + MarginAccountQueryTradeList() +} + +func MarginAccountQueryTradeList() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // MarginAccountQueryTradeListService - /sapi/v1/margin/myTrades + marginAccountQueryTradeList, err := client.NewMarginAccountQueryTradeListService().Symbol("BTCUSD"). + Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(marginAccountQueryTradeList)) +} diff --git a/examples/margin/MarginAccountSummary/MarginAccountSummary.go b/examples/margin/MarginAccountSummary/MarginAccountSummary.go new file mode 100644 index 0000000..86192b2 --- /dev/null +++ b/examples/margin/MarginAccountSummary/MarginAccountSummary.go @@ -0,0 +1,28 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + MarginAccountSummary() +} + +func MarginAccountSummary() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // MarginAccountSummaryService - /sapi/v1/margin/tradeCoeff + marginAccountSummary, err := client.NewMarginAccountSummaryService().Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(marginAccountSummary)) +} diff --git a/examples/margin/MarginBnbBurnStatus/MarginBnbBurnStatus.go b/examples/margin/MarginBnbBurnStatus/MarginBnbBurnStatus.go new file mode 100644 index 0000000..2c48f08 --- /dev/null +++ b/examples/margin/MarginBnbBurnStatus/MarginBnbBurnStatus.go @@ -0,0 +1,28 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + MarginBnbBurnStatus() +} + +func MarginBnbBurnStatus() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // MarginBnbBurnStatusService - /sapi/v1/bnbBurn + marginBnbBurnStatus, err := client.NewMarginBnbBurnStatusService().Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(marginBnbBurnStatus)) +} diff --git a/examples/margin/MarginCrossCollateralRatio/MarginCrossCollateralRatio.go b/examples/margin/MarginCrossCollateralRatio/MarginCrossCollateralRatio.go new file mode 100644 index 0000000..0828d5b --- /dev/null +++ b/examples/margin/MarginCrossCollateralRatio/MarginCrossCollateralRatio.go @@ -0,0 +1,29 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + MarginCrossCollateralRatio() +} + +func MarginCrossCollateralRatio() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // MarginCrossCollateralRatioService - /sapi/v1/margin/crossMarginCollateralRatio + marginCrossCollateralRatio, err := client.NewMarginCrossCollateralRatioService(). + Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(marginCrossCollateralRatio)) +} diff --git a/examples/margin/MarginCrossMarginFee/MarginCrossMarginFee.go b/examples/margin/MarginCrossMarginFee/MarginCrossMarginFee.go new file mode 100644 index 0000000..7d6fd51 --- /dev/null +++ b/examples/margin/MarginCrossMarginFee/MarginCrossMarginFee.go @@ -0,0 +1,29 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + MarginCrossMarginFee() +} + +func MarginCrossMarginFee() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // MarginCrossMarginFeeService - /sapi/v1/margin/crossMarginData + marginCrossMarginFee, err := client.NewMarginCrossMarginFeeService(). + Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(marginCrossMarginFee)) +} diff --git a/examples/margin/MarginCurrentOrderCount/MarginCurrentOrderCount.go b/examples/margin/MarginCurrentOrderCount/MarginCurrentOrderCount.go new file mode 100644 index 0000000..c061a48 --- /dev/null +++ b/examples/margin/MarginCurrentOrderCount/MarginCurrentOrderCount.go @@ -0,0 +1,29 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + MarginCurrentOrderCount() +} + +func MarginCurrentOrderCount() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // MarginCurrentOrderCountService - /sapi/v1/margin/rateLimit/order + marginCurrentOrderCount, err := client.NewMarginCurrentOrderCountService(). + Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(marginCurrentOrderCount)) +} diff --git a/examples/margin/MarginDustlog/MarginDustlog.go b/examples/margin/MarginDustlog/MarginDustlog.go new file mode 100644 index 0000000..2c6b316 --- /dev/null +++ b/examples/margin/MarginDustlog/MarginDustlog.go @@ -0,0 +1,29 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + MarginDustlog() +} + +func MarginDustlog() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // MarginDustlogService - /sapi/v1/margin/dribblet + marginDustlog, err := client.NewMarginDustlogService(). + Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(marginDustlog)) +} diff --git a/examples/margin/MarginInterestRateHistory/MarginInterestRateHistory.go b/examples/margin/MarginInterestRateHistory/MarginInterestRateHistory.go new file mode 100644 index 0000000..277d4a9 --- /dev/null +++ b/examples/margin/MarginInterestRateHistory/MarginInterestRateHistory.go @@ -0,0 +1,29 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + MarginInterestRateHistory() +} + +func MarginInterestRateHistory() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // MarginInterestRateHistoryService - /sapi/v1/margin/interestRateHistory + marginInterestRateHistory, err := client.NewMarginInterestRateHistoryService().Asset("USDT"). + Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(marginInterestRateHistory)) +} diff --git a/examples/margin/MarginIsolatedAccountDisable/MarginIsolatedAccountDisable.go b/examples/margin/MarginIsolatedAccountDisable/MarginIsolatedAccountDisable.go new file mode 100644 index 0000000..f2d8b82 --- /dev/null +++ b/examples/margin/MarginIsolatedAccountDisable/MarginIsolatedAccountDisable.go @@ -0,0 +1,29 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + MarginIsolatedAccountDisable() +} + +func MarginIsolatedAccountDisable() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // MarginIsolatedAccountDisableService - /sapi/v1/margin/isolated/account + marginIsolatedAccountDisable, err := client.NewMarginIsolatedAccountDisableService().Symbol("BTCUSDT"). + Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(marginIsolatedAccountDisable)) +} diff --git a/examples/margin/MarginIsolatedAccountEnable/MarginisolatedAccountEnable.go b/examples/margin/MarginIsolatedAccountEnable/MarginisolatedAccountEnable.go new file mode 100644 index 0000000..9f9cca4 --- /dev/null +++ b/examples/margin/MarginIsolatedAccountEnable/MarginisolatedAccountEnable.go @@ -0,0 +1,29 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + MarginIsolatedAccountEnable() +} + +func MarginIsolatedAccountEnable() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // MarginIsolatedAccountEnableService - /sapi/v1/margin/isolated/account + marginIsolatedAccountEnable, err := client.NewMarginIsolatedAccountEnableService().Symbol("BTCUSDT"). + Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(marginIsolatedAccountEnable)) +} diff --git a/examples/margin/MarginIsolatedAccountInfo/MarginIsolatedAccountInfo.go b/examples/margin/MarginIsolatedAccountInfo/MarginIsolatedAccountInfo.go new file mode 100644 index 0000000..fce4342 --- /dev/null +++ b/examples/margin/MarginIsolatedAccountInfo/MarginIsolatedAccountInfo.go @@ -0,0 +1,28 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + MarginIsolatedAccountInfo() +} + +func MarginIsolatedAccountInfo() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // MarginIsolatedAccountInfoService - /sapi/v1/margin/isolated/account + marginIsolatedAccountInfo, err := client.NewMarginIsolatedAccountInfoService().Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(marginIsolatedAccountInfo)) +} diff --git a/examples/margin/MarginIsolatedAccountLimit/MarginIsolatedAccountLimit.go b/examples/margin/MarginIsolatedAccountLimit/MarginIsolatedAccountLimit.go new file mode 100644 index 0000000..58ddf1e --- /dev/null +++ b/examples/margin/MarginIsolatedAccountLimit/MarginIsolatedAccountLimit.go @@ -0,0 +1,29 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + MarginIsolatedAccountLimit() +} + +func MarginIsolatedAccountLimit() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // MarginIsolatedAccountLimitService - /sapi/v1/margin/isolated/accountLimit + marginIsolatedAccountLimit, err := client.NewMarginIsolatedAccountLimitService(). + Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(marginIsolatedAccountLimit)) +} diff --git a/examples/margin/MarginIsolatedAccountTransfer/MarginIsolatedAccountTransfer.go b/examples/margin/MarginIsolatedAccountTransfer/MarginIsolatedAccountTransfer.go new file mode 100644 index 0000000..ccd1e57 --- /dev/null +++ b/examples/margin/MarginIsolatedAccountTransfer/MarginIsolatedAccountTransfer.go @@ -0,0 +1,29 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + MarginIsolatedAccountTransfer() +} + +func MarginIsolatedAccountTransfer() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // MarginIsolatedAccountTransferService - /sapi/v1/margin/isolated/transfer + marginIsolatedAccountTransfer, err := client.NewMarginIsolatedAccountTransferService().Asset("USDT"). + Symbol("BTCUSDT").TransFrom("SPOT").TransTo("ISOLATED_MARGIN").Amount(100).Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(marginIsolatedAccountTransfer)) +} diff --git a/examples/margin/MarginIsolatedAccountTransferHistory/MarginIsolatedAccountTransferHistory.go b/examples/margin/MarginIsolatedAccountTransferHistory/MarginIsolatedAccountTransferHistory.go new file mode 100644 index 0000000..3b443d9 --- /dev/null +++ b/examples/margin/MarginIsolatedAccountTransferHistory/MarginIsolatedAccountTransferHistory.go @@ -0,0 +1,29 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + MarginIsolatedAccountTransferHistory() +} + +func MarginIsolatedAccountTransferHistory() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // MarginIsolatedAccountTransferHistoryService - /sapi/v1/margin/isolated/transfer + marginIsolatedAccountTransferHistory, err := client.NewMarginIsolatedAccountTransferHistoryService(). + Symbol("BTCUSDT").Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(marginIsolatedAccountTransferHistory)) +} diff --git a/examples/margin/MarginIsolatedMarginFee/MarginIsolatedMarginFee.go b/examples/margin/MarginIsolatedMarginFee/MarginIsolatedMarginFee.go new file mode 100644 index 0000000..bd3319d --- /dev/null +++ b/examples/margin/MarginIsolatedMarginFee/MarginIsolatedMarginFee.go @@ -0,0 +1,29 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + MarginIsolatedMarginFee() +} + +func MarginIsolatedMarginFee() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // MarginIsolatedMarginFeeService - /sapi/v1/margin/isolatedMarginData + marginIsolatedMarginFee, err := client.NewMarginIsolatedMarginFeeService(). + Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(marginIsolatedMarginFee)) +} diff --git a/examples/margin/MarginIsolatedMarginTier/MarginIsolatedMarginTier.go b/examples/margin/MarginIsolatedMarginTier/MarginIsolatedMarginTier.go new file mode 100644 index 0000000..14600bd --- /dev/null +++ b/examples/margin/MarginIsolatedMarginTier/MarginIsolatedMarginTier.go @@ -0,0 +1,29 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + MarginIsolatedMarginTier() +} + +func MarginIsolatedMarginTier() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // MarginIsolatedMarginTierService - /sapi/v1/margin/isolatedMarginTier + marginIsolatedMarginTier, err := client.NewMarginIsolatedMarginTierService(). + Symbol("BTCUSDT").Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(marginIsolatedMarginTier)) +} diff --git a/examples/margin/MarginIsolatedSymbol/MarginIsolatedSymbol.go b/examples/margin/MarginIsolatedSymbol/MarginIsolatedSymbol.go new file mode 100644 index 0000000..374d258 --- /dev/null +++ b/examples/margin/MarginIsolatedSymbol/MarginIsolatedSymbol.go @@ -0,0 +1,29 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + MarginIsolatedSymbol() +} + +func MarginIsolatedSymbol() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // MarginIsolatedSymbolService - /sapi/v1/margin/isolated/pair + marginIsolatedSymbol, err := client.NewMarginIsolatedSymbolService().Symbol("BTCUSDT"). + Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(marginIsolatedSymbol)) +} diff --git a/examples/margin/MarginSmallLiabilityExchange/MarginSmallLiabilityExchange.go b/examples/margin/MarginSmallLiabilityExchange/MarginSmallLiabilityExchange.go new file mode 100644 index 0000000..4569337 --- /dev/null +++ b/examples/margin/MarginSmallLiabilityExchange/MarginSmallLiabilityExchange.go @@ -0,0 +1,29 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + MarginSmallLiabilityExchange() +} + +func MarginSmallLiabilityExchange() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // MarginSmallLiabilityExchangeService - /sapi/v1/margin/exchange-small-liability + marginSmallLiabilityExchange, err := client.NewMarginSmallLiabilityExchangeService(). + AssetNames("BTC,ETH,BNB").Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(marginSmallLiabilityExchange)) +} diff --git a/examples/margin/MarginSmallLiabilityExchangeCoinList/MarginSmallLiabilityExchangeCoinList.go b/examples/margin/MarginSmallLiabilityExchangeCoinList/MarginSmallLiabilityExchangeCoinList.go new file mode 100644 index 0000000..3b44d03 --- /dev/null +++ b/examples/margin/MarginSmallLiabilityExchangeCoinList/MarginSmallLiabilityExchangeCoinList.go @@ -0,0 +1,29 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + MarginSmallLiabilityExchangeCoinList() +} + +func MarginSmallLiabilityExchangeCoinList() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // MarginSmallLiabilityExchangeCoinListService - /sapi/v1/margin/exchange-small-liability + marginSmallLiabilityExchangeCoinList, err := client.NewMarginSmallLiabilityExchangeCoinListService(). + Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(marginSmallLiabilityExchangeCoinList)) +} diff --git a/examples/margin/MarginSmallLiabilityExchangeHistory/MarginSmallLiabilityExchangeHistory.go b/examples/margin/MarginSmallLiabilityExchangeHistory/MarginSmallLiabilityExchangeHistory.go new file mode 100644 index 0000000..6b51c5f --- /dev/null +++ b/examples/margin/MarginSmallLiabilityExchangeHistory/MarginSmallLiabilityExchangeHistory.go @@ -0,0 +1,29 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + MarginSmallLiabilityExchangeHistory() +} + +func MarginSmallLiabilityExchangeHistory() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // MarginSmallLiabilityExchangeHistoryService - /sapi/v1/margin/exchange-small-liability-history + marginSmallLiabilityExchangeHistory, err := client.NewMarginSmallLiabilityExchangeHistoryService(). + Current(1).Size(10).Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(marginSmallLiabilityExchangeHistory)) +} diff --git a/examples/margin/MarginToggleBnbBurn/MarginToggleBnbBurn.go b/examples/margin/MarginToggleBnbBurn/MarginToggleBnbBurn.go new file mode 100644 index 0000000..a441fd3 --- /dev/null +++ b/examples/margin/MarginToggleBnbBurn/MarginToggleBnbBurn.go @@ -0,0 +1,28 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + MarginToggleBnbBurn() +} + +func MarginToggleBnbBurn() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // MarginToggleBnbBurnService - /sapi/v1/bnbBurn + marginToggleBnbBurn, err := client.NewMarginToggleBnbBurnService().Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(marginToggleBnbBurn)) +} diff --git a/examples/margin/QueryCrossMarginPair/QueryCrossMarginPair.go b/examples/margin/QueryCrossMarginPair/QueryCrossMarginPair.go new file mode 100644 index 0000000..ab6d21a --- /dev/null +++ b/examples/margin/QueryCrossMarginPair/QueryCrossMarginPair.go @@ -0,0 +1,29 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + QueryCrossMarginPair() +} + +func QueryCrossMarginPair() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // QueryCrossMarginPairService - /sapi/v1/margin/pair + queryCrossMarginPair, err := client.NewQueryCrossMarginPairService().Symbol("BTCUSDT"). + Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(queryCrossMarginPair)) +} diff --git a/examples/margin/QueryMarginAsset/QueryMarginAsset.go b/examples/margin/QueryMarginAsset/QueryMarginAsset.go new file mode 100644 index 0000000..0efdf91 --- /dev/null +++ b/examples/margin/QueryMarginAsset/QueryMarginAsset.go @@ -0,0 +1,29 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + QueryMarginAsset() +} + +func QueryMarginAsset() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // QueryMarginAssetService - /sapi/v1/margin/asset + queryMarginAsset, err := client.NewQueryMarginAssetService().Asset("USDT"). + Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(queryMarginAsset)) +} diff --git a/examples/margin/QueryMarginPriceIndex/QueryMarginPriceIndex.go b/examples/margin/QueryMarginPriceIndex/QueryMarginPriceIndex.go new file mode 100644 index 0000000..b901be6 --- /dev/null +++ b/examples/margin/QueryMarginPriceIndex/QueryMarginPriceIndex.go @@ -0,0 +1,29 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + QueryMarginPriceIndex() +} + +func QueryMarginPriceIndex() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // QueryMarginPriceIndexService - /sapi/v1/margin/priceIndex + queryMarginPriceIndex, err := client.NewQueryMarginPriceIndexService().Symbol("BTCUSDT"). + Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(queryMarginPriceIndex)) +} diff --git a/examples/margin/Repay/Repay.go b/examples/margin/Repay/Repay.go new file mode 100644 index 0000000..3576aa4 --- /dev/null +++ b/examples/margin/Repay/Repay.go @@ -0,0 +1,29 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + Repay() +} + +func Repay() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // RepayService - /sapi/v1/margin/repay + repay, err := client.NewRepayService().Asset("BTC").Amount(0.002). + Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(repay)) +} diff --git a/examples/margin/RepayRecord/RepayRecord.go b/examples/margin/RepayRecord/RepayRecord.go new file mode 100644 index 0000000..6825f75 --- /dev/null +++ b/examples/margin/RepayRecord/RepayRecord.go @@ -0,0 +1,28 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + RepayRecord() +} + +func RepayRecord() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // RepayRecordService - /sapi/v1/margin/repay + repayRecord, err := client.NewRepayRecordService().Asset("BTC").Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(repayRecord)) +} diff --git a/examples/margin/Transfer/Transfer.go b/examples/margin/Transfer/Transfer.go new file mode 100644 index 0000000..03d3d53 --- /dev/null +++ b/examples/margin/Transfer/Transfer.go @@ -0,0 +1,29 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + Transfer() +} + +func Transfer() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // TransferService - /sapi/v1/margin/transfer + transfer, err := client.NewTransferService().Asset("BTC").Amount(0.002). + TransferType(1).Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(transfer)) +} diff --git a/examples/market/AggTradesList/AggTradesList.go b/examples/market/AggTradesList/AggTradesList.go new file mode 100644 index 0000000..3988b6e --- /dev/null +++ b/examples/market/AggTradesList/AggTradesList.go @@ -0,0 +1,27 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + AggTradesList() +} + +func AggTradesList() { + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient("", "", baseURL) + + // AggTradesList + aggTradesList, err := client.NewAggTradesListService(). + Symbol("BTCUSDT").Limit(20).Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(aggTradesList)) +} diff --git a/examples/market/AvgPrice/AvgPrice.go b/examples/market/AvgPrice/AvgPrice.go new file mode 100644 index 0000000..e6aedd6 --- /dev/null +++ b/examples/market/AvgPrice/AvgPrice.go @@ -0,0 +1,27 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + AvgPrice() +} + +func AvgPrice() { + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient("", "", baseURL) + + // AvgPrice + avgPrice, err := client.NewAvgPriceService(). + Symbol("BTCUSDT").Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(avgPrice)) +} diff --git a/examples/market/ExchangeInfo/ExchangeInfo.go b/examples/market/ExchangeInfo/ExchangeInfo.go new file mode 100644 index 0000000..7173747 --- /dev/null +++ b/examples/market/ExchangeInfo/ExchangeInfo.go @@ -0,0 +1,26 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + ExchangeInfo() +} + +func ExchangeInfo() { + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient("", "", baseURL) + + // ExchangeInfo + exchangeInfo, err := client.NewExchangeInfoService().Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(exchangeInfo)) +} diff --git a/examples/market/HistoricalTradeLookup/HistoricalTradeLookup.go b/examples/market/HistoricalTradeLookup/HistoricalTradeLookup.go new file mode 100644 index 0000000..776193d --- /dev/null +++ b/examples/market/HistoricalTradeLookup/HistoricalTradeLookup.go @@ -0,0 +1,27 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + HistoricalTradeLookup() +} + +func HistoricalTradeLookup() { + apiKey := "your api key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, "", baseURL) + + historicalTradeLookup, err := client.NewHistoricalTradeLookupService(). + Symbol("BTCUSDT").Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(historicalTradeLookup)) +} diff --git a/examples/market/Klines/Klines.go b/examples/market/Klines/Klines.go new file mode 100644 index 0000000..d1a894f --- /dev/null +++ b/examples/market/Klines/Klines.go @@ -0,0 +1,27 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + Klines() +} + +func Klines() { + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient("", "", baseURL) + + // Klines + klines, err := client.NewKlinesService(). + Symbol("BTCUSDT").Interval("1m").Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(klines)) +} diff --git a/examples/market/OrderBook/OrderBook.go b/examples/market/OrderBook/OrderBook.go new file mode 100644 index 0000000..51cc39e --- /dev/null +++ b/examples/market/OrderBook/OrderBook.go @@ -0,0 +1,27 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + OrderBook() +} + +func OrderBook() { + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient("", "", baseURL) + + // OrderBook + orderBook, err := client.NewOrderBookService(). + Symbol("BTCUSDT").Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(orderBook)) +} diff --git a/examples/market/Ping/Ping.go b/examples/market/Ping/Ping.go new file mode 100644 index 0000000..15ab668 --- /dev/null +++ b/examples/market/Ping/Ping.go @@ -0,0 +1,26 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + Ping() +} + +func Ping() { + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient("", "", baseURL) + + // NewPingService + ping := client.NewPingService().Do(context.Background()) + if ping == nil { + fmt.Println("Success") + return + } + fmt.Println(binance_connector.PrettyPrint(ping)) +} diff --git a/examples/market/RecentTradesList/RecentTradesList.go b/examples/market/RecentTradesList/RecentTradesList.go new file mode 100644 index 0000000..52db932 --- /dev/null +++ b/examples/market/RecentTradesList/RecentTradesList.go @@ -0,0 +1,27 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + RecentTradesList() +} + +func RecentTradesList() { + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient("", "", baseURL) + + // RecentTradesList + recentTradesList, err := client.NewRecentTradesListService(). + Symbol("BTCUSDT").Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(recentTradesList)) +} diff --git a/examples/market/ServerTime/ServerTime.go b/examples/market/ServerTime/ServerTime.go new file mode 100644 index 0000000..eca0b14 --- /dev/null +++ b/examples/market/ServerTime/ServerTime.go @@ -0,0 +1,28 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + ServerTime() +} + +func ServerTime() { + + client := binance_connector.NewClient("", "") + + // set to debug mode + client.Debug = true + + // NewServerTimeService + serverTime, err := client.NewServerTimeService().Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(serverTime)) +} diff --git a/examples/market/Ticker/Ticker.go b/examples/market/Ticker/Ticker.go new file mode 100644 index 0000000..46e3923 --- /dev/null +++ b/examples/market/Ticker/Ticker.go @@ -0,0 +1,27 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + Ticker() +} + +func Ticker() { + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient("", "", baseURL) + + // Ticker + ticker, err := client.NewTickerService(). + Symbol("BTCUSDT").Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(ticker)) +} diff --git a/examples/market/Ticker24hr/Ticker24hr.go b/examples/market/Ticker24hr/Ticker24hr.go new file mode 100644 index 0000000..c837ffd --- /dev/null +++ b/examples/market/Ticker24hr/Ticker24hr.go @@ -0,0 +1,27 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + Ticker24hr() +} + +func Ticker24hr() { + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient("", "", baseURL) + + // Ticker24hr + ticker24hr, err := client.NewTicker24hrService(). + Symbol("BTCUSDT").Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(ticker24hr)) +} diff --git a/examples/market/TickerBookTicker/TickerBookTicker.go b/examples/market/TickerBookTicker/TickerBookTicker.go new file mode 100644 index 0000000..683d8e6 --- /dev/null +++ b/examples/market/TickerBookTicker/TickerBookTicker.go @@ -0,0 +1,27 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + TickerBookTicker() +} + +func TickerBookTicker() { + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient("", "", baseURL) + + // TickerBookTicker + tickerBookTicker, err := client.NewTickerBookTickerService(). + Symbol("BTCUSDT").Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(tickerBookTicker)) +} diff --git a/examples/market/TickerPrice/TickerPrice.go b/examples/market/TickerPrice/TickerPrice.go new file mode 100644 index 0000000..b25a944 --- /dev/null +++ b/examples/market/TickerPrice/TickerPrice.go @@ -0,0 +1,27 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + TickerPrice() +} + +func TickerPrice() { + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient("", "", baseURL) + + // TickerPrice + tickerPrice, err := client.NewTickerPriceService(). + Symbol("BTCUSDT").Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(tickerPrice)) +} diff --git a/examples/market/UiKlines/UiKlines.go b/examples/market/UiKlines/UiKlines.go new file mode 100644 index 0000000..597c449 --- /dev/null +++ b/examples/market/UiKlines/UiKlines.go @@ -0,0 +1,27 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + UiKlines() +} + +func UiKlines() { + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient("", "", baseURL) + + // UiKlines + uiKlines, err := client.NewUIKlinesService(). + Symbol("BTCUSDT").Interval("1m").Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(uiKlines)) +} diff --git a/examples/subaccount/CreateSubAccount/CreateSubAccount.go b/examples/subaccount/CreateSubAccount/CreateSubAccount.go new file mode 100644 index 0000000..c924044 --- /dev/null +++ b/examples/subaccount/CreateSubAccount/CreateSubAccount.go @@ -0,0 +1,29 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + CreateSubAccount() +} + +func CreateSubAccount() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // #1 + subaccount, err := client.NewCreateSubAccountService().SubAccountString("TestSubaccount1"). + Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(subaccount)) +} diff --git a/examples/subaccount/DeleteIPListForSubAccountAPIKey/DeleteIPListForSubAccountAPIKey.go b/examples/subaccount/DeleteIPListForSubAccountAPIKey/DeleteIPListForSubAccountAPIKey.go new file mode 100644 index 0000000..b04a0c5 --- /dev/null +++ b/examples/subaccount/DeleteIPListForSubAccountAPIKey/DeleteIPListForSubAccountAPIKey.go @@ -0,0 +1,29 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + DeleteIPListForSubAccountAPIKey() +} + +func DeleteIPListForSubAccountAPIKey() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // Delete IP List For a Sub-account API Key (For Master Account) - /sapi/v1/sub-account/subaccountApi/ipRestriction/ipList + deleteIPListForSubAccountAPIKey, err := client.NewDeleteIPListForSubAccountAPIKeyService().Email("email@email.com"). + SubAccountApiKey("123123").IpAddress("127.0.0.1").Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(deleteIPListForSubAccountAPIKey)) +} diff --git a/examples/subaccount/DepositAssetsIntoManagedSubAccount/DepositAssetsIntoManagedSubAccount.go b/examples/subaccount/DepositAssetsIntoManagedSubAccount/DepositAssetsIntoManagedSubAccount.go new file mode 100644 index 0000000..f4c6ca4 --- /dev/null +++ b/examples/subaccount/DepositAssetsIntoManagedSubAccount/DepositAssetsIntoManagedSubAccount.go @@ -0,0 +1,29 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + DepositAssetsIntoManagedSubAccount() +} + +func DepositAssetsIntoManagedSubAccount() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // Deposit Assets Into The Managed Sub-account(For Investor Master Account) - /sapi/v1/sub-account/managed-subaccount/deposit + depositAssetsIntoManagedSubAccount, err := client.NewDepositAssetsIntoManagedSubAccountService().ToEmail("to@email.com"). + Asset("BTC").Amount(0.01).Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(depositAssetsIntoManagedSubAccount)) +} diff --git a/examples/subaccount/EnableFuturesForSubAccount/EnableFuturesForSubAccount.go b/examples/subaccount/EnableFuturesForSubAccount/EnableFuturesForSubAccount.go new file mode 100644 index 0000000..9aa629c --- /dev/null +++ b/examples/subaccount/EnableFuturesForSubAccount/EnableFuturesForSubAccount.go @@ -0,0 +1,29 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + EnableFuturesForSubAccount() +} + +func EnableFuturesForSubAccount() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // Enable Futures for Sub-account (For Master Account) - /sapi/v1/sub-account/futures/enable + enableFuturesForSubAccount, err := client.NewEnableFuturesForSubAccountService().Email("from@email.com"). + Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(enableFuturesForSubAccount)) +} diff --git a/examples/subaccount/EnableLeverageTokenForSubAccount/EnableLeverageTokenForSubAccount.go b/examples/subaccount/EnableLeverageTokenForSubAccount/EnableLeverageTokenForSubAccount.go new file mode 100644 index 0000000..2e2f5fa --- /dev/null +++ b/examples/subaccount/EnableLeverageTokenForSubAccount/EnableLeverageTokenForSubAccount.go @@ -0,0 +1,29 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + EnableLeverageTokenForSubAccount() +} + +func EnableLeverageTokenForSubAccount() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // Enable Leverage Token for Sub-account (For Master Account) - /sapi/v1/sub-account/blvt/enable + enableLeverageTokenForSubAccount, err := client.NewEnableLeverageTokenForSubAccountService().Email("email@email.com"). + EnableBlvt(true).Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(enableLeverageTokenForSubAccount)) +} diff --git a/examples/subaccount/EnableMarginForSubAccount/EnableMarginForSubAccount.go b/examples/subaccount/EnableMarginForSubAccount/EnableMarginForSubAccount.go new file mode 100644 index 0000000..75de9f8 --- /dev/null +++ b/examples/subaccount/EnableMarginForSubAccount/EnableMarginForSubAccount.go @@ -0,0 +1,29 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + EnableMarginForSubAccount() +} + +func EnableMarginForSubAccount() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // Enable Margin for Sub-account (For Master Account) - /sapi/v1/sub-account/margin/enable + enableMarginForSubAccount, err := client.NewEnableMarginForSubAccountService().Email("from@email.com"). + Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(enableMarginForSubAccount)) +} diff --git a/examples/subaccount/FuturesTransferForSubAccount/FuturesTransferForSubAccount.go b/examples/subaccount/FuturesTransferForSubAccount/FuturesTransferForSubAccount.go new file mode 100644 index 0000000..cd1835b --- /dev/null +++ b/examples/subaccount/FuturesTransferForSubAccount/FuturesTransferForSubAccount.go @@ -0,0 +1,29 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + FuturesTransferForSubAccount() +} + +func FuturesTransferForSubAccount() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // Futures Transfer for Sub-account (For Master Account) - /sapi/v1/sub-account/futures/transfer + futuresTransferForSubAccount, err := client.NewFuturesTransferForSubAccountService().Email("from@email.com").Asset("BTC"). + Amount(0.01).TransferType(1).Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(futuresTransferForSubAccount)) +} diff --git a/examples/subaccount/GetDetailOnSubAccountFuturesAccount/GetDetailOnSubAccountFuturesAccount.go b/examples/subaccount/GetDetailOnSubAccountFuturesAccount/GetDetailOnSubAccountFuturesAccount.go new file mode 100644 index 0000000..5cf474a --- /dev/null +++ b/examples/subaccount/GetDetailOnSubAccountFuturesAccount/GetDetailOnSubAccountFuturesAccount.go @@ -0,0 +1,29 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + GetDetailOnSubAccountFuturesAccount() +} + +func GetDetailOnSubAccountFuturesAccount() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // Get Detail on Sub-account's Futures Account (For Master Account) - /sapi/v1/sub-account/futures/account + getDetailOnSubAccountFuturesAccount, err := client.NewGetDetailOnSubAccountFuturesAccountService().Email("from@email.com"). + Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(getDetailOnSubAccountFuturesAccount)) +} diff --git a/examples/subaccount/GetDetailOnSubAccountFuturesAccountV2/GetDetailOnSubAccountFuturesAccountV2.go b/examples/subaccount/GetDetailOnSubAccountFuturesAccountV2/GetDetailOnSubAccountFuturesAccountV2.go new file mode 100644 index 0000000..903660f --- /dev/null +++ b/examples/subaccount/GetDetailOnSubAccountFuturesAccountV2/GetDetailOnSubAccountFuturesAccountV2.go @@ -0,0 +1,29 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + GetDetailOnSubAccountFuturesAccountV2() +} + +func GetDetailOnSubAccountFuturesAccountV2() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // Get Detail on Sub-account's Futures Account V2 (For Master Account) - /sapi/v1/sub-account/futures/internalTransfer + getDetailOnSubAccountFuturesAccountV2, err := client.NewGetDetailOnSubAccountFuturesAccountV2Service().Email("email@email.com"). + FuturesType(1).Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(getDetailOnSubAccountFuturesAccountV2)) +} diff --git a/examples/subaccount/GetDetailOnSubAccountMarginAccount/GetDetailOnSubAccountMarginAccount.go b/examples/subaccount/GetDetailOnSubAccountMarginAccount/GetDetailOnSubAccountMarginAccount.go new file mode 100644 index 0000000..8779f2a --- /dev/null +++ b/examples/subaccount/GetDetailOnSubAccountMarginAccount/GetDetailOnSubAccountMarginAccount.go @@ -0,0 +1,29 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + GetDetailOnSubAccountMarginAccount() +} + +func GetDetailOnSubAccountMarginAccount() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // Get Detail on Sub-account's Margin Account (For Master Account) - /sapi/v1/sub-account/margin/account + getDetailOnSubAccountMarginAccount, err := client.NewGetDetailOnSubAccountMarginAccountService().Email("from@email.com"). + Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(getDetailOnSubAccountMarginAccount)) +} diff --git a/examples/subaccount/GetFuturesPositionRiskOfSubAccount/GetFuturesPositionRiskOfSubAccount.go b/examples/subaccount/GetFuturesPositionRiskOfSubAccount/GetFuturesPositionRiskOfSubAccount.go new file mode 100644 index 0000000..8835bc5 --- /dev/null +++ b/examples/subaccount/GetFuturesPositionRiskOfSubAccount/GetFuturesPositionRiskOfSubAccount.go @@ -0,0 +1,29 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + GetFuturesPositionRiskOfSubAccount() +} + +func GetFuturesPositionRiskOfSubAccount() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // Get Futures Position-Risk of Sub-account (For Master Account) - /sapi/v1/sub-account/futures/positionRisk + getFuturesPositionRiskOfSubAccount, err := client.NewGetFuturesPositionRiskOfSubAccountService().Email("from@email.com"). + Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(getFuturesPositionRiskOfSubAccount)) +} diff --git a/examples/subaccount/GetFuturesPositionRiskOfSubAccountV2/GetFuturesPositionRiskOfSubAccountV2.go b/examples/subaccount/GetFuturesPositionRiskOfSubAccountV2/GetFuturesPositionRiskOfSubAccountV2.go new file mode 100644 index 0000000..514f168 --- /dev/null +++ b/examples/subaccount/GetFuturesPositionRiskOfSubAccountV2/GetFuturesPositionRiskOfSubAccountV2.go @@ -0,0 +1,29 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + GetFuturesPositionRiskOfSubAccountV2() +} + +func GetFuturesPositionRiskOfSubAccountV2() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // Get Futures Position-Risk of Sub-account V2 (For Master Account) - /sapi/v1/sub-account/futures/positionRisk + getFuturesPositionRiskOfSubAccountV2, err := client.NewGetFuturesPositionRiskOfSubAccountV2Service().Email("email@email.com"). + FuturesType(1).Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(getFuturesPositionRiskOfSubAccountV2)) +} diff --git a/examples/subaccount/GetIPRestrictionForSubAccountAPIKey/GetIPRestrictionForSubAccountAPIKey.go b/examples/subaccount/GetIPRestrictionForSubAccountAPIKey/GetIPRestrictionForSubAccountAPIKey.go new file mode 100644 index 0000000..4c05dd4 --- /dev/null +++ b/examples/subaccount/GetIPRestrictionForSubAccountAPIKey/GetIPRestrictionForSubAccountAPIKey.go @@ -0,0 +1,29 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + GetIPRestrictionForSubAccountAPIKey() +} + +func GetIPRestrictionForSubAccountAPIKey() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // Get IP Restriction for a Sub-account API Key (For Master Account) - /sapi/v1/sub-account/subaccountApi/ipRestriction + getIPRestrictionForSubAccountAPIKey, err := client.NewGetIPRestrictionForSubAccountAPIKeyService().Email("email@email.com"). + Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(getIPRestrictionForSubAccountAPIKey)) +} diff --git a/examples/subaccount/GetSubAccountDepositAddress/GetSubAccountDepositAddress.go b/examples/subaccount/GetSubAccountDepositAddress/GetSubAccountDepositAddress.go new file mode 100644 index 0000000..843df8f --- /dev/null +++ b/examples/subaccount/GetSubAccountDepositAddress/GetSubAccountDepositAddress.go @@ -0,0 +1,29 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + GetSubAccountDepositAddress() +} + +func GetSubAccountDepositAddress() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // Get Sub-account Deposit Address (For Master Account) - /sapi/v1/capital/deposit/subAddress + getSubAccountDepositAddress, err := client.NewGetSubAccountDepositAddressService().Email("from@email.com"). + Coin("BTC").Network("BTC").Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(getSubAccountDepositAddress)) +} diff --git a/examples/subaccount/GetSubAccountDepositHistory/GetSubAccountDepositHistory.go b/examples/subaccount/GetSubAccountDepositHistory/GetSubAccountDepositHistory.go new file mode 100644 index 0000000..778d6d6 --- /dev/null +++ b/examples/subaccount/GetSubAccountDepositHistory/GetSubAccountDepositHistory.go @@ -0,0 +1,29 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + GetSubAccountDepositHistory() +} + +func GetSubAccountDepositHistory() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // Get Sub-account Deposit History (For Master Account) - /sapi/v1/capital/deposit/subHisrec + getSubAccountDepositHistory, err := client.NewGetSubAccountDepositHistoryService().Email("from@email.com"). + Coin("BTC").Status(1).StartTime(1234567891011).EndTime(1234567891011).Limit(10).Offset(1).Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(getSubAccountDepositHistory)) +} diff --git a/examples/subaccount/GetSubAccountStatus/GetSubAccountStatus.go b/examples/subaccount/GetSubAccountStatus/GetSubAccountStatus.go new file mode 100644 index 0000000..dd64da2 --- /dev/null +++ b/examples/subaccount/GetSubAccountStatus/GetSubAccountStatus.go @@ -0,0 +1,29 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + GetSubAccountStatus() +} + +func GetSubAccountStatus() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // Get Sub-account's Status on Margin/Futures (For Master Account) - /sapi/v1/sub-account/status + getSubAccountStatus, err := client.NewGetSubAccountStatusService().Email("from@email.com"). + Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(getSubAccountStatus)) +} diff --git a/examples/subaccount/GetSummaryOfSubAccountFuturesAccount/GetSummaryOfSubAccountFuturesAccount.go b/examples/subaccount/GetSummaryOfSubAccountFuturesAccount/GetSummaryOfSubAccountFuturesAccount.go new file mode 100644 index 0000000..d8f3b4e --- /dev/null +++ b/examples/subaccount/GetSummaryOfSubAccountFuturesAccount/GetSummaryOfSubAccountFuturesAccount.go @@ -0,0 +1,29 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + GetSummaryOfSubAccountFuturesAccount() +} + +func GetSummaryOfSubAccountFuturesAccount() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // Get Summary of Sub-account's Futures Account (For Master Account) - /sapi/v1/sub-account/futures/accountSummary + getSummaryOfSubAccountFuturesAccount, err := client.NewGetSummaryOfSubAccountFuturesAccountService(). + Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(getSummaryOfSubAccountFuturesAccount)) +} diff --git a/examples/subaccount/GetSummaryOfSubAccountFuturesAccountV2/GetSummaryOfSubAccountFuturesAccountV2.go b/examples/subaccount/GetSummaryOfSubAccountFuturesAccountV2/GetSummaryOfSubAccountFuturesAccountV2.go new file mode 100644 index 0000000..a2895bd --- /dev/null +++ b/examples/subaccount/GetSummaryOfSubAccountFuturesAccountV2/GetSummaryOfSubAccountFuturesAccountV2.go @@ -0,0 +1,29 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + GetSummaryOfSubAccountFuturesAccountV2() +} + +func GetSummaryOfSubAccountFuturesAccountV2() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // Get Summary of Sub-account's Futures Account V2 (For Master Account) - /sapi/v1/sub-account/futures/accountSummary + getSummaryOfSubAccountFuturesAccountV2, err := client.NewGetSummaryOfSubAccountFuturesAccountV2Service().FuturesType(1). + Page(1).Limit(10).Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(getSummaryOfSubAccountFuturesAccountV2)) +} diff --git a/examples/subaccount/GetSummaryOfSubAccountMarginAccount/GetSummaryOfSubAccountMarginAccount.go b/examples/subaccount/GetSummaryOfSubAccountMarginAccount/GetSummaryOfSubAccountMarginAccount.go new file mode 100644 index 0000000..584bf4f --- /dev/null +++ b/examples/subaccount/GetSummaryOfSubAccountMarginAccount/GetSummaryOfSubAccountMarginAccount.go @@ -0,0 +1,29 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + GetSummaryOfSubAccountMarginAccount() +} + +func GetSummaryOfSubAccountMarginAccount() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // Get Summary of Sub-account's Margin Account (For Master Account) - /sapi/v1/sub-account/margin/accountSummary + getSummaryOfSubAccountMarginAccount, err := client.NewGetSummaryOfSubAccountMarginAccountService(). + Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(getSummaryOfSubAccountMarginAccount)) +} diff --git a/examples/subaccount/MarginTransferForSubAccount/MarginTransferForSubAccount.go b/examples/subaccount/MarginTransferForSubAccount/MarginTransferForSubAccount.go new file mode 100644 index 0000000..0d2d9fe --- /dev/null +++ b/examples/subaccount/MarginTransferForSubAccount/MarginTransferForSubAccount.go @@ -0,0 +1,29 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + MarginTransferForSubAccount() +} + +func MarginTransferForSubAccount() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // Margin Transfer for Sub-account (For Master Account) - /sapi/v1/sub-account/margin/transfer + marginTransferForSubAccount, err := client.NewMarginTransferForSubAccountService().Email("from@email.com").Asset("BTC"). + Amount(0.01).TransferType(1).Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(marginTransferForSubAccount)) +} diff --git a/examples/subaccount/QueryManagedSubAccountAssetDetails/QueryManagedSubAccountAssetDetails.go b/examples/subaccount/QueryManagedSubAccountAssetDetails/QueryManagedSubAccountAssetDetails.go new file mode 100644 index 0000000..8c97be3 --- /dev/null +++ b/examples/subaccount/QueryManagedSubAccountAssetDetails/QueryManagedSubAccountAssetDetails.go @@ -0,0 +1,29 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + QueryManagedSubAccountAssetDetails() +} + +func QueryManagedSubAccountAssetDetails() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // Query Managed Sub-account Asset Details(For Investor Master Account)- /sapi/v1/sub-account/managed-subaccount/asset + queryManagedSubAccountAssetDetails, err := client.NewQueryManagedSubAccountAssetDetailsService().Email("email@email.com"). + Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(queryManagedSubAccountAssetDetails)) +} diff --git a/examples/subaccount/QueryManagedSubAccountFuturesAssetDetails/QueryManagedSubAccountFuturesAssetDetails.go b/examples/subaccount/QueryManagedSubAccountFuturesAssetDetails/QueryManagedSubAccountFuturesAssetDetails.go new file mode 100644 index 0000000..0613748 --- /dev/null +++ b/examples/subaccount/QueryManagedSubAccountFuturesAssetDetails/QueryManagedSubAccountFuturesAssetDetails.go @@ -0,0 +1,29 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + QueryManagedSubAccountFuturesAssetDetails() +} + +func QueryManagedSubAccountFuturesAssetDetails() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // Query Managed Sub-account Futures Asset Details(For Investor Master Account)(USER_DATA) + queryManagedSubAccountFuturesAssetDetails, err := client.NewQueryManagedSubAccountFuturesAssetDetailsService().Email("email@email.com"). + Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(queryManagedSubAccountFuturesAssetDetails)) +} diff --git a/examples/subaccount/QueryManagedSubAccountList/QueryManagedSubAccountList.go b/examples/subaccount/QueryManagedSubAccountList/QueryManagedSubAccountList.go new file mode 100644 index 0000000..e836c6e --- /dev/null +++ b/examples/subaccount/QueryManagedSubAccountList/QueryManagedSubAccountList.go @@ -0,0 +1,27 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + QueryManagedSubAccountList() +} + +func QueryManagedSubAccountList() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + managedSubAccountList, err := client.NewQueryManagedSubAccountList().Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(managedSubAccountList)) +} diff --git a/examples/subaccount/QueryManagedSubAccountMarginAssetDetails/QueryManagedSubAccountMarginAssetDetails.go b/examples/subaccount/QueryManagedSubAccountMarginAssetDetails/QueryManagedSubAccountMarginAssetDetails.go new file mode 100644 index 0000000..b0eef33 --- /dev/null +++ b/examples/subaccount/QueryManagedSubAccountMarginAssetDetails/QueryManagedSubAccountMarginAssetDetails.go @@ -0,0 +1,29 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + QueryManagedSubAccountMarginAssetDetails() +} + +func QueryManagedSubAccountMarginAssetDetails() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // Query Managed Sub-account Margin Asset Details (For Investor Master Account) (USER_DATA) + queryManagedSubAccountMarginAssetDetails, err := client.NewQueryManagedSubAccountMarginAssetDetailsService().Email("email@email.com"). + Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(queryManagedSubAccountMarginAssetDetails)) +} diff --git a/examples/subaccount/QueryManagedSubAccountSnapshot/QueryManagedSubAccountSnapshot.go b/examples/subaccount/QueryManagedSubAccountSnapshot/QueryManagedSubAccountSnapshot.go new file mode 100644 index 0000000..9f19517 --- /dev/null +++ b/examples/subaccount/QueryManagedSubAccountSnapshot/QueryManagedSubAccountSnapshot.go @@ -0,0 +1,28 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + QueryManagedSubAccountSnapshot() +} + +func QueryManagedSubAccountSnapshot() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + withdrawAssetsFromTheManagedSubAccount, err := client.NewQueryManagedSubAccountSnapshotService().Email("email@email.com"). + SubType("BTC").StartTime(123123123).EndTime(123132123).Limit(10).Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(withdrawAssetsFromTheManagedSubAccount)) +} diff --git a/examples/subaccount/QueryManagedSubAccountTransferLog/QueryManagedSubAccountTransferLog.go b/examples/subaccount/QueryManagedSubAccountTransferLog/QueryManagedSubAccountTransferLog.go new file mode 100644 index 0000000..31e1bd0 --- /dev/null +++ b/examples/subaccount/QueryManagedSubAccountTransferLog/QueryManagedSubAccountTransferLog.go @@ -0,0 +1,29 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + QueryManagedSubAccountTransferLog() +} + +func QueryManagedSubAccountTransferLog() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // Query Managed Sub Account Transfer Log (Investor) (USER_DATA) + queryManagedSubAccountTransferLog, err := client.NewQueryManagedSubAccountTransferLogService().Email("email@email.com"). + StartTime(123123).EndTime(123123).Page(1).Limit(10).Transfers("").TransferFunctionAccountType("").Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(queryManagedSubAccountTransferLog)) +} diff --git a/examples/subaccount/QueryManagedSubAccountTransferLogForTradingTeam/QueryManagedSubAccountTransferLogForTradingTeam.go b/examples/subaccount/QueryManagedSubAccountTransferLogForTradingTeam/QueryManagedSubAccountTransferLogForTradingTeam.go new file mode 100644 index 0000000..4b1817f --- /dev/null +++ b/examples/subaccount/QueryManagedSubAccountTransferLogForTradingTeam/QueryManagedSubAccountTransferLogForTradingTeam.go @@ -0,0 +1,29 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + QueryManagedSubAccountTransferLogForTradingTeam() +} + +func QueryManagedSubAccountTransferLogForTradingTeam() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // Query Managed Sub Account Transfer Log (Trading Team) (USER_DATA) + queryManagedSubAccountTransferLogForTradingTeam, err := client.NewQueryManagedSubAccountTransferLogForTradingTeamService().Email("email@email.com"). + StartTime(123123).EndTime(123123).Page(1).Limit(10).Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(queryManagedSubAccountTransferLogForTradingTeam)) +} diff --git a/examples/subaccount/QuerySubAccountAssets/QuerySubAccountAssets.go b/examples/subaccount/QuerySubAccountAssets/QuerySubAccountAssets.go new file mode 100644 index 0000000..b4f4c80 --- /dev/null +++ b/examples/subaccount/QuerySubAccountAssets/QuerySubAccountAssets.go @@ -0,0 +1,29 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + QuerySubAccountAssets() +} + +func QuerySubAccountAssets() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // Query Sub-account Assets (For Master Account) - /sapi/v3/sub-account/assets + querySubAccountAssets, err := client.NewQuerySubAccountAssetsService().Email("from@email.com"). + Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(querySubAccountAssets)) +} diff --git a/examples/subaccount/QuerySubAccountAssetsForMasterAccount/QuerySubAccountAssetsForMasterAccount.go b/examples/subaccount/QuerySubAccountAssetsForMasterAccount/QuerySubAccountAssetsForMasterAccount.go new file mode 100644 index 0000000..522c6bd --- /dev/null +++ b/examples/subaccount/QuerySubAccountAssetsForMasterAccount/QuerySubAccountAssetsForMasterAccount.go @@ -0,0 +1,29 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + QuerySubAccountAssetsForMasterAccount() +} + +func QuerySubAccountAssetsForMasterAccount() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // Query Sub-account Assets (For Master Account)(USER_DATA) + querySubAccountAssetsForMasterAccount, err := client.NewQuerySubAccountAssetsService().Email("from@email.com"). + Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(querySubAccountAssetsForMasterAccount)) +} diff --git a/examples/subaccount/QuerySubAccountSpotAssetsSummary/QuerySubAccountSpotAssetsSummary.go b/examples/subaccount/QuerySubAccountSpotAssetsSummary/QuerySubAccountSpotAssetsSummary.go new file mode 100644 index 0000000..56a79cf --- /dev/null +++ b/examples/subaccount/QuerySubAccountSpotAssetsSummary/QuerySubAccountSpotAssetsSummary.go @@ -0,0 +1,29 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + QuerySubAccountSpotAssetsSummary() +} + +func QuerySubAccountSpotAssetsSummary() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // Query Sub-account Spot Assets Summary (For Master Account) - /sapi/v1/sub-account/spotSummary + querySubAccountSpotAssetsSummary, err := client.NewQuerySubAccountSpotAssetsSummaryService().Email("from@email.com"). + Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(querySubAccountSpotAssetsSummary)) +} diff --git a/examples/subaccount/QuerySubAccountTransactionTatistics/QuerySubAccountTransactionTatistics.go b/examples/subaccount/QuerySubAccountTransactionTatistics/QuerySubAccountTransactionTatistics.go new file mode 100644 index 0000000..546bdd7 --- /dev/null +++ b/examples/subaccount/QuerySubAccountTransactionTatistics/QuerySubAccountTransactionTatistics.go @@ -0,0 +1,27 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + QuerySubAccountTransactionTatistics() +} + +func QuerySubAccountTransactionTatistics() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + transactionTatistics, err := client.NewQuerySubAccountTransactionTatistics().Email("email@email.com").Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(transactionTatistics)) +} diff --git a/examples/subaccount/QueryUniversalTransferHistory/QueryUniversalTransferHistory.go b/examples/subaccount/QueryUniversalTransferHistory/QueryUniversalTransferHistory.go new file mode 100644 index 0000000..a3607b9 --- /dev/null +++ b/examples/subaccount/QueryUniversalTransferHistory/QueryUniversalTransferHistory.go @@ -0,0 +1,30 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + QueryUniversalTransferHistory() +} + +func QueryUniversalTransferHistory() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // Query Universal Transfer History (For Master Account) - /sapi/v1/asset/universalTransfer + queryUniversalTransferHistory, err := client.NewQueryUniversalTransferHistoryService().FromEmail("from@email.com"). + ToEmail("to@email.com").ClientTranId("123123").StartTime(1234567891011).EndTime(1234567891011). + Page(1).Limit(10).Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(queryUniversalTransferHistory)) +} diff --git a/examples/subaccount/SubAccountFuturesAssetTransfer/SubAccountFuturesAssetTransfer.go b/examples/subaccount/SubAccountFuturesAssetTransfer/SubAccountFuturesAssetTransfer.go new file mode 100644 index 0000000..94b5628 --- /dev/null +++ b/examples/subaccount/SubAccountFuturesAssetTransfer/SubAccountFuturesAssetTransfer.go @@ -0,0 +1,29 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + SubAccountFuturesAssetTransfer() +} + +func SubAccountFuturesAssetTransfer() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // Sub-account Futures Asset Transfer (For Master Account) - /sapi/v1/sub-account/futures/internalTransfer + subaccountFuturesAssetTransfer, err := client.NewSubAccountFuturesAssetTransferService().FromEmail("from@email.com"). + ToEmail("to@email.com").FuturesType(1).Asset("BTC").Amount(0.01).Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(subaccountFuturesAssetTransfer)) +} diff --git a/examples/subaccount/SubAccountFuturesAssetTransferHistory/SubAccountFuturesAssetTransferHistory.go b/examples/subaccount/SubAccountFuturesAssetTransferHistory/SubAccountFuturesAssetTransferHistory.go new file mode 100644 index 0000000..5606f5f --- /dev/null +++ b/examples/subaccount/SubAccountFuturesAssetTransferHistory/SubAccountFuturesAssetTransferHistory.go @@ -0,0 +1,29 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + SubAccountFuturesAssetTransferHistory() +} + +func SubAccountFuturesAssetTransferHistory() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // Query Sub-account Futures Asset Transfer History (For Master Account) - /sapi/v1/sub-account/futures/internalTransfer + subaccountFuturesAssetTransferHistory, err := client.NewQuerySubAccountFuturesAssetTransferHistoryService().Email("from@email.com"). + FuturesType(1).StartTime(1234567891011).EndTime(1).Page(1).Limit(10).Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(subaccountFuturesAssetTransferHistory)) +} diff --git a/examples/subaccount/SubAccountList/SubAccountList.go b/examples/subaccount/SubAccountList/SubAccountList.go new file mode 100644 index 0000000..7f98630 --- /dev/null +++ b/examples/subaccount/SubAccountList/SubAccountList.go @@ -0,0 +1,29 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + SubAccountList() +} + +func SubAccountList() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // Query Sub-account List (For Master Account) - /sapi/v1/sub-account/list + subaccountList, err := client.NewQuerySubAccountListService().Email("test@email.com"). + IsFreeze("").Page(1).Limit(10).Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(subaccountList)) +} diff --git a/examples/subaccount/SubAccountSpotAssetTransferHistory/SubAccountSpotAssetTransferHistory.go b/examples/subaccount/SubAccountSpotAssetTransferHistory/SubAccountSpotAssetTransferHistory.go new file mode 100644 index 0000000..6b311d3 --- /dev/null +++ b/examples/subaccount/SubAccountSpotAssetTransferHistory/SubAccountSpotAssetTransferHistory.go @@ -0,0 +1,29 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + SubAccountSpotAssetTransferHistory() +} + +func SubAccountSpotAssetTransferHistory() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // Query Sub-account Spot Asset Transfer History (For Master Account) - /sapi/v1/sub-account/sub/transfer/history + subaccountSpotAssetTransferHistory, err := client.NewQuerySubAccountSpotAssetTransferHistoryService().FromEmail("from@email.com"). + ToEmail("to@email.com").StartTime(1234567891011).EndTime(1).Page(1).Limit(10).Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(subaccountSpotAssetTransferHistory)) +} diff --git a/examples/subaccount/SubAccountTransferHistory/SubAccountTransferHistory.go b/examples/subaccount/SubAccountTransferHistory/SubAccountTransferHistory.go new file mode 100644 index 0000000..a562b21 --- /dev/null +++ b/examples/subaccount/SubAccountTransferHistory/SubAccountTransferHistory.go @@ -0,0 +1,29 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + SubAccountTransferHistory() +} + +func SubAccountTransferHistory() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // Sub-account Transfer History (For Sub-account) - /sapi/v1/sub-account/transfer/subUserHistory + subAccountTransferHistory, err := client.NewSubAccountTransferHistoryService().Asset("BTC"). + TransferType(1).StartTime(1234567891011).EndTime(1234567891011).Limit(10).Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(subAccountTransferHistory)) +} diff --git a/examples/subaccount/TransferToMaster/TransferToMaster.go b/examples/subaccount/TransferToMaster/TransferToMaster.go new file mode 100644 index 0000000..0f76cdb --- /dev/null +++ b/examples/subaccount/TransferToMaster/TransferToMaster.go @@ -0,0 +1,29 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + TransferToMaster() +} + +func TransferToMaster() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // Transfer to Master (For Sub-account) - /sapi/v1/sub-account/transfer/subToMaster + transferToMaster, err := client.NewTransferToMasterService().Asset("BTC"). + Amount(0.01).Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(transferToMaster)) +} diff --git a/examples/subaccount/TransferToSubAccountOfSameMaster/TransferToSubAccountOfSameMaster.go b/examples/subaccount/TransferToSubAccountOfSameMaster/TransferToSubAccountOfSameMaster.go new file mode 100644 index 0000000..4b527c7 --- /dev/null +++ b/examples/subaccount/TransferToSubAccountOfSameMaster/TransferToSubAccountOfSameMaster.go @@ -0,0 +1,29 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + TransferToSubAccountOfSameMaster() +} + +func TransferToSubAccountOfSameMaster() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // Transfer to Sub-account of Same Master (For Sub-account) - /sapi/v1/sub-account/transfer/subToSub + transferToSubAccountOfSameMaster, err := client.NewTransferToSubAccountOfSameMasterService().ToEmail("from@email.com").Asset("BTC"). + Amount(0.01).Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(transferToSubAccountOfSameMaster)) +} diff --git a/examples/subaccount/UniversalTransfer/UniversalTransfer.go b/examples/subaccount/UniversalTransfer/UniversalTransfer.go new file mode 100644 index 0000000..e4655f0 --- /dev/null +++ b/examples/subaccount/UniversalTransfer/UniversalTransfer.go @@ -0,0 +1,29 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + UniversalTransfer() +} + +func UniversalTransfer() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // Universal Transfer (For Master Account) - /sapi/v1/asset/universalTransfer + universalTransfer, err := client.NewUniversalTransferService().FromEmail("from@email.com").ToEmail("to@email.com"). + FromAccountType("SPOT").ToAccountType("SPOT").ClientTranId("123123").Symbol("BTC").Asset("BTC").Amount(0.01).Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(universalTransfer)) +} diff --git a/examples/subaccount/UpdateIPRestrictionForSubAccountAPIKey/UpdateIPRestrictionForSubAccountAPIKey.go b/examples/subaccount/UpdateIPRestrictionForSubAccountAPIKey/UpdateIPRestrictionForSubAccountAPIKey.go new file mode 100644 index 0000000..89aac53 --- /dev/null +++ b/examples/subaccount/UpdateIPRestrictionForSubAccountAPIKey/UpdateIPRestrictionForSubAccountAPIKey.go @@ -0,0 +1,29 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + UpdateIPRestrictionForSubAccountAPIKey() +} + +func UpdateIPRestrictionForSubAccountAPIKey() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // Update IP Restriction for Sub-Account API key (For Master Account) - /sapi/v2/sub-account/subaccountApi/ipRestriction + updateIPRestrictionForSubAccountAPIKey, err := client.NewUpdateIPRestrictionForSubAccountAPIKeyService().Email("email@email.com"). + SubAccountApiKey("123123").Status("").IpAddress("127.0.0.1").Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(updateIPRestrictionForSubAccountAPIKey)) +} diff --git a/examples/subaccount/WithdrawAssetsFromTheManagedSubAccount/WithdrawAssetsFromTheManagedSubAccount.go b/examples/subaccount/WithdrawAssetsFromTheManagedSubAccount/WithdrawAssetsFromTheManagedSubAccount.go new file mode 100644 index 0000000..96d3325 --- /dev/null +++ b/examples/subaccount/WithdrawAssetsFromTheManagedSubAccount/WithdrawAssetsFromTheManagedSubAccount.go @@ -0,0 +1,28 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + WithdrawAssetsFromTheManagedSubAccount() +} + +func WithdrawAssetsFromTheManagedSubAccount() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + withdrawAssetsFromTheManagedSubAccount, err := client.NewWithdrawAssetsFromTheManagedSubAccountService().FromEmail("email@email.com"). + Asset("BTC").Amount(1.5).TransferDate(123132123).Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(withdrawAssetsFromTheManagedSubAccount)) +} diff --git a/examples/user_stream/CloseUserStream/CloseUserStream.go b/examples/user_stream/CloseUserStream/CloseUserStream.go new file mode 100644 index 0000000..807185f --- /dev/null +++ b/examples/user_stream/CloseUserStream/CloseUserStream.go @@ -0,0 +1,24 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + CloseUserStream() +} + +func CloseUserStream() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + close := client.NewCloseUserStream().ListenKey("your_listen_key"). + Do(context.Background()) + fmt.Println(close) +} diff --git a/examples/user_stream/CreateNewListenKey/CreateListenKey.go b/examples/user_stream/CreateNewListenKey/CreateListenKey.go new file mode 100644 index 0000000..d67b95e --- /dev/null +++ b/examples/user_stream/CreateNewListenKey/CreateListenKey.go @@ -0,0 +1,28 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + CreateNewListenKey() +} + +func CreateNewListenKey() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + listenKey, err := client.NewCreateListenKeyService(). + Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(listenKey) +} diff --git a/examples/user_stream/PingUserStream/PingUserStream.go b/examples/user_stream/PingUserStream/PingUserStream.go new file mode 100644 index 0000000..64d5241 --- /dev/null +++ b/examples/user_stream/PingUserStream/PingUserStream.go @@ -0,0 +1,23 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + PingUserStream() +} + +func PingUserStream() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + ping := client.NewPingUserStream().ListenKey("your_listen_key").Do(context.Background()) + fmt.Println(ping) +} diff --git a/examples/wallet/APIKeyPermission/APIKeyPermission.go b/examples/wallet/APIKeyPermission/APIKeyPermission.go new file mode 100644 index 0000000..4347078 --- /dev/null +++ b/examples/wallet/APIKeyPermission/APIKeyPermission.go @@ -0,0 +1,28 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + APIKeyPermission() +} + +func APIKeyPermission() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // APIKeyPermissionService - /sapi/v1/account/apiRestrictions + apiKeyPermission, err := client.NewAPIKeyPermissionService().Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(apiKeyPermission)) +} diff --git a/examples/wallet/AccountAPITradingStatus/AccountAPITradingStatus.go b/examples/wallet/AccountAPITradingStatus/AccountAPITradingStatus.go new file mode 100644 index 0000000..85aa60e --- /dev/null +++ b/examples/wallet/AccountAPITradingStatus/AccountAPITradingStatus.go @@ -0,0 +1,29 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + AccountApiTradingStatus() +} + +func AccountApiTradingStatus() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // AccountApiTradingStatusService - /sapi/v1/account/apiTradingStatus + accountApiTradingStatus, err := client.NewAccountApiTradingStatusService(). + Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(accountApiTradingStatus)) +} diff --git a/examples/wallet/AccountStatus/AccountStatus.go b/examples/wallet/AccountStatus/AccountStatus.go new file mode 100644 index 0000000..00fd531 --- /dev/null +++ b/examples/wallet/AccountStatus/AccountStatus.go @@ -0,0 +1,28 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + AccountStatus() +} + +func AccountStatus() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // AccountStatusService - /sapi/v1/account/status + accountStatus, err := client.NewAccountStatusService().Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(accountStatus)) +} diff --git a/examples/wallet/AssetDetail/AssetDetail.go b/examples/wallet/AssetDetail/AssetDetail.go new file mode 100644 index 0000000..0ee988d --- /dev/null +++ b/examples/wallet/AssetDetail/AssetDetail.go @@ -0,0 +1,28 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + AssetDetail() +} + +func AssetDetail() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // AssetDetailService - /sapi/v1/asset/dust-btc + assetDetail, err := client.NewAssetDetailService().Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(assetDetail)) +} diff --git a/examples/wallet/AssetDetailV2/AssetDetailV2.go b/examples/wallet/AssetDetailV2/AssetDetailV2.go new file mode 100644 index 0000000..772a98c --- /dev/null +++ b/examples/wallet/AssetDetailV2/AssetDetailV2.go @@ -0,0 +1,29 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + AssetDetailV2() +} + +func AssetDetailV2() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // AssetDetailV2Service - /sapi/v1/asset/assetDetail + assetDetailV2, err := client.NewAssetDetailV2Service().Asset("BTC"). + Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(assetDetailV2)) +} diff --git a/examples/wallet/AssetDividendRecord/AssetDividendRecord.go b/examples/wallet/AssetDividendRecord/AssetDividendRecord.go new file mode 100644 index 0000000..fd2e629 --- /dev/null +++ b/examples/wallet/AssetDividendRecord/AssetDividendRecord.go @@ -0,0 +1,29 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + AssetDividendRecord() +} + +func AssetDividendRecord() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // AssetDividendRecordService - /sapi/v1/asset/assetDividend + assetDividendRecord, err := client.NewAssetDividendRecordService().Asset("BTC"). + Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(assetDividendRecord)) +} diff --git a/examples/wallet/AutoConvertStableCoin/AutoConvertStableCoin.go b/examples/wallet/AutoConvertStableCoin/AutoConvertStableCoin.go new file mode 100644 index 0000000..9abcc34 --- /dev/null +++ b/examples/wallet/AutoConvertStableCoin/AutoConvertStableCoin.go @@ -0,0 +1,28 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + AutoConvertStableCoin() +} + +func AutoConvertStableCoin() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // AutoConvertStableCoinService - /sapi/v1/capital/contract/convertible-coins + autoConvertStableCoin, err := client.NewAutoConvertStableCoinService().Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(autoConvertStableCoin)) +} diff --git a/examples/wallet/BUSDConvert/BUSDConvert.go b/examples/wallet/BUSDConvert/BUSDConvert.go new file mode 100644 index 0000000..8c73ad1 --- /dev/null +++ b/examples/wallet/BUSDConvert/BUSDConvert.go @@ -0,0 +1,29 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + BUSDConvert() +} + +func BUSDConvert() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // BUSDConvertService - /sapi/v1/asset/convert-transfer + bUSDConvert, err := client.NewBUSDConvertService().ClientTranId("118263407119"). + Asset("BUSD").Amount(20.0).AccountType("MAIN").Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(bUSDConvert)) +} diff --git a/examples/wallet/BUSDConvertHistory/BUSDConvertHistory.go b/examples/wallet/BUSDConvertHistory/BUSDConvertHistory.go new file mode 100644 index 0000000..4a010f1 --- /dev/null +++ b/examples/wallet/BUSDConvertHistory/BUSDConvertHistory.go @@ -0,0 +1,29 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + BUSDConvertHistory() +} + +func BUSDConvertHistory() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // BUSDConvertHistoryService - /sapi/v1/asset/convert-transfer/queryByPage + bUSDConvertHistory, err := client.NewBUSDConvertHistoryService(). + StartTime(1664442061000).EndTime(1664442078000).Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(bUSDConvertHistory)) +} diff --git a/examples/wallet/CloudMiningPaymentHistory/CloudMiningPaymentHistory.go b/examples/wallet/CloudMiningPaymentHistory/CloudMiningPaymentHistory.go new file mode 100644 index 0000000..c393d97 --- /dev/null +++ b/examples/wallet/CloudMiningPaymentHistory/CloudMiningPaymentHistory.go @@ -0,0 +1,29 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + CloudMiningPaymentHistory() +} + +func CloudMiningPaymentHistory() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // CloudMiningPaymentHistoryService - /sapi/v1/asset/ledger-transfer/cloud-mining/queryByPage + cloudMiningPaymentHistory, err := client.NewCloudMiningPaymentHistoryService(). + StartTime(1664442061000).EndTime(1664442078000).Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(cloudMiningPaymentHistory)) +} diff --git a/examples/wallet/DepositAddress/DepositAddress.go b/examples/wallet/DepositAddress/DepositAddress.go new file mode 100644 index 0000000..0097aa2 --- /dev/null +++ b/examples/wallet/DepositAddress/DepositAddress.go @@ -0,0 +1,29 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + DepositAddress() +} + +func DepositAddress() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // DepositAddressService - /sapi/v1/capital/deposit/address + depositAddress, err := client.NewDepositAddressService().Coin("BTC"). + Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(depositAddress)) +} diff --git a/examples/wallet/DepositHistory/DepositHistory.go b/examples/wallet/DepositHistory/DepositHistory.go new file mode 100644 index 0000000..d536da1 --- /dev/null +++ b/examples/wallet/DepositHistory/DepositHistory.go @@ -0,0 +1,29 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + DepositHistory() +} + +func DepositHistory() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // DepositHistoryService - /sapi/v1/capital/deposit/hisrec + depositHistory, err := client.NewDepositHistoryService().Coin("BTC"). + Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(depositHistory)) +} diff --git a/examples/wallet/DisableFastWithdrawSwitch/DisableFastWithdrawSwitch.go b/examples/wallet/DisableFastWithdrawSwitch/DisableFastWithdrawSwitch.go new file mode 100644 index 0000000..0b90d53 --- /dev/null +++ b/examples/wallet/DisableFastWithdrawSwitch/DisableFastWithdrawSwitch.go @@ -0,0 +1,29 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + DisableFastWithdrawSwitch() +} + +func DisableFastWithdrawSwitch() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // DisableFastWithdrawSwitchService - /sapi/v1/account/disableFastWithdrawSwitch + disableFastWithdrawSwitch, err := client.NewDisableFastWithdrawSwitchService(). + Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(disableFastWithdrawSwitch)) +} diff --git a/examples/wallet/DustLog/DustLog.go b/examples/wallet/DustLog/DustLog.go new file mode 100644 index 0000000..261ddd5 --- /dev/null +++ b/examples/wallet/DustLog/DustLog.go @@ -0,0 +1,28 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + DustLog() +} + +func DustLog() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // DustLogService - /sapi/v1/asset/dribblet + dustLog, err := client.NewDustLogService().Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(dustLog)) +} diff --git a/examples/wallet/DustTransfer/DustTransfer.go b/examples/wallet/DustTransfer/DustTransfer.go new file mode 100644 index 0000000..99b83ac --- /dev/null +++ b/examples/wallet/DustTransfer/DustTransfer.go @@ -0,0 +1,29 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + DustTransfer() +} + +func DustTransfer() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // DustTransferService - /sapi/v1/asset/dust + dustTransfer, err := client.NewDustTransferService().Asset([]string{"ETH", "LTC", "TRX"}). + Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(dustTransfer)) +} diff --git a/examples/wallet/EnableFastWithdrawSwitch/EnableFastWithdrawSwitch.go b/examples/wallet/EnableFastWithdrawSwitch/EnableFastWithdrawSwitch.go new file mode 100644 index 0000000..1fbfa2d --- /dev/null +++ b/examples/wallet/EnableFastWithdrawSwitch/EnableFastWithdrawSwitch.go @@ -0,0 +1,29 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + EnableFastWithdrawSwitchService() +} + +func EnableFastWithdrawSwitchService() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // EnableFastWithdrawSwitchService - /sapi/v1/account/enableFastWithdrawSwitch + res, err := client.NewEnableFastWithdrawSwitchService(). + Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(res)) +} diff --git a/examples/wallet/FundingWallet/FundingWallet.go b/examples/wallet/FundingWallet/FundingWallet.go new file mode 100644 index 0000000..034c024 --- /dev/null +++ b/examples/wallet/FundingWallet/FundingWallet.go @@ -0,0 +1,29 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + FundingWallet() +} + +func FundingWallet() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // FundingWalletService - /sapi/v1/asset/get-funding-asset + fundingWallet, err := client.NewFundingWalletService().Asset("BTC"). + Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(fundingWallet)) +} diff --git a/examples/wallet/GetAccountSnapshot/GetAccountSnapshot.go b/examples/wallet/GetAccountSnapshot/GetAccountSnapshot.go new file mode 100644 index 0000000..9e8f6e9 --- /dev/null +++ b/examples/wallet/GetAccountSnapshot/GetAccountSnapshot.go @@ -0,0 +1,29 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + AccountSnapshot() +} + +func AccountSnapshot() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // GetAccountSnapshotService get all orders from account - /sapi/v1/accountSnapshot + accountSnapshot, err := client.NewGetAccountSnapshotService().MarketType("SPOT"). + Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(accountSnapshot)) +} diff --git a/examples/wallet/GetAllCoinsInfo/GetAllCoinsInfo.go b/examples/wallet/GetAllCoinsInfo/GetAllCoinsInfo.go new file mode 100644 index 0000000..169bd03 --- /dev/null +++ b/examples/wallet/GetAllCoinsInfo/GetAllCoinsInfo.go @@ -0,0 +1,28 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + AllCoinsInfo() +} + +func AllCoinsInfo() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // GetAllCoinsInfoService - /sapi/v1/capital/config/getall + allCoinsInfo, err := client.NewGetAllCoinsInfoService().Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(allCoinsInfo)) +} diff --git a/examples/wallet/GetSystemStatus/GetSystemStatus.go b/examples/wallet/GetSystemStatus/GetSystemStatus.go new file mode 100644 index 0000000..4836ac9 --- /dev/null +++ b/examples/wallet/GetSystemStatus/GetSystemStatus.go @@ -0,0 +1,28 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + GetSystemStatus() +} + +func GetSystemStatus() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // GetSystemStatusService get account info - /sapi/v1/system/status + systemStatus, err := client.NewGetSystemStatusService().Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(systemStatus)) +} diff --git a/examples/wallet/TradeFee/TradeFee.go b/examples/wallet/TradeFee/TradeFee.go new file mode 100644 index 0000000..44b3f72 --- /dev/null +++ b/examples/wallet/TradeFee/TradeFee.go @@ -0,0 +1,29 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + TradeFee() +} + +func TradeFee() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // TradeFeeService - /sapi/v1/asset/tradeFee + tradeFee, err := client.NewTradeFeeService().Symbol("BTC"). + Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(tradeFee)) +} diff --git a/examples/wallet/UserAsset/UserAsset.go b/examples/wallet/UserAsset/UserAsset.go new file mode 100644 index 0000000..072197b --- /dev/null +++ b/examples/wallet/UserAsset/UserAsset.go @@ -0,0 +1,29 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + UserAsset() +} + +func UserAsset() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // UserAssetService - /sapi/v3/asset/getUserAsset + userAsset, err := client.NewUserAssetService().Asset("BTC"). + Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(userAsset)) +} diff --git a/examples/wallet/UserUniversalTransfer/UserUniversalTransfer.go b/examples/wallet/UserUniversalTransfer/UserUniversalTransfer.go new file mode 100644 index 0000000..a415d74 --- /dev/null +++ b/examples/wallet/UserUniversalTransfer/UserUniversalTransfer.go @@ -0,0 +1,29 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + UserUniversalTransfer() +} + +func UserUniversalTransfer() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // UserUniversalTransferService - /sapi/v1/asset/transfer + userUniversalTransfer, err := client.NewUserUniversalTransferService(). + TransferType("MAIN_UMFUTURE").Asset("USDT").Amount(20.50).Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(userUniversalTransfer)) +} diff --git a/examples/wallet/UserUniversalTransferHistory/UserUniversalTransferHistory.go b/examples/wallet/UserUniversalTransferHistory/UserUniversalTransferHistory.go new file mode 100644 index 0000000..937d78d --- /dev/null +++ b/examples/wallet/UserUniversalTransferHistory/UserUniversalTransferHistory.go @@ -0,0 +1,29 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + UserUniversalTransferHistory() +} + +func UserUniversalTransferHistory() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // UserUniversalTransferHistoryService - /sapi/v1/asset/transfer + userUniversalTransferHistory, err := client.NewUserUniversalTransferHistoryService(). + TransferType("MAIN_UMFUTURE").Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(userUniversalTransferHistory)) +} diff --git a/examples/wallet/Withdraw/Withdraw.go b/examples/wallet/Withdraw/Withdraw.go new file mode 100644 index 0000000..61785b9 --- /dev/null +++ b/examples/wallet/Withdraw/Withdraw.go @@ -0,0 +1,29 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + Withdraw() +} + +func Withdraw() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // WithdrawService - /sapi/v1/capital/withdraw/apply + withdraw, err := client.NewWithdrawService().Coin("BTC").Address("123123123"). + Amount(0.01).Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(withdraw)) +} diff --git a/examples/wallet/WithdrawHistory/WithdrawHistory.go b/examples/wallet/WithdrawHistory/WithdrawHistory.go new file mode 100644 index 0000000..2f308a2 --- /dev/null +++ b/examples/wallet/WithdrawHistory/WithdrawHistory.go @@ -0,0 +1,29 @@ +package main + +import ( + "context" + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + WithdrawHistory() +} + +func WithdrawHistory() { + apiKey := "your api key" + secretKey := "your secret key" + baseURL := "https://api.binance.com" + + client := binance_connector.NewClient(apiKey, secretKey, baseURL) + + // WithdrawHistoryService - /sapi/v1/capital/withdraw/history + withdrawHistory, err := client.NewWithdrawHistoryService(). + Do(context.Background()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(binance_connector.PrettyPrint(withdrawHistory)) +} diff --git a/examples/websocket/AllMarketMiniTickers/AllMarketMiniTickers.go b/examples/websocket/AllMarketMiniTickers/AllMarketMiniTickers.go new file mode 100644 index 0000000..b7de99d --- /dev/null +++ b/examples/websocket/AllMarketMiniTickers/AllMarketMiniTickers.go @@ -0,0 +1,26 @@ +package main + +import ( + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + WsAllMarketMiniTickers() +} + +func WsAllMarketMiniTickers() { + wsAllMarketMiniTickersHandler := func(event binance_connector.WsAllMiniMarketsStatEvent) { + fmt.Println(binance_connector.PrettyPrint(event)) + } + errHandler := func(err error) { + fmt.Println(err) + } + doneCh, _, err := binance_connector.WsAllMiniMarketsStatServe(wsAllMarketMiniTickersHandler, errHandler) + if err != nil { + fmt.Println(err) + return + } + <-doneCh +} diff --git a/examples/websocket/AllMarketTickers/AllMarketTickers.go b/examples/websocket/AllMarketTickers/AllMarketTickers.go new file mode 100644 index 0000000..26adfb4 --- /dev/null +++ b/examples/websocket/AllMarketTickers/AllMarketTickers.go @@ -0,0 +1,26 @@ +package main + +import ( + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + WsAllMarketTickersExample() +} + +func WsAllMarketTickersExample() { + wsAllMarketTickersHandler := func(event binance_connector.WsAllMarketsStatEvent) { + fmt.Println(binance_connector.PrettyPrint(event)) + } + errHandler := func(err error) { + fmt.Println(err) + } + doneCh, _, err := binance_connector.WsAllMarketsStatServe(wsAllMarketTickersHandler, errHandler) + if err != nil { + fmt.Println(err) + return + } + <-doneCh +} diff --git a/examples/websocket/UserDataStream/UserDataStream.go b/examples/websocket/UserDataStream/UserDataStream.go new file mode 100644 index 0000000..bb04248 --- /dev/null +++ b/examples/websocket/UserDataStream/UserDataStream.go @@ -0,0 +1,26 @@ +package main + +import ( + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + WsUserData() +} + +func WsUserData() { + wsUserDataHandler := func(event *binance_connector.WsUserDataEvent) { + fmt.Println(binance_connector.PrettyPrint(event)) + } + errHandler := func(err error) { + fmt.Println(err) + } + doneCh, _, err := binance_connector.WsUserDataServe("YourListenKey", wsUserDataHandler, errHandler) + if err != nil { + fmt.Println(err) + return + } + <-doneCh +} diff --git a/examples/websocket/aggtrades/aggtrades.go b/examples/websocket/aggtrades/aggtrades.go new file mode 100644 index 0000000..c37270f --- /dev/null +++ b/examples/websocket/aggtrades/aggtrades.go @@ -0,0 +1,26 @@ +package main + +import ( + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + AggTradesExample() +} + +func AggTradesExample() { + wsAggTradeHandler := func(event *binance_connector.WsAggTradeEvent) { + fmt.Println(binance_connector.PrettyPrint(event)) + } + errHandler := func(err error) { + fmt.Println(err) + } + doneCh, _, err := binance_connector.WsAggTradeServe("LTCBTC", wsAggTradeHandler, errHandler) + if err != nil { + fmt.Println(err) + return + } + <-doneCh +} diff --git a/examples/websocket/bookticker/bookticker.go b/examples/websocket/bookticker/bookticker.go new file mode 100644 index 0000000..9580d4c --- /dev/null +++ b/examples/websocket/bookticker/bookticker.go @@ -0,0 +1,26 @@ +package main + +import ( + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + WsBookTickerExample() +} + +func WsBookTickerExample() { + wsBookTickerHandler := func(event *binance_connector.WsBookTickerEvent) { + fmt.Println(binance_connector.PrettyPrint(event)) + } + errHandler := func(err error) { + fmt.Println(err) + } + doneCh, _, err := binance_connector.WsBookTickerServe("LTCBTC", wsBookTickerHandler, errHandler) + if err != nil { + fmt.Println(err) + return + } + <-doneCh +} diff --git a/examples/websocket/depth/depth.go b/examples/websocket/depth/depth.go new file mode 100644 index 0000000..35d9f41 --- /dev/null +++ b/examples/websocket/depth/depth.go @@ -0,0 +1,33 @@ +package main + +import ( + "fmt" + "time" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + WsDepthHandlerExample() +} + +func WsDepthHandlerExample() { + wsDepthHandler := func(event *binance_connector.WsDepthEvent) { + fmt.Println(binance_connector.PrettyPrint(event)) + } + errHandler := func(err error) { + fmt.Println(err) + } + doneCh, stopCh, err := binance_connector.WsDepthServe("LTCBTC", wsDepthHandler, errHandler) + if err != nil { + fmt.Println(err) + return + } + // use stopC to exit + go func() { + time.Sleep(5 * time.Second) + stopCh <- struct{}{} + }() + // remove this if you do not want to be blocked here + <-doneCh +} diff --git a/examples/websocket/kline/kline.go b/examples/websocket/kline/kline.go new file mode 100644 index 0000000..eb76864 --- /dev/null +++ b/examples/websocket/kline/kline.go @@ -0,0 +1,26 @@ +package main + +import ( + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + WsKlineExample() +} + +func WsKlineExample() { + wsKlineHandler := func(event *binance_connector.WsKlineEvent) { + fmt.Println(binance_connector.PrettyPrint(event)) + } + errHandler := func(err error) { + fmt.Println(err) + } + doneCh, _, err := binance_connector.WsKlineServe("LTCBTC", "1m", wsKlineHandler, errHandler) + if err != nil { + fmt.Println(err) + return + } + <-doneCh +} diff --git a/examples/websocket/trades/trades.go b/examples/websocket/trades/trades.go new file mode 100644 index 0000000..af3b167 --- /dev/null +++ b/examples/websocket/trades/trades.go @@ -0,0 +1,26 @@ +package main + +import ( + "fmt" + + binance_connector "github.com/binance/binance-connector-go" +) + +func main() { + WsTradeExample() +} + +func WsTradeExample() { + wsTradeHandler := func(event *binance_connector.WsTradeEvent) { + fmt.Println(binance_connector.PrettyPrint(event)) + } + errHandler := func(err error) { + fmt.Println(err) + } + doneCh, _, err := binance_connector.WsTradeServe("LTCBTC", wsTradeHandler, errHandler) + if err != nil { + fmt.Println(err) + return + } + <-doneCh +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..97cdb92 --- /dev/null +++ b/go.mod @@ -0,0 +1,14 @@ +module github.com/binance/binance-connector-go + +go 1.14 + +require ( + github.com/bitly/go-simplejson v0.5.0 + github.com/gorilla/websocket v1.5.0 + github.com/stretchr/testify v1.8.2 +) + +require ( + github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 // indirect + github.com/kr/pretty v0.3.1 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..4bb3ae8 --- /dev/null +++ b/go.sum @@ -0,0 +1,32 @@ +github.com/bitly/go-simplejson v0.5.0 h1:6IH+V8/tVMab511d5bn4M7EwGXZf9Hj6i2xSwkNEM+Y= +github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngEKAMDJEczWVA= +github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 h1:DDGfHa7BWjL4YnC6+E63dPcxHo2sUxDIu8g3QgEJdRY= +github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= +github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/handlers/errors.go b/handlers/errors.go new file mode 100644 index 0000000..98c7e6d --- /dev/null +++ b/handlers/errors.go @@ -0,0 +1,22 @@ +package handlers + +import ( + "fmt" +) + +// APIError define API error when response status is 4xx or 5xx +type APIError struct { + Code int64 `json:"code"` + Message string `json:"msg"` +} + +// Error return error code and message +func (e APIError) Error() string { + return fmt.Sprintf(" code=%d, msg=%s", e.Code, e.Message) +} + +// IsAPIError check if e is an API error +func IsAPIError(e error) bool { + _, ok := e.(*APIError) + return ok +} diff --git a/margin.go b/margin.go new file mode 100644 index 0000000..8f7f645 --- /dev/null +++ b/margin.go @@ -0,0 +1,3650 @@ +package binance_connector + +import ( + "context" + "encoding/json" + "net/http" +) + +// Cross Margin Account Transfer API Endpoint +const ( + transferEndpoint = "/sapi/v1/margin/transfer" +) + +// TransferService transfer between spot and margin account +type TransferService struct { + c *Client + asset string + amount float64 + transferType int +} + +// Asset set asset +func (s *TransferService) Asset(asset string) *TransferService { + s.asset = asset + return s +} + +// Amount set amount +func (s *TransferService) Amount(amount float64) *TransferService { + s.amount = amount + return s +} + +// TransferType set transfer type +func (s *TransferService) TransferType(transferType int) *TransferService { + s.transferType = transferType + return s +} + +// Do send request +func (s *TransferService) Do(ctx context.Context, opts ...RequestOption) (res *TransferResponse, err error) { + r := &request{ + method: http.MethodPost, + endpoint: transferEndpoint, + secType: secTypeSigned, + } + r.setParam("asset", s.asset) + r.setParam("amount", s.amount) + r.setParam("type", s.transferType) + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return &TransferResponse{}, err + } + res = new(TransferResponse) + err = json.Unmarshal(data, res) + if err != nil { + return &TransferResponse{}, err + } + return res, nil +} + +// TransferResponse define transfer response +type TransferResponse struct { + TranId int64 `json:"tranId"` +} + +// Cross Margin Account Borrow API Endpoint +const ( + borrowEndpoint = "/sapi/v1/margin/loan" +) + +// BorrowService borrow from cross margin account +type BorrowService struct { + c *Client + asset string + amount float64 + isIsolated *string + symbol *string +} + +// Asset set asset +func (s *BorrowService) Asset(asset string) *BorrowService { + s.asset = asset + return s +} + +// Amount set amount +func (s *BorrowService) Amount(amount float64) *BorrowService { + s.amount = amount + return s +} + +// IsIsolated set isolated +func (s *BorrowService) IsIsolated(isIsolated string) *BorrowService { + s.isIsolated = &isIsolated + return s +} + +// Do send request +func (s *BorrowService) Do(ctx context.Context, opts ...RequestOption) (res *BorrowResponse, err error) { + r := &request{ + method: http.MethodPost, + endpoint: borrowEndpoint, + secType: secTypeSigned, + } + r.setParam("asset", s.asset) + r.setParam("amount", s.amount) + if s.isIsolated != nil { + r.setParam("isolatedSymbol", *s.isIsolated) + } + if s.symbol != nil { + r.setParam("symbol", *s.symbol) + } + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return &BorrowResponse{}, err + } + res = new(BorrowResponse) + err = json.Unmarshal(data, res) + if err != nil { + return &BorrowResponse{}, err + } + return res, nil +} + +// BorrowResponse define borrow response +type BorrowResponse struct { + TranId int64 `json:"tranId"` +} + +// Cross Margin Account Repay API Endpoint +const ( + repayEndpoint = "/sapi/v1/margin/repay" +) + +// RepayService repay to cross margin account +type RepayService struct { + c *Client + asset string + isIsolated *string + symbol *string + amount float64 +} + +// Asset set asset +func (s *RepayService) Asset(asset string) *RepayService { + s.asset = asset + return s +} + +// Amount set amount +func (s *RepayService) Amount(amount float64) *RepayService { + s.amount = amount + return s +} + +// Symbol set symbol +func (s *RepayService) Symbol(symbol string) *RepayService { + s.symbol = &symbol + return s +} + +// IsIsolated set isolated +func (s *RepayService) IsIsolated(isIsolated string) *RepayService { + s.isIsolated = &isIsolated + return s +} + +// Do send request +func (s *RepayService) Do(ctx context.Context, opts ...RequestOption) (res *RepayResponse, err error) { + r := &request{ + method: http.MethodPost, + endpoint: repayEndpoint, + secType: secTypeSigned, + } + r.setParam("asset", s.asset) + r.setParam("amount", s.amount) + if s.isIsolated != nil { + r.setParam("isIsolated", *s.isIsolated) + } + if s.symbol != nil { + r.setParam("symbol", *s.symbol) + } + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return &RepayResponse{}, err + } + res = new(RepayResponse) + err = json.Unmarshal(data, res) + if err != nil { + return &RepayResponse{}, err + } + return res, nil +} + +// RepayResponse define repay response +type RepayResponse struct { + TranId int64 `json:"tranId"` +} + +// Query Margin Asset API Endpoint +const ( + queryMarginAssetEndpoint = "/sapi/v1/margin/asset" +) + +// QueryMarginAssetService query margin asset +type QueryMarginAssetService struct { + c *Client + asset string +} + +// Asset set asset +func (s *QueryMarginAssetService) Asset(asset string) *QueryMarginAssetService { + s.asset = asset + return s +} + +// Do send request +func (s *QueryMarginAssetService) Do(ctx context.Context, opts ...RequestOption) (res *QueryMarginAssetResponse, err error) { + r := &request{ + method: http.MethodGet, + endpoint: queryMarginAssetEndpoint, + secType: secTypeAPIKey, + } + r.setParam("asset", s.asset) + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return &QueryMarginAssetResponse{}, err + } + res = new(QueryMarginAssetResponse) + err = json.Unmarshal(data, res) + if err != nil { + return &QueryMarginAssetResponse{}, err + } + return res, nil +} + +// QueryMarginAssetResponse define query margin asset response +type QueryMarginAssetResponse struct { + FullName string `json:"assetFullName"` + Name string `json:"assetName"` + Borrowable bool `json:"isBorrowable"` + Mortgageable bool `json:"isMortgageable"` + UserMinBorrow string `json:"userMinBorrow"` + UserMinRepay string `json:"userMinRepay"` +} + +// Query Cross Margin Pair API Endpoint +const ( + queryCrossMarginPairEndpoint = "/sapi/v1/margin/pair" +) + +// QueryCrossMarginPairService query cross margin pair +type QueryCrossMarginPairService struct { + c *Client + symbol string +} + +// Symbol set symbol +func (s *QueryCrossMarginPairService) Symbol(symbol string) *QueryCrossMarginPairService { + s.symbol = symbol + return s +} + +// Do send request +func (s *QueryCrossMarginPairService) Do(ctx context.Context, opts ...RequestOption) (res *QueryCrossMarginPairResponse, err error) { + r := &request{ + method: http.MethodGet, + endpoint: queryCrossMarginPairEndpoint, + secType: secTypeSigned, + } + r.setParam("symbol", s.symbol) + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return &QueryCrossMarginPairResponse{}, err + } + res = new(QueryCrossMarginPairResponse) + err = json.Unmarshal(data, res) + if err != nil { + return &QueryCrossMarginPairResponse{}, err + } + return res, nil +} + +// QueryCrossMarginPairResponse define query cross margin pair response +type QueryCrossMarginPairResponse struct { + SymbolDetail struct { + Symbol string `json:"symbol"` + IsMarginTrade bool `json:"isMarginTrade"` + IsBuyAllowed bool `json:"isBuyAllowed"` + IsSellAllowed bool `json:"isSellAllowed"` + } `json:"symbolDetail"` +} + +// Get all margin assets API Endpoint +const ( + getAllMarginAssetsEndpoint = "/sapi/v1/margin/allAssets" +) + +// GetAllMarginAssetsService get all margin assets +type GetAllMarginAssetsService struct { + c *Client +} + +// Do send request +func (s *GetAllMarginAssetsService) Do(ctx context.Context, opts ...RequestOption) (res *GetAllMarginAssetsResponse, err error) { + r := &request{ + method: http.MethodGet, + endpoint: getAllMarginAssetsEndpoint, + secType: secTypeSigned, + } + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return &GetAllMarginAssetsResponse{}, err + } + res = new(GetAllMarginAssetsResponse) + err = json.Unmarshal(data, res) + if err != nil { + return &GetAllMarginAssetsResponse{}, err + } + return res, nil +} + +// GetAllMarginAssetsResponse define get all margin assets response +type GetAllMarginAssetsResponse struct { + AssetDetailList []struct { + AssetFullName string `json:"assetFullName"` + AssetName string `json:"assetName"` + IsBorrowable bool `json:"isBorrowable"` + IsMortgageable bool `json:"isMortgageable"` + MinLoanAmt string `json:"minLoanAmt"` + MaxLoanAmt string `json:"maxLoanAmt"` + MinMortgageAmt string `json:"minMortgageAmt"` + MaxMortgageAmt string `json:"maxMortgageAmt"` + Asset string `json:"asset"` + } `json:"assetDetailList"` +} + +// Get all margin pairs API Endpoint +const ( + getAllMarginPairsEndpoint = "/sapi/v1/margin/allPairs" +) + +// GetAllMarginPairsService get all margin pairs +type GetAllMarginPairsService struct { + c *Client +} + +// Do send request +func (s *GetAllMarginPairsService) Do(ctx context.Context, opts ...RequestOption) (res *GetAllMarginPairsResponse, err error) { + r := &request{ + method: http.MethodGet, + endpoint: getAllMarginPairsEndpoint, + secType: secTypeAPIKey, + } + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return &GetAllMarginPairsResponse{}, err + } + res = new(GetAllMarginPairsResponse) + err = json.Unmarshal(data, res) + if err != nil { + return &GetAllMarginPairsResponse{}, err + } + return res, nil +} + +// GetAllMarginPairsResponse define get all margin pairs response +type GetAllMarginPairsResponse struct { + SymbolDetailList []struct { + Base string `json:"base"` + Id int `json:"id"` + IsBuyAllowed bool `json:"isBuyAllowed"` + IsMarginTrade bool `json:"isMarginTrade"` + IsSellAllowed bool `json:"isSellAllowed"` + Quote string `json:"quote"` + Symbol string `json:"symbol"` + } `json:"symbolDetailList"` +} + +// Query Margin Price Index API Endpoint +const ( + queryMarginPriceIndexEndpoint = "/sapi/v1/margin/priceIndex" +) + +// QueryMarginPriceIndexService query margin price index +type QueryMarginPriceIndexService struct { + c *Client + symbol string +} + +// Symbol set symbol +func (s *QueryMarginPriceIndexService) Symbol(symbol string) *QueryMarginPriceIndexService { + s.symbol = symbol + return s +} + +// Do send request +func (s *QueryMarginPriceIndexService) Do(ctx context.Context, opts ...RequestOption) (res *QueryMarginPriceIndexResponse, err error) { + r := &request{ + method: http.MethodGet, + endpoint: queryMarginPriceIndexEndpoint, + secType: secTypeAPIKey, + } + r.setParam("symbol", s.symbol) + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return &QueryMarginPriceIndexResponse{}, err + } + res = new(QueryMarginPriceIndexResponse) + err = json.Unmarshal(data, res) + if err != nil { + return &QueryMarginPriceIndexResponse{}, err + } + return res, nil +} + +// QueryMarginPriceIndexResponse define query margin price index response +type QueryMarginPriceIndexResponse struct { + CalcTime int64 `json:"calcTime"` + Price string `json:"price"` + Symbol string `json:"symbol"` +} + +// Margin Accouunt New Order (TRADE) API Endpoint +const ( + marginAccountNewOrderEndpoint = "/sapi/v1/margin/order" +) + +// MarginAccountNewOrderService margin account new order +type MarginAccountNewOrderService struct { + c *Client + symbol string + isIsolated *string + side string + orderType string + quantity *float64 + quoteOrderQty *float64 + price *float64 + stopPrice *float64 + newClientOrderId *string + icebergQty *float64 + newOrderRespType *string + sideEffectType *string + timeInForce *string +} + +// Symbol set symbol +func (s *MarginAccountNewOrderService) Symbol(symbol string) *MarginAccountNewOrderService { + s.symbol = symbol + return s +} + +// IsIsolated set isIsolated +func (s *MarginAccountNewOrderService) IsIsolated(isIsolated string) *MarginAccountNewOrderService { + s.isIsolated = &isIsolated + return s +} + +// Side set side +func (s *MarginAccountNewOrderService) Side(side string) *MarginAccountNewOrderService { + s.side = side + return s +} + +// OrderType set orderType +func (s *MarginAccountNewOrderService) OrderType(orderType string) *MarginAccountNewOrderService { + s.orderType = orderType + return s +} + +// Quantity set quantity +func (s *MarginAccountNewOrderService) Quantity(quantity float64) *MarginAccountNewOrderService { + s.quantity = &quantity + return s +} + +// QuoteOrderQty set quoteOrderQty +func (s *MarginAccountNewOrderService) QuoteOrderQty(quoteOrderQty float64) *MarginAccountNewOrderService { + s.quoteOrderQty = "eOrderQty + return s +} + +// Price set price +func (s *MarginAccountNewOrderService) Price(price float64) *MarginAccountNewOrderService { + s.price = &price + return s +} + +// StopPrice set stopPrice +func (s *MarginAccountNewOrderService) StopPrice(stopPrice float64) *MarginAccountNewOrderService { + s.stopPrice = &stopPrice + return s +} + +// NewClientOrderId set newClientOrderId +func (s *MarginAccountNewOrderService) NewClientOrderId(newClientOrderId string) *MarginAccountNewOrderService { + s.newClientOrderId = &newClientOrderId + return s +} + +// IcebergQty set icebergQty +func (s *MarginAccountNewOrderService) IcebergQty(icebergQty float64) *MarginAccountNewOrderService { + s.icebergQty = &icebergQty + return s +} + +// NewOrderRespType set newOrderRespType +func (s *MarginAccountNewOrderService) NewOrderRespType(newOrderRespType string) *MarginAccountNewOrderService { + s.newOrderRespType = &newOrderRespType + return s +} + +// SideEffectType set sideEffectType +func (s *MarginAccountNewOrderService) SideEffectType(sideEffectType string) *MarginAccountNewOrderService { + s.sideEffectType = &sideEffectType + return s +} + +// TimeInForce set timeInForce +func (s *MarginAccountNewOrderService) TimeInForce(timeInForce string) *MarginAccountNewOrderService { + s.timeInForce = &timeInForce + return s +} + +// Do send request +func (s *MarginAccountNewOrderService) Do(ctx context.Context, opts ...RequestOption) (res *MarginAccountNewOrderResponse, err error) { + r := &request{ + method: http.MethodPost, + endpoint: marginAccountNewOrderEndpoint, + secType: secTypeSigned, + } + m := params{ + "symbol": s.symbol, + "side": s.side, + "type": s.orderType, + } + if s.isIsolated != nil { + m["isIsolated"] = *s.isIsolated + } + if s.quantity != nil { + m["quantity"] = *s.quantity + } + if s.quoteOrderQty != nil { + m["quoteOrderQty"] = *s.quoteOrderQty + } + if s.price != nil { + m["price"] = *s.price + } + if s.stopPrice != nil { + m["stopPrice"] = *s.stopPrice + } + if s.newClientOrderId != nil { + m["newClientOrderId"] = *s.newClientOrderId + } + if s.icebergQty != nil { + m["icebergQty"] = *s.icebergQty + } + if s.newOrderRespType != nil { + m["newOrderRespType"] = *s.newOrderRespType + } + if s.sideEffectType != nil { + m["sideEffectType"] = *s.sideEffectType + } + if s.timeInForce != nil { + m["timeInForce"] = *s.timeInForce + } + r.setParams(m) + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return &MarginAccountNewOrderResponse{}, err + } + res = new(MarginAccountNewOrderResponse) + err = json.Unmarshal(data, res) + if err != nil { + return &MarginAccountNewOrderResponse{}, err + } + return res, nil +} + +// MarginAccountNewOrderResponse define margin account new order response +type MarginAccountNewOrderResponse struct { + Symbol string `json:"symbol"` + OrderId int64 `json:"orderId"` + ClientOrderId string `json:"clientOrderId"` + TransactTime uint64 `json:"transactTime"` + Price string `json:"price"` + OrigQty string `json:"origQty"` + ExecutedQty string `json:"executedQty"` + CumulativeQuoteQty string `json:"cummulativeQuoteQty"` + Status string `json:"status"` + TimeInForce string `json:"timeInForce"` + Type string `json:"type"` + IsIsolated bool `json:"isIsolated"` + Side string `json:"side"` +} + +// Margin Account Cancel Order (TRADE) API Endpoint +const ( + marginAccountCancelOrderEndpoint = "/sapi/v1/margin/order" +) + +// MarginAccountCancelOrderService margin account cancel order +type MarginAccountCancelOrderService struct { + c *Client + symbol string + isIsolated *string + orderId *int + origClientOrderId *string + newClientOrderId *string +} + +// Symbol set symbol +func (s *MarginAccountCancelOrderService) Symbol(symbol string) *MarginAccountCancelOrderService { + s.symbol = symbol + return s +} + +// IsIsolated set isIsolated +func (s *MarginAccountCancelOrderService) IsIsolated(isIsolated string) *MarginAccountCancelOrderService { + s.isIsolated = &isIsolated + return s +} + +// OrderId set orderId +func (s *MarginAccountCancelOrderService) OrderId(orderId int) *MarginAccountCancelOrderService { + s.orderId = &orderId + return s +} + +// OrigClientOrderId set origClientOrderId +func (s *MarginAccountCancelOrderService) OrigClientOrderId(origClientOrderId string) *MarginAccountCancelOrderService { + s.origClientOrderId = &origClientOrderId + return s +} + +// NewClientOrderId set newClientOrderId +func (s *MarginAccountCancelOrderService) NewClientOrderId(newClientOrderId string) *MarginAccountCancelOrderService { + s.newClientOrderId = &newClientOrderId + return s +} + +// Do send request +func (s *MarginAccountCancelOrderService) Do(ctx context.Context, opts ...RequestOption) (res *MarginAccountCancelOrderResponse, err error) { + r := &request{ + method: http.MethodDelete, + endpoint: marginAccountCancelOrderEndpoint, + secType: secTypeSigned, + } + m := params{ + "symbol": s.symbol, + } + if s.isIsolated != nil { + m["isIsolated"] = *s.isIsolated + } + if s.orderId != nil { + m["orderId"] = *s.orderId + } + if s.origClientOrderId != nil { + m["origClientOrderId"] = *s.origClientOrderId + } + if s.newClientOrderId != nil { + m["newClientOrderId"] = *s.newClientOrderId + } + r.setParams(m) + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return &MarginAccountCancelOrderResponse{}, err + } + res = new(MarginAccountCancelOrderResponse) + err = json.Unmarshal(data, res) + if err != nil { + return &MarginAccountCancelOrderResponse{}, err + } + return res, nil +} + +// MarginAccountCancelOrderResponse define margin account cancel order response +type MarginAccountCancelOrderResponse struct { + Symbol string `json:"symbol"` + IsIsolated bool `json:"isIsolated"` + OrderId int `json:"orderId"` + OrigClientOrderId string `json:"origClientOrderId"` + ClientOrderId string `json:"clientOrderId"` + Price string `json:"price"` + OrigQty string `json:"origQty"` + ExecutedQty string `json:"executedQty"` + CumulativeQuoteQty string `json:"cumulativeQuoteQty"` + Status string `json:"status"` + TimeInForce string `json:"timeInForce"` + Type string `json:"type"` + Side string `json:"side"` +} + +// Margin Account Cancel All Orders (TRADE) API Endpoint +const ( + marginAccountCancelAllOrdersEndpoint = "/sapi/v1/margin/openOrders" +) + +// MarginAccountCancelAllOrdersService margin account cancel all orders +type MarginAccountCancelAllOrdersService struct { + c *Client + symbol string + isIsolated *string +} + +// Symbol set symbol +func (s *MarginAccountCancelAllOrdersService) Symbol(symbol string) *MarginAccountCancelAllOrdersService { + s.symbol = symbol + return s +} + +// IsIsolated set isIsolated +func (s *MarginAccountCancelAllOrdersService) IsIsolated(isIsolated string) *MarginAccountCancelAllOrdersService { + s.isIsolated = &isIsolated + return s +} + +// Do send request +func (s *MarginAccountCancelAllOrdersService) Do(ctx context.Context, opts ...RequestOption) (res *MarginAccountCancelAllOrdersResponse, err error) { + r := &request{ + method: http.MethodDelete, + endpoint: marginAccountCancelAllOrdersEndpoint, + secType: secTypeSigned, + } + m := params{ + "symbol": s.symbol, + } + if s.isIsolated != nil { + m["isIsolated"] = *s.isIsolated + } + r.setParams(m) + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return &MarginAccountCancelAllOrdersResponse{}, err + } + res = new(MarginAccountCancelAllOrdersResponse) + err = json.Unmarshal(data, res) + if err != nil { + return &MarginAccountCancelAllOrdersResponse{}, err + } + return res, nil +} + +// MarginAccountCancelAllOrdersResponse define margin account cancel all orders response +type MarginAccountCancelAllOrdersResponse struct { + Symbol string `json:"symbol"` + IsIsolated bool `json:"isIsolated"` + OrigClientOrderId string `json:"origClientOrderId"` + OrderId int `json:"orderId"` + OrderListId int `json:"orderListId"` + ClientOrderId string `json:"clientOrderId"` + Price string `json:"price"` + OrigQty string `json:"origQty"` + ExecutedQty string `json:"executedQty"` + CumulativeQuoteQty string `json:"cumulativeQuoteQty"` + Status string `json:"status"` + TimeInForce string `json:"timeInForce"` + Type string `json:"type"` + Side string `json:"side"` +} + +// Get Cross Margin Transfer History (USER_DATA) API Endpoint +const ( + crossMarginTransferHistoryEndpoint = "/sapi/v1/margin/transfer" +) + +// CrossMarginTransferHistoryService get cross margin transfer history +type CrossMarginTransferHistoryService struct { + c *Client + asset *string + orderType *string + startTime *uint64 + endTime *uint64 + current *int + size *int + archived *string +} + +// Asset set asset +func (s *CrossMarginTransferHistoryService) Asset(asset string) *CrossMarginTransferHistoryService { + s.asset = &asset + return s +} + +// OrderType set orderType +func (s *CrossMarginTransferHistoryService) OrderType(orderType string) *CrossMarginTransferHistoryService { + s.orderType = &orderType + return s +} + +// StartTime set startTime +func (s *CrossMarginTransferHistoryService) StartTime(startTime uint64) *CrossMarginTransferHistoryService { + s.startTime = &startTime + return s +} + +// EndTime set endTime +func (s *CrossMarginTransferHistoryService) EndTime(endTime uint64) *CrossMarginTransferHistoryService { + s.endTime = &endTime + return s +} + +// Current set current +func (s *CrossMarginTransferHistoryService) Current(current int) *CrossMarginTransferHistoryService { + s.current = ¤t + return s +} + +// Size set size +func (s *CrossMarginTransferHistoryService) Size(size int) *CrossMarginTransferHistoryService { + s.size = &size + return s +} + +// Archived set archived +func (s *CrossMarginTransferHistoryService) Archived(archived string) *CrossMarginTransferHistoryService { + s.archived = &archived + return s +} + +// Do send request +func (s *CrossMarginTransferHistoryService) Do(ctx context.Context, opts ...RequestOption) (res *CrossMarginTransferHistoryResponse, err error) { + r := &request{ + method: http.MethodGet, + endpoint: crossMarginTransferHistoryEndpoint, + secType: secTypeSigned, + } + if s.asset != nil { + r.setParam("asset", *s.asset) + } + if s.orderType != nil { + r.setParam("type", *s.orderType) + } + if s.startTime != nil { + r.setParam("startTime", *s.startTime) + } + if s.endTime != nil { + r.setParam("endTime", *s.endTime) + } + if s.current != nil { + r.setParam("current", *s.current) + } + if s.size != nil { + r.setParam("size", *s.size) + } + if s.archived != nil { + r.setParam("archived", *s.archived) + } + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return &CrossMarginTransferHistoryResponse{}, err + } + res = new(CrossMarginTransferHistoryResponse) + err = json.Unmarshal(data, res) + if err != nil { + return &CrossMarginTransferHistoryResponse{}, err + } + return res, nil +} + +// CrossMarginTransferHistoryResponse define cross margin transfer history response +type CrossMarginTransferHistoryResponse struct { + Rows []struct { + Amount string `json:"amount"` + Asset string `json:"asset"` + Status string `json:"status"` + Timestamp uint64 `json:"timestamp"` + TxId int64 `json:"txId"` + Type string `json:"type"` + } `json:"rows"` + Total int `json:"total"` +} + +// Query Loan Record (USER_DATA) API Endpoint +const ( + loanRecordEndpoint = "/sapi/v1/margin/loan" +) + +// LoanRecordService query loan record +type LoanRecordService struct { + c *Client + asset string + isolatedSymbol *string + txid *int64 + startTime *uint64 + endTime *uint64 + current *int + size *int + archived *string +} + +// Asset set asset +func (s *LoanRecordService) Asset(asset string) *LoanRecordService { + s.asset = asset + return s +} + +// IsolatedSymbol set isolatedSymbol +func (s *LoanRecordService) IsolatedSymbol(isolatedSymbol string) *LoanRecordService { + s.isolatedSymbol = &isolatedSymbol + return s +} + +// TxId set txid +func (s *LoanRecordService) TxId(txid int64) *LoanRecordService { + s.txid = &txid + return s +} + +// StartTime set startTime +func (s *LoanRecordService) StartTime(startTime uint64) *LoanRecordService { + s.startTime = &startTime + return s +} + +// EndTime set endTime +func (s *LoanRecordService) EndTime(endTime uint64) *LoanRecordService { + s.endTime = &endTime + return s +} + +// Current set current +func (s *LoanRecordService) Current(current int) *LoanRecordService { + s.current = ¤t + return s +} + +// Size set size +func (s *LoanRecordService) Size(size int) *LoanRecordService { + s.size = &size + return s +} + +// Archived set archived +func (s *LoanRecordService) Archived(archived string) *LoanRecordService { + s.archived = &archived + return s +} + +// Do send request +func (s *LoanRecordService) Do(ctx context.Context, opts ...RequestOption) (res *LoanRecordResponse, err error) { + r := &request{ + method: http.MethodGet, + endpoint: loanRecordEndpoint, + secType: secTypeSigned, + } + m := params{ + "asset": s.asset, + } + if s.isolatedSymbol != nil { + m["isolatedSymbol"] = *s.isolatedSymbol + } + if s.txid != nil { + m["txId"] = *s.txid + } + if s.startTime != nil { + m["startTime"] = *s.startTime + } + if s.endTime != nil { + m["endTime"] = *s.endTime + } + if s.current != nil { + m["current"] = *s.current + } + if s.size != nil { + m["size"] = *s.size + } + if s.archived != nil { + m["archived"] = *s.archived + } + r.setParams(m) + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return &LoanRecordResponse{}, err + } + res = new(LoanRecordResponse) + err = json.Unmarshal(data, res) + if err != nil { + return &LoanRecordResponse{}, err + } + return res, nil +} + +// LoanRecordResponse define loan record response +type LoanRecordResponse struct { + Rows []struct { + IsolatedSymbol string `json:"isolatedSymbol"` + TxId int64 `json:"txId"` + Asset string `json:"asset"` + Principal string `json:"principal"` + Timestamp uint64 `json:"timestamp"` + Status string `json:"status"` + } `json:"rows"` + Total int `json:"total"` +} + +// Query Repay Record (USER_DATA) API Endpoint +const ( + repayRecordEndpoint = "/sapi/v1/margin/repay" +) + +// RepayRecordService query repay record +type RepayRecordService struct { + c *Client + asset string + isolatedSymbol *string + txid *int64 + startTime *uint64 + endTime *uint64 + current *int + size *int + archived *string +} + +// Asset set asset +func (s *RepayRecordService) Asset(asset string) *RepayRecordService { + s.asset = asset + return s +} + +// IsolatedSymbol set isolatedSymbol +func (s *RepayRecordService) IsolatedSymbol(isolatedSymbol string) *RepayRecordService { + s.isolatedSymbol = &isolatedSymbol + return s +} + +// TxId set txid +func (s *RepayRecordService) TxId(txid int64) *RepayRecordService { + s.txid = &txid + return s +} + +// StartTime set startTime +func (s *RepayRecordService) StartTime(startTime uint64) *RepayRecordService { + s.startTime = &startTime + return s +} + +// EndTime set endTime +func (s *RepayRecordService) EndTime(endTime uint64) *RepayRecordService { + s.endTime = &endTime + return s +} + +// Current set current +func (s *RepayRecordService) Current(current int) *RepayRecordService { + s.current = ¤t + return s +} + +// Size set size +func (s *RepayRecordService) Size(size int) *RepayRecordService { + s.size = &size + return s +} + +// Archived set archived +func (s *RepayRecordService) Archived(archived string) *RepayRecordService { + s.archived = &archived + return s +} + +// Do send request +func (s *RepayRecordService) Do(ctx context.Context, opts ...RequestOption) (res *RepayRecordResponse, err error) { + r := &request{ + method: http.MethodGet, + endpoint: repayRecordEndpoint, + secType: secTypeSigned, + } + m := params{ + "asset": s.asset, + } + if s.isolatedSymbol != nil { + m["isolatedSymbol"] = *s.isolatedSymbol + } + if s.txid != nil { + m["txId"] = *s.txid + } + if s.startTime != nil { + m["startTime"] = *s.startTime + } + if s.endTime != nil { + m["endTime"] = *s.endTime + } + if s.current != nil { + m["current"] = *s.current + } + if s.size != nil { + m["size"] = *s.size + } + if s.archived != nil { + m["archived"] = *s.archived + } + r.setParams(m) + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return &RepayRecordResponse{}, err + } + res = new(RepayRecordResponse) + err = json.Unmarshal(data, res) + if err != nil { + return &RepayRecordResponse{}, err + } + return res, nil +} + +// RepayRecordResponse define repay record response +type RepayRecordResponse struct { + Rows []struct { + IsolatedSymbol string `json:"isolatedSymbol"` + Amount string `json:"amount"` + Asset string `json:"asset"` + Interest string `json:"interest"` + Principal string `json:"principal"` + Status string `json:"status"` + Timestamp uint64 `json:"timestamp"` + TxId int64 `json:"txId"` + } `json:"rows"` + Total int `json:"total"` +} + +// Query Interest History (USER_DATA) API Endpoint +const ( + interestHistoryEndpoint = "/sapi/v1/margin/interestHistory" +) + +// InterestHistoryService query interest history +type InterestHistoryService struct { + c *Client + asset *string + isolatedSymbol *string + startTime *uint64 + endTime *uint64 + current *int + size *int + archived *string +} + +// Asset set asset +func (s *InterestHistoryService) Asset(asset string) *InterestHistoryService { + s.asset = &asset + return s +} + +// IsolatedSymbol set isolatedSymbol +func (s *InterestHistoryService) IsolatedSymbol(isolatedSymbol string) *InterestHistoryService { + s.isolatedSymbol = &isolatedSymbol + return s +} + +// StartTime set startTime +func (s *InterestHistoryService) StartTime(startTime uint64) *InterestHistoryService { + s.startTime = &startTime + return s +} + +// EndTime set endTime +func (s *InterestHistoryService) EndTime(endTime uint64) *InterestHistoryService { + s.endTime = &endTime + return s +} + +// Current set current +func (s *InterestHistoryService) Current(current int) *InterestHistoryService { + s.current = ¤t + return s +} + +// Size set size +func (s *InterestHistoryService) Size(size int) *InterestHistoryService { + s.size = &size + return s +} + +// Archived set archived +func (s *InterestHistoryService) Archived(archived string) *InterestHistoryService { + s.archived = &archived + return s +} + +// Do send request +func (s *InterestHistoryService) Do(ctx context.Context, opts ...RequestOption) (res *InterestHistoryResponse, err error) { + r := &request{ + method: http.MethodGet, + endpoint: interestHistoryEndpoint, + secType: secTypeSigned, + } + if s.asset != nil { + r.setParam("asset", *s.asset) + } + if s.isolatedSymbol != nil { + r.setParam("isolatedSymbol", *s.isolatedSymbol) + } + if s.startTime != nil { + r.setParam("startTime", *s.startTime) + } + if s.endTime != nil { + r.setParam("endTime", *s.endTime) + } + if s.current != nil { + r.setParam("current", *s.current) + } + if s.size != nil { + r.setParam("size", *s.size) + } + if s.archived != nil { + r.setParam("archived", *s.archived) + } + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return &InterestHistoryResponse{}, err + } + res = new(InterestHistoryResponse) + err = json.Unmarshal(data, res) + if err != nil { + return &InterestHistoryResponse{}, err + } + return res, nil +} + +// InterestHistoryResponse define interest history response +type InterestHistoryResponse struct { + Rows []struct { + TxId int64 `json:"txId"` + InterestAccruedTime uint64 `json:"interestAccruedTime"` + Asset string `json:"asset"` + RawAsset string `json:"rawAsset"` + Principal string `json:"principal"` + Interest string `json:"interest"` + InterestRate string `json:"interestRate"` + Type string `json:"type"` + IsolatedSymbol string `json:"isolatedSymbol"` + } `json:"rows"` + Total int `json:"total"` +} + +// Query Force Liquidation Record (USER_DATA) API Endpoint +const ( + forceLiquidationRecordEndpoint = "/sapi/v1/margin/forceLiquidationRec" +) + +// ForceLiquidationRecordService query force liquidation record +type ForceLiquidationRecordService struct { + c *Client + startTime *uint64 + endTime *uint64 + isolatedSymbol *string + current *int + size *int +} + +// IsolatedSymbol set isolatedSymbol +func (s *ForceLiquidationRecordService) IsolatedSymbol(isolatedSymbol string) *ForceLiquidationRecordService { + s.isolatedSymbol = &isolatedSymbol + return s +} + +// StartTime set startTime +func (s *ForceLiquidationRecordService) StartTime(startTime uint64) *ForceLiquidationRecordService { + s.startTime = &startTime + return s +} + +// EndTime set endTime +func (s *ForceLiquidationRecordService) EndTime(endTime uint64) *ForceLiquidationRecordService { + s.endTime = &endTime + return s +} + +// Current set current +func (s *ForceLiquidationRecordService) Current(current int) *ForceLiquidationRecordService { + s.current = ¤t + return s +} + +// Size set size +func (s *ForceLiquidationRecordService) Size(size int) *ForceLiquidationRecordService { + s.size = &size + return s +} + +// Do send request +func (s *ForceLiquidationRecordService) Do(ctx context.Context, opts ...RequestOption) (res *ForceLiquidationRecordResponse, err error) { + r := &request{ + method: http.MethodGet, + endpoint: forceLiquidationRecordEndpoint, + secType: secTypeSigned, + } + if s.startTime != nil { + r.setParam("startTime", *s.startTime) + } + if s.endTime != nil { + r.setParam("endTime", *s.endTime) + } + if s.isolatedSymbol != nil { + r.setParam("isolatedSymbol", *s.isolatedSymbol) + } + if s.current != nil { + r.setParam("current", *s.current) + } + if s.size != nil { + r.setParam("size", *s.size) + } + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return &ForceLiquidationRecordResponse{}, err + } + res = new(ForceLiquidationRecordResponse) + err = json.Unmarshal(data, res) + if err != nil { + return &ForceLiquidationRecordResponse{}, err + } + return res, nil +} + +// ForceLiquidationRecordResponse define force liquidation record response +type ForceLiquidationRecordResponse struct { + Rows []struct { + AvgPrice string `json:"avgPrice"` + ExecutedQty string `json:"executedQty"` + OrderId int `json:"orderId"` + Price string `json:"price"` + Qty string `json:"qty"` + Side string `json:"side"` + Symbol string `json:"symbol"` + TimeInForce string `json:"timeInForce"` + IsIsolated bool `json:"isIsolated"` + UpdatedTime uint64 `json:"updatedTime"` + } `json:"rows"` + Total int `json:"total"` +} + +// Query Query Cross Margin Account Details (USER_DATA) API Endpoint +const ( + crossMarginAccountDetailEndpoint = "/sapi/v1/margin/account" +) + +// CrossMarginAccountDetailService query cross margin account details +type CrossMarginAccountDetailService struct { + c *Client +} + +// Do send request +func (s *CrossMarginAccountDetailService) Do(ctx context.Context, opts ...RequestOption) (res *CrossMarginAccountDetailResponse, err error) { + r := &request{ + method: http.MethodGet, + endpoint: crossMarginAccountDetailEndpoint, + secType: secTypeSigned, + } + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return &CrossMarginAccountDetailResponse{}, err + } + res = new(CrossMarginAccountDetailResponse) + err = json.Unmarshal(data, res) + if err != nil { + return &CrossMarginAccountDetailResponse{}, err + } + return res, nil +} + +// CrossMarginAccountDetailResponse define cross margin account detail response +type CrossMarginAccountDetailResponse struct { + BorrowEnabled bool `json:"borrowEnabled"` + MarginLevel string `json:"marginLevel"` + TotalAssetOfBtc string `json:"totalAssetOfBtc"` + TotalLiabilityOfBtc string `json:"totalLiabilityOfBtc"` + TotalNetAssetOfBtc string `json:"totalNetAssetOfBtc"` + TradeEnabled bool `json:"tradeEnabled"` + TransferEnabled bool `json:"transferEnabled"` + UserAssets []struct { + Asset string `json:"asset"` + Borrowed string `json:"borrowed"` + Free string `json:"free"` + Interest string `json:"interest"` + Locked string `json:"locked"` + NetAsset string `json:"netAsset"` + } `json:"userAssets"` +} + +// Query Margin Account's Order (USER_DATA) API Endpoint +const ( + marginAccountOrderEndpoint = "/sapi/v1/margin/order" +) + +// MarginAccountOrderService query margin account's order +type MarginAccountOrderService struct { + c *Client + symbol string + isIsolated *string + orderId *int + origClientOrderId *string +} + +// Symbol set symbol +func (s *MarginAccountOrderService) Symbol(symbol string) *MarginAccountOrderService { + s.symbol = symbol + return s +} + +// IsIsolated set isIsolated +func (s *MarginAccountOrderService) IsIsolated(isIsolated string) *MarginAccountOrderService { + s.isIsolated = &isIsolated + return s +} + +// OrderId set orderId +func (s *MarginAccountOrderService) OrderId(orderId int) *MarginAccountOrderService { + s.orderId = &orderId + return s +} + +// OrigClientOrderId set origClientOrderId +func (s *MarginAccountOrderService) OrigClientOrderId(origClientOrderId string) *MarginAccountOrderService { + s.origClientOrderId = &origClientOrderId + return s +} + +// Do send request +func (s *MarginAccountOrderService) Do(ctx context.Context, opts ...RequestOption) (res *MarginAccountOrderResponse, err error) { + r := &request{ + method: http.MethodGet, + endpoint: marginAccountOrderEndpoint, + secType: secTypeSigned, + } + m := params{ + "symbol": s.symbol, + } + if s.isIsolated != nil { + m["isIsolated"] = *s.isIsolated + } + if s.orderId != nil { + m["orderId"] = *s.orderId + } + if s.origClientOrderId != nil { + m["origClientOrderId"] = *s.origClientOrderId + } + r.setParams(m) + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return &MarginAccountOrderResponse{}, err + } + res = new(MarginAccountOrderResponse) + err = json.Unmarshal(data, res) + if err != nil { + return &MarginAccountOrderResponse{}, err + } + return res, nil +} + +// MarginAccountOrderResponse define margin account order response +type MarginAccountOrderResponse struct { + ClientOrderId string `json:"clientOrderId"` + CumulativeQuoteQty string `json:"cumulativeQuoteQty"` + ExecutedQty string `json:"executedQty"` + IcebergQty string `json:"icebergQty"` + IsWorking bool `json:"isWorking"` + OrderId int `json:"orderId"` + OrigQty string `json:"origQty"` + Price string `json:"price"` + Side string `json:"side"` + Status string `json:"status"` + StopPrice string `json:"stopPrice"` + Symbol string `json:"symbol"` + IsIsolated bool `json:"isIsolated"` + Time uint64 `json:"time"` + TimeInForce string `json:"timeInForce"` + OrderType string `json:"type"` + UpdateTime uint64 `json:"updateTime"` +} + +// Query Margin Account's Open Order (USER_DATA) API Endpoint +const ( + marginAccountOpenOrderEndpoint = "/sapi/v1/margin/openOrders" +) + +// MarginAccountOpenOrderService query margin account's open order +type MarginAccountOpenOrderService struct { + c *Client + symbol *string + isIsolated *string +} + +// Symbol set symbol +func (s *MarginAccountOpenOrderService) Symbol(symbol string) *MarginAccountOpenOrderService { + s.symbol = &symbol + return s +} + +// IsIsolated set isIsolated +func (s *MarginAccountOpenOrderService) IsIsolated(isIsolated string) *MarginAccountOpenOrderService { + s.isIsolated = &isIsolated + return s +} + +// Do send request +func (s *MarginAccountOpenOrderService) Do(ctx context.Context, opts ...RequestOption) (res *MarginAccountOpenOrderResponse, err error) { + r := &request{ + method: http.MethodGet, + endpoint: marginAccountOpenOrderEndpoint, + secType: secTypeSigned, + } + if s.symbol != nil { + r.setParam("symbol", *s.symbol) + } + if s.isIsolated != nil { + r.setParam("isIsolated", *s.isIsolated) + } + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return &MarginAccountOpenOrderResponse{}, err + } + res = new(MarginAccountOpenOrderResponse) + err = json.Unmarshal(data, res) + if err != nil { + return &MarginAccountOpenOrderResponse{}, err + } + return res, nil +} + +// MarginAccountOpenOrderResponse define margin account open order response +type MarginAccountOpenOrderResponse struct { + Orders []struct { + ClientOrderId string `json:"clientOrderId"` + CumulativeQuoteQty string `json:"cumulativeQuoteQty"` + ExecutedQty string `json:"executedQty"` + IcebergQty string `json:"icebergQty"` + IsWorking bool `json:"isWorking"` + OrderId int `json:"orderId"` + OrigQty string `json:"origQty"` + Price string `json:"price"` + Side string `json:"side"` + Status string `json:"status"` + StopPrice string `json:"stopPrice"` + Symbol string `json:"symbol"` + IsIsolated bool `json:"isIsolated"` + Time uint64 `json:"time"` + TimeInForce string `json:"timeInForce"` + OrderType string `json:"type"` + UpdateTime uint64 `json:"updateTime"` + } `json:"orders"` +} + +// Query Margin Account's All Orders (USER_DATA) API Endpoint +const ( + marginAccountAllOrderEndpoint = "/sapi/v1/margin/allOrders" +) + +// MarginAccountAllOrderService query margin account's all order +type MarginAccountAllOrderService struct { + c *Client + symbol string + isIsolated *string + orderId *int + startTime *uint64 + endTime *uint64 + limit *int +} + +// Symbol set symbol +func (s *MarginAccountAllOrderService) Symbol(symbol string) *MarginAccountAllOrderService { + s.symbol = symbol + return s +} + +// IsIsolated set isIsolated +func (s *MarginAccountAllOrderService) IsIsolated(isIsolated string) *MarginAccountAllOrderService { + s.isIsolated = &isIsolated + return s +} + +// OrderId set orderId +func (s *MarginAccountAllOrderService) OrderId(orderId int) *MarginAccountAllOrderService { + s.orderId = &orderId + return s +} + +// StartTime set startTime +func (s *MarginAccountAllOrderService) StartTime(startTime uint64) *MarginAccountAllOrderService { + s.startTime = &startTime + return s +} + +// EndTime set endTime +func (s *MarginAccountAllOrderService) EndTime(endTime uint64) *MarginAccountAllOrderService { + s.endTime = &endTime + return s +} + +// Limit set limit +func (s *MarginAccountAllOrderService) Limit(limit int) *MarginAccountAllOrderService { + s.limit = &limit + return s +} + +// Do send request +func (s *MarginAccountAllOrderService) Do(ctx context.Context, opts ...RequestOption) (res *MarginAccountAllOrderResponse, err error) { + r := &request{ + method: http.MethodGet, + endpoint: marginAccountAllOrderEndpoint, + secType: secTypeSigned, + } + m := params{ + "symbol": s.symbol, + } + if s.isIsolated != nil { + m["isIsolated"] = *s.isIsolated + } + if s.orderId != nil { + m["orderId"] = *s.orderId + } + if s.startTime != nil { + m["startTime"] = *s.startTime + } + if s.endTime != nil { + m["endTime"] = *s.endTime + } + if s.limit != nil { + m["limit"] = *s.limit + } + r.setParams(m) + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return &MarginAccountAllOrderResponse{}, err + } + res = new(MarginAccountAllOrderResponse) + err = json.Unmarshal(data, res) + if err != nil { + return &MarginAccountAllOrderResponse{}, err + } + return res, nil +} + +// MarginAccountAllOrderResponse define margin account all order response +type MarginAccountAllOrderResponse struct { + Orders []struct { + ClientOrderId string `json:"clientOrderId"` + CumulativeQuoteQty string `json:"cumulativeQuoteQty"` + ExecutedQty string `json:"executedQty"` + IcebergQty string `json:"icebergQty"` + IsWorking bool `json:"isWorking"` + OrderId int `json:"orderId"` + OrigQty string `json:"origQty"` + Price string `json:"price"` + Side string `json:"side"` + Status string `json:"status"` + StopPrice string `json:"stopPrice"` + Symbol string `json:"symbol"` + IsIsolated bool `json:"isIsolated"` + Time uint64 `json:"time"` + TimeInForce string `json:"timeInForce"` + OrderType string `json:"type"` + UpdateTime uint64 `json:"updateTime"` + } `json:"orders"` +} + +// Margin Account New OCO (TRADE) API Endpoint +const ( + marginAccountNewOCOEndpoint = "/sapi/v1/margin/order/oco" +) + +// MarginAccountNewOCOService create new oco order +type MarginAccountNewOCOService struct { + c *Client + symbol string + isIsolated *string + listClientOrderId *string + side string + quantity float64 + limitClientOrderId *string + price float64 + limitIcebergQty *float64 + stopClientOrderId *string + stopPrice float64 + stopLimitPrice *float64 + stopIcebergQty *float64 + stopLimitTimeInForce *string + newOrderRespType *string + sideEffectType *string +} + +// Symbol set symbol +func (s *MarginAccountNewOCOService) Symbol(symbol string) *MarginAccountNewOCOService { + s.symbol = symbol + return s +} + +// IsIsolated set isIsolated +func (s *MarginAccountNewOCOService) IsIsolated(isIsolated string) *MarginAccountNewOCOService { + s.isIsolated = &isIsolated + return s +} + +// ListClientOrderId set listClientOrderId +func (s *MarginAccountNewOCOService) ListClientOrderId(listClientOrderId string) *MarginAccountNewOCOService { + s.listClientOrderId = &listClientOrderId + return s +} + +// Side set side +func (s *MarginAccountNewOCOService) Side(side string) *MarginAccountNewOCOService { + s.side = side + return s +} + +// Quantity set quantity +func (s *MarginAccountNewOCOService) Quantity(quantity float64) *MarginAccountNewOCOService { + s.quantity = quantity + return s +} + +// LimitClientOrderId set limitClientOrderId +func (s *MarginAccountNewOCOService) LimitClientOrderId(limitClientOrderId string) *MarginAccountNewOCOService { + s.limitClientOrderId = &limitClientOrderId + return s +} + +// Price set price +func (s *MarginAccountNewOCOService) Price(price float64) *MarginAccountNewOCOService { + s.price = price + return s +} + +// LimitIcebergQty set limitIcebergQty +func (s *MarginAccountNewOCOService) LimitIcebergQty(limitIcebergQty float64) *MarginAccountNewOCOService { + s.limitIcebergQty = &limitIcebergQty + return s +} + +// StopClientOrderId set stopClientOrderId +func (s *MarginAccountNewOCOService) StopClientOrderId(stopClientOrderId string) *MarginAccountNewOCOService { + s.stopClientOrderId = &stopClientOrderId + return s +} + +// StopPrice set stopPrice +func (s *MarginAccountNewOCOService) StopPrice(stopPrice float64) *MarginAccountNewOCOService { + s.stopPrice = stopPrice + return s +} + +// StopLimitPrice set stopLimitPrice +func (s *MarginAccountNewOCOService) StopLimitPrice(stopLimitPrice float64) *MarginAccountNewOCOService { + s.stopLimitPrice = &stopLimitPrice + return s +} + +// StopIcebergQty set stopIcebergQty +func (s *MarginAccountNewOCOService) StopIcebergQty(stopIcebergQty float64) *MarginAccountNewOCOService { + s.stopIcebergQty = &stopIcebergQty + return s +} + +// StopLimitTimeInForce set stopLimitTimeInForce +func (s *MarginAccountNewOCOService) StopLimitTimeInForce(stopLimitTimeInForce string) *MarginAccountNewOCOService { + s.stopLimitTimeInForce = &stopLimitTimeInForce + return s +} + +// NewOrderRespType set newOrderRespType +func (s *MarginAccountNewOCOService) NewOrderRespType(newOrderRespType string) *MarginAccountNewOCOService { + s.newOrderRespType = &newOrderRespType + return s +} + +// SideEffectType set sideEffectType +func (s *MarginAccountNewOCOService) SideEffectType(sideEffectType string) *MarginAccountNewOCOService { + s.sideEffectType = &sideEffectType + return s +} + +// Do send request +func (s *MarginAccountNewOCOService) Do(ctx context.Context, opts ...RequestOption) (res *MarginAccountNewOCOResponse, err error) { + r := &request{ + method: http.MethodPost, + endpoint: marginAccountNewOCOEndpoint, + secType: secTypeSigned, + } + m := params{ + "symbol": s.symbol, + "side": s.side, + "quantity": s.quantity, + "price": s.price, + "stopPrice": s.stopPrice, + } + if s.isIsolated != nil { + m["isIsolated"] = *s.isIsolated + } + if s.listClientOrderId != nil { + m["listClientOrderId"] = *s.listClientOrderId + } + if s.limitClientOrderId != nil { + m["limitClientOrderId"] = *s.limitClientOrderId + } + if s.limitIcebergQty != nil { + m["limitIcebergQty"] = *s.limitIcebergQty + } + if s.stopClientOrderId != nil { + m["stopClientOrderId"] = *s.stopClientOrderId + } + if s.stopLimitPrice != nil { + m["stopLimitPrice"] = *s.stopLimitPrice + } + if s.stopIcebergQty != nil { + m["stopIcebergQty"] = *s.stopIcebergQty + } + if s.stopLimitTimeInForce != nil { + m["stopLimitTimeInForce"] = *s.stopLimitTimeInForce + } + if s.newOrderRespType != nil { + m["newOrderRespType"] = *s.newOrderRespType + } + if s.sideEffectType != nil { + m["sideEffectType"] = *s.sideEffectType + } + r.setParams(m) + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return &MarginAccountNewOCOResponse{}, err + } + res = new(MarginAccountNewOCOResponse) + err = json.Unmarshal(data, res) + if err != nil { + return &MarginAccountNewOCOResponse{}, err + } + return res, nil +} + +// MarginAccountNewOCOService response +type MarginAccountNewOCOResponse struct { + OrderListId int `json:"orderListId"` + ContingencyType string `json:"contingencyType"` + ListStatusType string `json:"listStatusType"` + ListOrderStatus string `json:"listOrderStatus"` + ListClientOrderId string `json:"listClientOrderId"` + TransactionTime uint64 `json:"transactionTime"` + Symbol string `json:"symbol"` + MarginBuyBorrowAmount string `json:"marginBuyBorrowAmount"` + MarginBuyBorrowAsset string `json:"marginBuyBorrowAsset"` + Orders []struct { + Symbol string `json:"symbol"` + OrderId int `json:"orderId"` + ClientOrderId string `json:"clientOrderId"` + } `json:"orders"` + OrderReports []struct { + Symbol string `json:"symbol"` + OrderId int `json:"orderId"` + OrderListId int `json:"orderListId"` + ClientOrderId string `json:"clientOrderId"` + TransactTime uint64 `json:"transactTime"` + Price string `json:"price"` + OrigQty string `json:"origQty"` + ExecutedQty string `json:"executedQty"` + CumulativeQuoteQty string `json:"cumulativeQuoteQty"` + Status string `json:"status"` + TimeInForce string `json:"timeInForce"` + OrderType string `json:"type"` + Side string `json:"side"` + StopPrice string `json:"stopPrice"` + } `json:"orderReports"` +} + +// Margin Account Cancel OCO (TRADE) +const ( + marginAccountCancelOCOEndpoint = "/sapi/v1/margin/orderList" +) + +type MarginAccountCancelOCOService struct { + c *Client + symbol string + isIsolated *string + orderListId *int + listClientOrderId *string + newClientOrderId *string +} + +// Symbol set symbol +func (s *MarginAccountCancelOCOService) Symbol(symbol string) *MarginAccountCancelOCOService { + s.symbol = symbol + return s +} + +// IsIsolated set isIsolated +func (s *MarginAccountCancelOCOService) IsIsolated(isIsolated string) *MarginAccountCancelOCOService { + s.isIsolated = &isIsolated + return s +} + +// OrderListId set orderListId +func (s *MarginAccountCancelOCOService) OrderListId(orderListId int) *MarginAccountCancelOCOService { + s.orderListId = &orderListId + return s +} + +// ListClientOrderId set listClientOrderId +func (s *MarginAccountCancelOCOService) ListClientOrderId(listClientOrderId string) *MarginAccountCancelOCOService { + s.listClientOrderId = &listClientOrderId + return s +} + +// NewClientOrderId set newClientOrderId +func (s *MarginAccountCancelOCOService) NewClientOrderId(newClientOrderId string) *MarginAccountCancelOCOService { + s.newClientOrderId = &newClientOrderId + return s +} + +// Do send request +func (s *MarginAccountCancelOCOService) Do(ctx context.Context, opts ...RequestOption) (res *MarginAccountCancelOCOResponse, err error) { + r := &request{ + method: http.MethodDelete, + endpoint: marginAccountCancelOCOEndpoint, + secType: secTypeSigned, + } + m := params{ + "symbol": s.symbol, + } + if s.isIsolated != nil { + m["isIsolated"] = *s.isIsolated + } + if s.orderListId != nil { + m["orderListId"] = *s.orderListId + } + if s.listClientOrderId != nil { + m["listClientOrderId"] = *s.listClientOrderId + } + if s.newClientOrderId != nil { + m["newClientOrderId"] = *s.newClientOrderId + } + r.setParams(m) + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return &MarginAccountCancelOCOResponse{}, err + } + res = new(MarginAccountCancelOCOResponse) + err = json.Unmarshal(data, res) + if err != nil { + return &MarginAccountCancelOCOResponse{}, err + } + return res, nil +} + +// MarginAccountCancelOCOService response +type MarginAccountCancelOCOResponse struct { + OrderListId int `json:"orderListId"` + ContingencyType string `json:"contingencyType"` + ListStatusType string `json:"listStatusType"` + ListOrderStatus string `json:"listOrderStatus"` + ListClientOrderId string `json:"listClientOrderId"` + TransactionTime uint64 `json:"transactionTime"` + Symbol string `json:"symbol"` + IsIsolated bool `json:"isIsolated"` + Orders []struct { + Symbol string `json:"symbol"` + OrderId int `json:"orderId"` + ClientOrderId string `json:"clientOrderId"` + } `json:"orders"` + OrderReports []struct { + Symbol string `json:"symbol"` + OrigClientOrderId string `json:"origClientOrderId"` + OrderId int `json:"orderId"` + OrderListId int `json:"orderListId"` + ClientOrderId string `json:"clientOrderId"` + Price string `json:"price"` + OrigQty string `json:"origQty"` + ExecutedQty string `json:"executedQty"` + CumulativeQuoteQty string `json:"cumulativeQuoteQty"` + Status string `json:"status"` + TimeInForce string `json:"timeInForce"` + OrderType string `json:"type"` + Side string `json:"side"` + StopPrice string `json:"stopPrice"` + } `json:"orderReports"` +} + +// Query Margin Account's OCO (USER_DATA) (HMAC SHA256) +const ( + marginAccountQueryOCOEndpoint = "/sapi/v1/margin/orderList" +) + +type MarginAccountQueryOCOService struct { + c *Client + isIsolated *string + symbol *string + orderListId *int + origClientOrderId *string +} + +// IsIsolated set isIsolated +func (s *MarginAccountQueryOCOService) IsIsolated(isIsolated string) *MarginAccountQueryOCOService { + s.isIsolated = &isIsolated + return s +} + +// Symbol set symbol +func (s *MarginAccountQueryOCOService) Symbol(symbol string) *MarginAccountQueryOCOService { + s.symbol = &symbol + return s +} + +// OrderListId set orderListId +func (s *MarginAccountQueryOCOService) OrderListId(orderListId int) *MarginAccountQueryOCOService { + s.orderListId = &orderListId + return s +} + +// OrigClientOrderId set origClientOrderId +func (s *MarginAccountQueryOCOService) OrigClientOrderId(origClientOrderId string) *MarginAccountQueryOCOService { + s.origClientOrderId = &origClientOrderId + return s +} + +// Do send request +func (s *MarginAccountQueryOCOService) Do(ctx context.Context, opts ...RequestOption) (res *MarginAccountQueryOCOResponse, err error) { + r := &request{ + method: http.MethodGet, + endpoint: marginAccountQueryOCOEndpoint, + secType: secTypeSigned, + } + if s.isIsolated != nil { + r.setParam("isIsolated", *s.isIsolated) + } + if s.symbol != nil { + r.setParam("symbol", *s.symbol) + } + if s.orderListId != nil { + r.setParam("orderListId", *s.orderListId) + } + if s.origClientOrderId != nil { + r.setParam("origClientOrderId", *s.origClientOrderId) + } + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return &MarginAccountQueryOCOResponse{}, err + } + res = new(MarginAccountQueryOCOResponse) + err = json.Unmarshal(data, res) + if err != nil { + return &MarginAccountQueryOCOResponse{}, err + } + return res, nil +} + +// MarginAccountQueryOCOService response +type MarginAccountQueryOCOResponse struct { + OrderListId int `json:"orderListId"` + ContingencyType string `json:"contingencyType"` + ListStatusType string `json:"listStatusType"` + ListOrderStatus string `json:"listOrderStatus"` + ListClientOrderId string `json:"listClientOrderId"` + TransactionTime uint64 `json:"transactionTime"` + Symbol string `json:"symbol"` + IsIsolated bool `json:"isIsolated"` + Orders []struct { + Symbol string `json:"symbol"` + OrderId int `json:"orderId"` + ClientOrderId string `json:"clientOrderId"` + } `json:"orders"` +} + +// Query Margin Account's all OCO (USER_DATA) +const ( + marginAccountQueryAllOCOEndpoint = "/sapi/v1/margin/allOrderList" +) + +type MarginAccountQueryAllOCOService struct { + c *Client + isIsolated *string + symbol *string + fromId *int + startTime *uint64 + endTime *uint64 + limit *int +} + +// IsIsolated set isIsolated +func (s *MarginAccountQueryAllOCOService) IsIsolated(isIsolated string) *MarginAccountQueryAllOCOService { + s.isIsolated = &isIsolated + return s +} + +// Symbol set symbol +func (s *MarginAccountQueryAllOCOService) Symbol(symbol string) *MarginAccountQueryAllOCOService { + s.symbol = &symbol + return s +} + +// FromId set fromId +func (s *MarginAccountQueryAllOCOService) FromId(fromId int) *MarginAccountQueryAllOCOService { + s.fromId = &fromId + return s +} + +// StartTime set startTime +func (s *MarginAccountQueryAllOCOService) StartTime(startTime uint64) *MarginAccountQueryAllOCOService { + s.startTime = &startTime + return s +} + +// EndTime set endTime +func (s *MarginAccountQueryAllOCOService) EndTime(endTime uint64) *MarginAccountQueryAllOCOService { + s.endTime = &endTime + return s +} + +// Limit set limit +func (s *MarginAccountQueryAllOCOService) Limit(limit int) *MarginAccountQueryAllOCOService { + s.limit = &limit + return s +} + +// Do send request +func (s *MarginAccountQueryAllOCOService) Do(ctx context.Context, opts ...RequestOption) (res *MarginAccountQueryAllOCOResponse, err error) { + r := &request{ + method: http.MethodGet, + endpoint: marginAccountQueryAllOCOEndpoint, + secType: secTypeSigned, + } + if s.isIsolated != nil { + r.setParam("isIsolated", *s.isIsolated) + } + if s.symbol != nil { + r.setParam("symbol", *s.symbol) + } + if s.fromId != nil { + r.setParam("fromId", *s.fromId) + } + if s.startTime != nil { + r.setParam("startTime", *s.startTime) + } + if s.endTime != nil { + r.setParam("endTime", *s.endTime) + } + if s.limit != nil { + r.setParam("limit", *s.limit) + } + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return &MarginAccountQueryAllOCOResponse{}, err + } + res = new(MarginAccountQueryAllOCOResponse) + err = json.Unmarshal(data, res) + if err != nil { + return &MarginAccountQueryAllOCOResponse{}, err + } + return res, nil +} + +// MarginAccountQueryAllOCOService response +type MarginAccountQueryAllOCOResponse struct { + OrderListId int `json:"orderListId"` + ContingencyType string `json:"contingencyType"` + ListStatusType string `json:"listStatusType"` + ListOrderStatus string `json:"listOrderStatus"` + ListClientOrderId string `json:"listClientOrderId"` + TransactionTime uint64 `json:"transactionTime"` + Symbol string `json:"symbol"` + IsIsolated bool `json:"isIsolated"` + Orders []struct { + Symbol string `json:"symbol"` + OrderId int `json:"orderId"` + ClientOrderId string `json:"clientOrderId"` + } `json:"orders"` +} + +// Query Margin Account's Open OCO (USER_DATA) +const ( + marginAccountQueryOpenOCOEndpoint = "/sapi/v1/margin/openOrderList" +) + +type MarginAccountQueryOpenOCOService struct { + c *Client + isIsolated *string + symbol *string +} + +// IsIsolated set isIsolated +func (s *MarginAccountQueryOpenOCOService) IsIsolated(isIsolated string) *MarginAccountQueryOpenOCOService { + s.isIsolated = &isIsolated + return s +} + +// Symbol set symbol +func (s *MarginAccountQueryOpenOCOService) Symbol(symbol string) *MarginAccountQueryOpenOCOService { + s.symbol = &symbol + return s +} + +// Do send request +func (s *MarginAccountQueryOpenOCOService) Do(ctx context.Context, opts ...RequestOption) (res *MarginAccountQueryOpenOCOResponse, err error) { + r := &request{ + method: http.MethodGet, + endpoint: marginAccountQueryOpenOCOEndpoint, + secType: secTypeSigned, + } + if s.isIsolated != nil { + r.setParam("isIsolated", *s.isIsolated) + } + if s.symbol != nil { + r.setParam("symbol", *s.symbol) + } + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return &MarginAccountQueryOpenOCOResponse{}, err + } + res = new(MarginAccountQueryOpenOCOResponse) + err = json.Unmarshal(data, res) + if err != nil { + return &MarginAccountQueryOpenOCOResponse{}, err + } + return res, nil +} + +// MarginAccountQueryOpenOCOService response +type MarginAccountQueryOpenOCOResponse struct { + OrderListId int `json:"orderListId"` + ContingencyType string `json:"contingencyType"` + ListStatusType string `json:"listStatusType"` + ListOrderStatus string `json:"listOrderStatus"` + ListClientOrderId string `json:"listClientOrderId"` + TransactionTime uint64 `json:"transactionTime"` + Symbol string `json:"symbol"` + IsIsolated bool `json:"isIsolated"` + Orders []struct { + Symbol string `json:"symbol"` + OrderId int `json:"orderId"` + ClientOrderId string `json:"clientOrderId"` + } `json:"orders"` +} + +// Query Margin Account's Trade List (USER_DATA) +const ( + marginAccountQueryTradeListEndpoint = "/sapi/v1/margin/myTrades" +) + +type MarginAccountQueryTradeListService struct { + c *Client + symbol string + isIsolated *string + orderId *int + startTime *uint64 + endTime *uint64 + fromId *int + limit *int +} + +// Symbol set symbol +func (s *MarginAccountQueryTradeListService) Symbol(symbol string) *MarginAccountQueryTradeListService { + s.symbol = symbol + return s +} + +// IsIsolated set isIsolated +func (s *MarginAccountQueryTradeListService) IsIsolated(isIsolated string) *MarginAccountQueryTradeListService { + s.isIsolated = &isIsolated + return s +} + +// OrderId set orderId +func (s *MarginAccountQueryTradeListService) OrderId(orderId int) *MarginAccountQueryTradeListService { + s.orderId = &orderId + return s +} + +// StartTime set startTime +func (s *MarginAccountQueryTradeListService) StartTime(startTime uint64) *MarginAccountQueryTradeListService { + s.startTime = &startTime + return s +} + +// EndTime set endTime +func (s *MarginAccountQueryTradeListService) EndTime(endTime uint64) *MarginAccountQueryTradeListService { + s.endTime = &endTime + return s +} + +// FromId set fromId +func (s *MarginAccountQueryTradeListService) FromId(fromId int) *MarginAccountQueryTradeListService { + s.fromId = &fromId + return s +} + +// Limit set limit +func (s *MarginAccountQueryTradeListService) Limit(limit int) *MarginAccountQueryTradeListService { + s.limit = &limit + return s +} + +// Do send request +func (s *MarginAccountQueryTradeListService) Do(ctx context.Context, opts ...RequestOption) (res *MarginAccountQueryTradeListResponse, err error) { + r := &request{ + method: http.MethodGet, + endpoint: marginAccountQueryTradeListEndpoint, + secType: secTypeSigned, + } + m := params{ + "symbol": s.symbol, + } + if s.isIsolated != nil { + m["isIsolated"] = *s.isIsolated + } + if s.orderId != nil { + m["orderId"] = *s.orderId + } + if s.startTime != nil { + m["startTime"] = *s.startTime + } + if s.endTime != nil { + m["endTime"] = *s.endTime + } + if s.fromId != nil { + m["fromId"] = *s.fromId + } + if s.limit != nil { + m["limit"] = *s.limit + } + r.setParams(m) + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return &MarginAccountQueryTradeListResponse{}, err + } + res = new(MarginAccountQueryTradeListResponse) + err = json.Unmarshal(data, res) + if err != nil { + return &MarginAccountQueryTradeListResponse{}, err + } + return res, nil +} + +// MarginAccountQueryTradeListService response +type MarginAccountQueryTradeListResponse struct { + Commission string `json:"commission"` + CommissionAsset string `json:"commissionAsset"` + Id int `json:"id"` + IsBestMatch bool `json:"isBestMatch"` + IsBuyer bool `json:"isBuyer"` + IsMaker bool `json:"isMaker"` + OrderId int `json:"orderId"` + Price string `json:"price"` + Qty string `json:"qty"` + Symbol string `json:"symbol"` + IsIsolated bool `json:"isIsolated"` + Time uint64 `json:"time"` +} + +// Query Margin Account's Max Borrow (USER_DATA) +const ( + marginAccountQueryMaxBorrowEndpoint = "/sapi/v1/margin/maxBorrowable" +) + +type MarginAccountQueryMaxBorrowService struct { + c *Client + asset string + isolatedSymbol *string +} + +// Asset set asset +func (s *MarginAccountQueryMaxBorrowService) Asset(asset string) *MarginAccountQueryMaxBorrowService { + s.asset = asset + return s +} + +// IsolatedSymbol set isolatedSymbol +func (s *MarginAccountQueryMaxBorrowService) IsolatedSymbol(isolatedSymbol string) *MarginAccountQueryMaxBorrowService { + s.isolatedSymbol = &isolatedSymbol + return s +} + +// Do send request +func (s *MarginAccountQueryMaxBorrowService) Do(ctx context.Context, opts ...RequestOption) (res *MarginAccountQueryMaxBorrowResponse, err error) { + r := &request{ + method: http.MethodGet, + endpoint: marginAccountQueryMaxBorrowEndpoint, + secType: secTypeSigned, + } + m := params{ + "asset": s.asset, + } + if s.isolatedSymbol != nil { + m["isolatedSymbol"] = *s.isolatedSymbol + } + r.setParams(m) + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return &MarginAccountQueryMaxBorrowResponse{}, err + } + res = new(MarginAccountQueryMaxBorrowResponse) + err = json.Unmarshal(data, res) + if err != nil { + return &MarginAccountQueryMaxBorrowResponse{}, err + } + return res, nil +} + +// MarginAccountQueryMaxBorrowService response +type MarginAccountQueryMaxBorrowResponse struct { + Amount string `json:"amount"` + BorrowLimit string `json:"borrowLimit"` +} + +// Query Margin Account's Max Transfer-Out Amount (USER_DATA) +const ( + marginAccountQueryMaxTransferOutAmountEndpoint = "/sapi/v1/margin/maxTransferable" +) + +type MarginAccountQueryMaxTransferOutAmountService struct { + c *Client + asset string + isolatedSymbol *string +} + +// Asset set asset +func (s *MarginAccountQueryMaxTransferOutAmountService) Asset(asset string) *MarginAccountQueryMaxTransferOutAmountService { + s.asset = asset + return s +} + +// IsolatedSymbol set isolatedSymbol +func (s *MarginAccountQueryMaxTransferOutAmountService) IsolatedSymbol(isolatedSymbol string) *MarginAccountQueryMaxTransferOutAmountService { + s.isolatedSymbol = &isolatedSymbol + return s +} + +// Do send request +func (s *MarginAccountQueryMaxTransferOutAmountService) Do(ctx context.Context, opts ...RequestOption) (res *MarginAccountQueryMaxTransferOutAmountResponse, err error) { + r := &request{ + method: http.MethodGet, + endpoint: marginAccountQueryMaxTransferOutAmountEndpoint, + secType: secTypeSigned, + } + m := params{ + "asset": s.asset, + } + if s.isolatedSymbol != nil { + m["isolatedSymbol"] = *s.isolatedSymbol + } + r.setParams(m) + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return &MarginAccountQueryMaxTransferOutAmountResponse{}, err + } + res = new(MarginAccountQueryMaxTransferOutAmountResponse) + err = json.Unmarshal(data, res) + if err != nil { + return &MarginAccountQueryMaxTransferOutAmountResponse{}, err + } + return res, nil +} + +// MarginAccountQueryMaxTransferOutAmountService response +type MarginAccountQueryMaxTransferOutAmountResponse struct { + Amount string `json:"amount"` +} + +// Get Summary of Margin account (USER_DATA) - GET /sapi/v1/margin/tradeCoeff (HMAC SHA256) +const ( + marginAccountSummaryEndpoint = "/sapi/v1/margin/tradeCoeff" +) + +type MarginAccountSummaryService struct { + c *Client +} + +// Do send request +func (s *MarginAccountSummaryService) Do(ctx context.Context, opts ...RequestOption) (res *MarginAccountSummaryResponse, err error) { + r := &request{ + method: http.MethodGet, + endpoint: marginAccountSummaryEndpoint, + secType: secTypeSigned, + } + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return &MarginAccountSummaryResponse{}, err + } + res = new(MarginAccountSummaryResponse) + err = json.Unmarshal(data, res) + if err != nil { + return &MarginAccountSummaryResponse{}, err + } + return res, nil +} + +// MarginAccountSummaryService response +type MarginAccountSummaryResponse struct { + NormalBar string `json:"normalBar"` + MarginCallBar string `json:"marginCallBar"` + ForceLiquidationBar string `json:"forceLiquidationBar"` +} + +// Isolated Margin Account Transfer (MARGIN) +const ( + marginIsolatedAccountTransferEndpoint = "/sapi/v1/margin/isolated/transfer" +) + +type MarginIsolatedAccountTransferService struct { + c *Client + asset string + symbol string + transFrom string + transTo string + amount float64 +} + +// Asset set asset +func (s *MarginIsolatedAccountTransferService) Asset(asset string) *MarginIsolatedAccountTransferService { + s.asset = asset + return s +} + +// Symbol set symbol +func (s *MarginIsolatedAccountTransferService) Symbol(symbol string) *MarginIsolatedAccountTransferService { + s.symbol = symbol + return s +} + +// TransFrom set transFrom +func (s *MarginIsolatedAccountTransferService) TransFrom(transFrom string) *MarginIsolatedAccountTransferService { + s.transFrom = transFrom + return s +} + +// TransTo set transTo +func (s *MarginIsolatedAccountTransferService) TransTo(transTo string) *MarginIsolatedAccountTransferService { + s.transTo = transTo + return s +} + +// Amount set amount +func (s *MarginIsolatedAccountTransferService) Amount(amount float64) *MarginIsolatedAccountTransferService { + s.amount = amount + return s +} + +// Do send request +func (s *MarginIsolatedAccountTransferService) Do(ctx context.Context, opts ...RequestOption) (res *MarginIsolatedAccountTransferResponse, err error) { + r := &request{ + method: http.MethodPost, + endpoint: marginIsolatedAccountTransferEndpoint, + secType: secTypeSigned, + } + m := params{ + "asset": s.asset, + "symbol": s.symbol, + "transFrom": s.transFrom, + "transTo": s.transTo, + "amount": s.amount, + } + r.setParams(m) + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return &MarginIsolatedAccountTransferResponse{}, err + } + res = new(MarginIsolatedAccountTransferResponse) + err = json.Unmarshal(data, res) + if err != nil { + return &MarginIsolatedAccountTransferResponse{}, err + } + return res, nil +} + +// MarginIsolatedAccountTransferService response +type MarginIsolatedAccountTransferResponse struct { + TranId string `json:"tranId"` +} + +// Isolated Margin Account Transfer History (MARGIN) +const ( + marginIsolatedAccountTransferHistoryEndpoint = "/sapi/v1/margin/isolated/transfer" +) + +type MarginIsolatedAccountTransferHistoryService struct { + c *Client + asset *string + symbol string + transFrom *string + transTo *string + startTime *uint64 + endTime *uint64 + current *int + size *int + archived *string +} + +// Asset set asset +func (s *MarginIsolatedAccountTransferHistoryService) Asset(asset string) *MarginIsolatedAccountTransferHistoryService { + s.asset = &asset + return s +} + +// Symbol set symbol +func (s *MarginIsolatedAccountTransferHistoryService) Symbol(symbol string) *MarginIsolatedAccountTransferHistoryService { + s.symbol = symbol + return s +} + +// TransFrom set transFrom +func (s *MarginIsolatedAccountTransferHistoryService) TransFrom(transFrom string) *MarginIsolatedAccountTransferHistoryService { + s.transFrom = &transFrom + return s +} + +// TransTo set transTo +func (s *MarginIsolatedAccountTransferHistoryService) TransTo(transTo string) *MarginIsolatedAccountTransferHistoryService { + s.transTo = &transTo + return s +} + +// StartTime set startTime +func (s *MarginIsolatedAccountTransferHistoryService) StartTime(startTime uint64) *MarginIsolatedAccountTransferHistoryService { + s.startTime = &startTime + return s +} + +// EndTime set endTime +func (s *MarginIsolatedAccountTransferHistoryService) EndTime(endTime uint64) *MarginIsolatedAccountTransferHistoryService { + s.endTime = &endTime + return s +} + +// Current set current +func (s *MarginIsolatedAccountTransferHistoryService) Current(current int) *MarginIsolatedAccountTransferHistoryService { + s.current = ¤t + return s +} + +// Size set size +func (s *MarginIsolatedAccountTransferHistoryService) Size(size int) *MarginIsolatedAccountTransferHistoryService { + s.size = &size + return s +} + +// Archived set archived +func (s *MarginIsolatedAccountTransferHistoryService) Archived(archived string) *MarginIsolatedAccountTransferHistoryService { + s.archived = &archived + return s +} + +// Do send request +func (s *MarginIsolatedAccountTransferHistoryService) Do(ctx context.Context, opts ...RequestOption) (res *MarginIsolatedAccountTransferHistoryResponse, err error) { + r := &request{ + method: http.MethodGet, + endpoint: marginIsolatedAccountTransferHistoryEndpoint, + secType: secTypeSigned, + } + m := params{ + "symbol": s.symbol, + } + if s.asset != nil { + m["asset"] = *s.asset + } + if s.transFrom != nil { + m["transFrom"] = *s.transFrom + } + if s.transTo != nil { + m["transTo"] = *s.transTo + } + if s.startTime != nil { + m["startTime"] = *s.startTime + } + if s.endTime != nil { + m["endTime"] = *s.endTime + } + if s.current != nil { + m["current"] = *s.current + } + if s.size != nil { + m["size"] = *s.size + } + if s.archived != nil { + m["archived"] = *s.archived + } + r.setParams(m) + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return &MarginIsolatedAccountTransferHistoryResponse{}, err + } + res = new(MarginIsolatedAccountTransferHistoryResponse) + err = json.Unmarshal(data, res) + if err != nil { + return &MarginIsolatedAccountTransferHistoryResponse{}, err + } + return res, nil +} + +// MarginIsolatedAccountTransferHistoryService response +type MarginIsolatedAccountTransferHistoryResponse struct { + Rows []struct { + Amount string `json:"amount"` + Asset string `json:"asset"` + Status string `json:"status"` + TimeStamp uint64 `json:"timeStamp"` + TxId int64 `json:"txId"` + TransFrom string `json:"transFrom"` + TransTo string `json:"transTo"` + } `json:"rows"` + Total int64 `json:"total"` +} + +// Query Isolated Margin Account Info (USER_DATA) +const ( + marginIsolatedAccountInfoEndpoint = "/sapi/v1/margin/isolated/account" +) + +type MarginIsolatedAccountInfoService struct { + c *Client + symbols *string +} + +// Symbols set symbols +func (s *MarginIsolatedAccountInfoService) Symbols(symbols string) *MarginIsolatedAccountInfoService { + s.symbols = &symbols + return s +} + +// Do send request +func (s *MarginIsolatedAccountInfoService) Do(ctx context.Context, opts ...RequestOption) (res *MarginIsolatedAccountInfoResponse, err error) { + r := &request{ + method: http.MethodGet, + endpoint: marginIsolatedAccountInfoEndpoint, + secType: secTypeSigned, + } + if s.symbols != nil { + r.addParam("symbols", s.symbols) + } + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return &MarginIsolatedAccountInfoResponse{}, err + } + res = new(MarginIsolatedAccountInfoResponse) + err = json.Unmarshal(data, res) + if err != nil { + return &MarginIsolatedAccountInfoResponse{}, err + } + return res, nil +} + +// MarginIsolatedAccountInfoService response +type MarginIsolatedAccountInfoResponse struct { + Assets []struct { + BaseAsset struct { + Asset string `json:"asset"` + BorrowEnabled bool `json:"borrowEnabled"` + Free string `json:"free"` + Interest string `json:"interest"` + Locked string `json:"locked"` + NetAsset string `json:"netAsset"` + NetAssetOfBtc string `json:"netAssetOfBtc"` + RepayEnabled bool `json:"repayEnabled"` + TotalAsset string `json:"totalAsset"` + } `json:"baseAsset"` + QuoteAsset struct { + Asset string `json:"asset"` + BorrowEnabled bool `json:"borrowEnabled"` + Free string `json:"free"` + Interest string `json:"interest"` + Locked string `json:"locked"` + NetAsset string `json:"netAsset"` + NetAssetOfBtc string `json:"netAssetOfBtc"` + RepayEnabled bool `json:"repayEnabled"` + TotalAsset string `json:"totalAsset"` + } `json:"quoteAsset"` + Symbol string `json:"symbol"` + IsolatedCreated bool `json:"isolatedCreated"` + Enabled bool `json:"enabled"` + MarginLevel string `json:"marginLevel"` + MarginLevelStatus string `json:"marginLevelStatus"` + MarginRatio string `json:"marginRatio"` + IndexPrice string `json:"indexPrice"` + LiquidatePrice string `json:"liquidatePrice"` + LiquidateRate string `json:"liquidateRate"` + TradeEnabled bool `json:"tradeEnabled"` + } `json:"assets"` +} + +// Disable Isolated Margin Account (TRADE) +const ( + marginIsolatedAccountDisableEndpoint = "/sapi/v1/margin/isolated/account" +) + +type MarginIsolatedAccountDisableService struct { + c *Client + symbol string +} + +// Symbol set symbol +func (s *MarginIsolatedAccountDisableService) Symbol(symbol string) *MarginIsolatedAccountDisableService { + s.symbol = symbol + return s +} + +// Do send request +func (s *MarginIsolatedAccountDisableService) Do(ctx context.Context, opts ...RequestOption) (res *MarginIsolatedAccountDisableResponse, err error) { + r := &request{ + method: http.MethodDelete, + endpoint: marginIsolatedAccountDisableEndpoint, + secType: secTypeSigned, + } + m := params{ + "symbol": s.symbol, + } + r.setParams(m) + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return &MarginIsolatedAccountDisableResponse{}, err + } + res = new(MarginIsolatedAccountDisableResponse) + err = json.Unmarshal(data, res) + if err != nil { + return &MarginIsolatedAccountDisableResponse{}, err + } + return res, nil +} + +// MarginIsolatedAccountDisableService response +type MarginIsolatedAccountDisableResponse struct { + Success bool `json:"success"` +} + +// Enable Isolated Margin Account (TRADE) +const ( + marginIsolatedAccountEnableEndpoint = "/sapi/v1/margin/isolated/account" +) + +type MarginIsolatedAccountEnableService struct { + c *Client + symbol string +} + +// Symbol set symbol +func (s *MarginIsolatedAccountEnableService) Symbol(symbol string) *MarginIsolatedAccountEnableService { + s.symbol = symbol + return s +} + +// Do send request +func (s *MarginIsolatedAccountEnableService) Do(ctx context.Context, opts ...RequestOption) (res *MarginIsolatedAccountEnableResponse, err error) { + r := &request{ + method: http.MethodPost, + endpoint: marginIsolatedAccountEnableEndpoint, + secType: secTypeSigned, + } + m := params{ + "symbol": s.symbol, + } + r.setParams(m) + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return &MarginIsolatedAccountEnableResponse{}, err + } + res = new(MarginIsolatedAccountEnableResponse) + err = json.Unmarshal(data, res) + if err != nil { + return &MarginIsolatedAccountEnableResponse{}, err + } + return res, nil +} + +// MarginIsolatedAccountEnableService response +type MarginIsolatedAccountEnableResponse struct { + Success bool `json:"success"` +} + +// Query Enabled Isolated Margin Account Limit (USER_DATA) +const ( + marginIsolatedAccountLimitEndpoint = "/sapi/v1/margin/isolated/accountLimit" +) + +type MarginIsolatedAccountLimitService struct { + c *Client +} + +// Do send request +func (s *MarginIsolatedAccountLimitService) Do(ctx context.Context, opts ...RequestOption) (res *MarginIsolatedAccountLimitResponse, err error) { + r := &request{ + method: http.MethodGet, + endpoint: marginIsolatedAccountLimitEndpoint, + secType: secTypeSigned, + } + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return &MarginIsolatedAccountLimitResponse{}, err + } + res = new(MarginIsolatedAccountLimitResponse) + err = json.Unmarshal(data, res) + if err != nil { + return &MarginIsolatedAccountLimitResponse{}, err + } + return res, nil +} + +// MarginIsolatedAccountLimitService response +type MarginIsolatedAccountLimitResponse struct { + EnabledAccount int `json:"enabledAccount"` + MaxAccount int `json:"maxAccount"` +} + +// Query Isolated Margin Symbol (USER_DATA) +const ( + marginIsolatedSymbolEndpoint = "/sapi/v1/margin/isolated/pair" +) + +type MarginIsolatedSymbolService struct { + c *Client + symbol string +} + +// Symbol set symbol +func (s *MarginIsolatedSymbolService) Symbol(symbol string) *MarginIsolatedSymbolService { + s.symbol = symbol + return s +} + +// Do send request +func (s *MarginIsolatedSymbolService) Do(ctx context.Context, opts ...RequestOption) (res *MarginIsolatedSymbolResponse, err error) { + r := &request{ + method: http.MethodGet, + endpoint: marginIsolatedSymbolEndpoint, + secType: secTypeSigned, + } + m := params{ + "symbol": s.symbol, + } + r.setParams(m) + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return &MarginIsolatedSymbolResponse{}, err + } + res = new(MarginIsolatedSymbolResponse) + err = json.Unmarshal(data, res) + if err != nil { + return &MarginIsolatedSymbolResponse{}, err + } + return res, nil +} + +// MarginIsolatedSymbolService response +type MarginIsolatedSymbolResponse struct { + Symbol string `json:"symbol"` + Base string `json:"base"` + Quote string `json:"quote"` + IsMarginTrade bool `json:"isMarginTrade"` + IsBuyAllowed bool `json:"isBuyAllowed"` + IsSellAllowed bool `json:"isSellAllowed"` +} + +// Get All Isolated Margin Symbol(USER_DATA) +const ( + marginIsolatedSymbolAllEndpoint = "/sapi/v1/margin/isolated/allPairs" +) + +// AllIsolatedMarginSymbolService returns all isolated margin symbols +type AllIsolatedMarginSymbolService struct { + c *Client +} + +// Do send request +func (s *AllIsolatedMarginSymbolService) Do(ctx context.Context, opts ...RequestOption) (res []*MarginIsolatedSymbolResponse, err error) { + r := &request{ + method: http.MethodGet, + endpoint: marginIsolatedSymbolAllEndpoint, + secType: secTypeAPIKey, + } + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return []*MarginIsolatedSymbolResponse{}, err + } + res = make([]*MarginIsolatedSymbolResponse, 0) + err = json.Unmarshal(data, &res) + if err != nil { + return []*MarginIsolatedSymbolResponse{}, err + } + return res, nil +} + +// MarginIsolatedSymbolAllService returns all isolated margin symbols + +// Toggle BNB Burn On Spot Trade And Margin Interest (USER_DATA) +const ( + marginToggleBnbBurnEndpoint = "/sapi/v1/bnbBurn" +) + +type MarginToggleBnbBurnService struct { + c *Client + spotBNBBurn *string + interestBNBBurn *string +} + +// SpotBNBBurn set spotBNBBurn +func (s *MarginToggleBnbBurnService) SpotBNBBurn(spotBNBBurn string) *MarginToggleBnbBurnService { + s.spotBNBBurn = &spotBNBBurn + return s +} + +// InterestBNBBurn set interestBNBBurn +func (s *MarginToggleBnbBurnService) InterestBNBBurn(interestBNBBurn string) *MarginToggleBnbBurnService { + s.interestBNBBurn = &interestBNBBurn + return s +} + +// Do send request +func (s *MarginToggleBnbBurnService) Do(ctx context.Context, opts ...RequestOption) (res *MarginToggleBnbBurnResponse, err error) { + r := &request{ + method: http.MethodPost, + endpoint: marginToggleBnbBurnEndpoint, + secType: secTypeSigned, + } + if s.spotBNBBurn != nil { + r.addParam("spotBNBBurn", s.spotBNBBurn) + } + if s.interestBNBBurn != nil { + r.addParam("interestBNBBurn", s.interestBNBBurn) + } + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return &MarginToggleBnbBurnResponse{}, err + } + res = new(MarginToggleBnbBurnResponse) + err = json.Unmarshal(data, res) + if err != nil { + return &MarginToggleBnbBurnResponse{}, err + } + return res, nil +} + +// MarginToggleBnbBurnService response +type MarginToggleBnbBurnResponse struct { + SpotBNBBurn bool `json:"spotBNBBurn"` + InterestBNBBurn bool `json:"interestBNBBurn"` +} + +// Get BNB Burn Status (USER_DATA) +const ( + marginBnbBurnStatusEndpoint = "/sapi/v1/bnbBurn" +) + +type MarginBnbBurnStatusService struct { + c *Client +} + +// Do send request +func (s *MarginBnbBurnStatusService) Do(ctx context.Context, opts ...RequestOption) (res *MarginBnbBurnStatusResponse, err error) { + r := &request{ + method: http.MethodGet, + endpoint: marginBnbBurnStatusEndpoint, + secType: secTypeSigned, + } + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return &MarginBnbBurnStatusResponse{}, err + } + res = new(MarginBnbBurnStatusResponse) + err = json.Unmarshal(data, res) + if err != nil { + return &MarginBnbBurnStatusResponse{}, err + } + return res, nil +} + +// MarginBnbBurnStatusService response +type MarginBnbBurnStatusResponse struct { + SpotBNBBurn bool `json:"spotBNBBurn"` + InterestBNBBurn bool `json:"interestBNBBurn"` +} + +// Query Margin Interest Rate History (USER_DATA) +const ( + marginInterestRateHistoryEndpoint = "/sapi/v1/margin/interestRateHistory" +) + +type MarginInterestRateHistoryService struct { + c *Client + asset string + vipLevel *int + startTime *uint64 + endTime *uint64 +} + +// Asset set asset +func (s *MarginInterestRateHistoryService) Asset(asset string) *MarginInterestRateHistoryService { + s.asset = asset + return s +} + +// VipLevel set vipLevel +func (s *MarginInterestRateHistoryService) VipLevel(vipLevel int) *MarginInterestRateHistoryService { + s.vipLevel = &vipLevel + return s +} + +// StartTime set startTime +func (s *MarginInterestRateHistoryService) StartTime(startTime uint64) *MarginInterestRateHistoryService { + s.startTime = &startTime + return s +} + +// EndTime set endTime +func (s *MarginInterestRateHistoryService) EndTime(endTime uint64) *MarginInterestRateHistoryService { + s.endTime = &endTime + return s +} + +// Do send request +func (s *MarginInterestRateHistoryService) Do(ctx context.Context, opts ...RequestOption) (res []*MarginInterestRateHistoryResponse, err error) { + r := &request{ + method: http.MethodGet, + endpoint: marginInterestRateHistoryEndpoint, + secType: secTypeSigned, + } + m := params{ + "asset": s.asset, + } + if s.vipLevel != nil { + m["vipLevel"] = *s.vipLevel + } + if s.startTime != nil { + m["startTime"] = *s.startTime + } + if s.endTime != nil { + m["endTime"] = *s.endTime + } + r.setParams(m) + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return []*MarginInterestRateHistoryResponse{}, err + } + res = make([]*MarginInterestRateHistoryResponse, 0) + err = json.Unmarshal(data, &res) + if err != nil { + return []*MarginInterestRateHistoryResponse{}, err + } + return res, nil +} + +// MarginInterestRateHistoryService response +type MarginInterestRateHistoryResponse struct { + Asset string `json:"asset"` + DailyInterestRate float64 `json:"dailyInterestRate"` + Timestamp uint64 `json:"timestamp"` + VIPLevel int `json:"vipLevel"` +} + +// Query Cross Margin Fee Data (USER_DATA) +const ( + marginCrossMarginFeeEndpoint = "/sapi/v1/margin/crossMarginData" +) + +type MarginCrossMarginFeeService struct { + c *Client + vipLevel *int + coin *string +} + +// VipLevel set vipLevel +func (s *MarginCrossMarginFeeService) VipLevel(vipLevel int) *MarginCrossMarginFeeService { + s.vipLevel = &vipLevel + return s +} + +// Coin set coin +func (s *MarginCrossMarginFeeService) Coin(coin string) *MarginCrossMarginFeeService { + s.coin = &coin + return s +} + +// Do send request +func (s *MarginCrossMarginFeeService) Do(ctx context.Context, opts ...RequestOption) (res []*MarginCrossMarginFeeResponse, err error) { + r := &request{ + method: http.MethodGet, + endpoint: marginCrossMarginFeeEndpoint, + secType: secTypeSigned, + } + if s.vipLevel != nil { + r.setParam("vipLevel", *s.vipLevel) + } + if s.coin != nil { + r.setParam("coin", *s.coin) + } + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return []*MarginCrossMarginFeeResponse{}, err + } + res = make([]*MarginCrossMarginFeeResponse, 0) + err = json.Unmarshal(data, &res) + if err != nil { + return []*MarginCrossMarginFeeResponse{}, err + } + return res, nil +} + +// MarginCrossMarginFeeService response +type MarginCrossMarginFeeResponse struct { + VIPLevel int `json:"vipLevel"` + Coin string `json:"coin"` + TransferIn bool `json:"transferIn"` + Borrowable bool `json:"transferOut"` + DailyInterest string `json:"dailyInterest"` + YearlyInterest string `json:"yearlyInterest"` + BorrowLimit string `json:"borrowLimit"` + MarginablePairs struct { + Pair string `json:"pair"` + } `json:"marginablePairs"` +} + +// Query Isolated Margin Fee Data (USER_DATA) +const ( + marginIsolatedMarginFeeEndpoint = "/sapi/v1/margin/isolatedMarginData" +) + +type MarginIsolatedMarginFeeService struct { + c *Client + vipLevel *int + symbol *string +} + +// VipLevel set vipLevel +func (s *MarginIsolatedMarginFeeService) VipLevel(vipLevel int) *MarginIsolatedMarginFeeService { + s.vipLevel = &vipLevel + return s +} + +// Symbol set symbol +func (s *MarginIsolatedMarginFeeService) Symbol(symbol string) *MarginIsolatedMarginFeeService { + s.symbol = &symbol + return s +} + +// Do send request +func (s *MarginIsolatedMarginFeeService) Do(ctx context.Context, opts ...RequestOption) (res []*MarginIsolatedMarginFeeResponse, err error) { + r := &request{ + method: http.MethodGet, + endpoint: marginIsolatedMarginFeeEndpoint, + secType: secTypeSigned, + } + if s.vipLevel != nil { + r.setParam("vipLevel", *s.vipLevel) + } + if s.symbol != nil { + r.setParam("symbol", *s.symbol) + } + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return []*MarginIsolatedMarginFeeResponse{}, err + } + res = make([]*MarginIsolatedMarginFeeResponse, 0) + err = json.Unmarshal(data, &res) + if err != nil { + return []*MarginIsolatedMarginFeeResponse{}, err + } + return res, nil +} + +// MarginIsolatedMarginFeeService response +type MarginIsolatedMarginFeeResponse struct { + VIPLevel int `json:"vipLevel"` + Symbol string `json:"symbol"` + Leverage string `json:"leverage"` + Data struct { + Coin string `json:"coin"` + DailyInterest string `json:"dailyInterest"` + BorrowLimit string `json:"borrowLimit"` + } `json:"data"` +} + +// Query Isolated Margin Tier Data (USER_DATA) +const ( + marginIsolatedMarginTierEndpoint = "/sapi/v1/margin/isolatedMarginTier" +) + +type MarginIsolatedMarginTierService struct { + c *Client + symbol string + tier *int +} + +// Symbol set symbol +func (s *MarginIsolatedMarginTierService) Symbol(symbol string) *MarginIsolatedMarginTierService { + s.symbol = symbol + return s +} + +// Tier set tier +func (s *MarginIsolatedMarginTierService) Tier(tier int) *MarginIsolatedMarginTierService { + s.tier = &tier + return s +} + +// Do send request +func (s *MarginIsolatedMarginTierService) Do(ctx context.Context, opts ...RequestOption) (res []*MarginIsolatedMarginTierResponse, err error) { + r := &request{ + method: http.MethodGet, + endpoint: marginIsolatedMarginTierEndpoint, + secType: secTypeSigned, + } + m := params{ + "symbol": s.symbol, + } + if s.tier != nil { + m["tier"] = *s.tier + } + r.setParams(m) + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return []*MarginIsolatedMarginTierResponse{}, err + } + res = make([]*MarginIsolatedMarginTierResponse, 0) + err = json.Unmarshal(data, &res) + if err != nil { + return []*MarginIsolatedMarginTierResponse{}, err + } + return res, nil +} + +// MarginIsolatedMarginTierService response +type MarginIsolatedMarginTierResponse struct { + Symbol string `json:"symbol"` + Tier int `json:"tier"` + EffectiveMultiple string `json:"effectiveMultiple"` + InitialRiskRatio string `json:"initialRiskRatio"` + LiquidationRiskRatio string `json:"liquidationRiskRatio"` + BaseAssetMaxBorrowable string `json:"baseAssetMaxBorrowable"` + QuoteAssetMaxBorrowable string `json:"quoteAssetMaxBorrowable"` +} + +// Query Current Margin Order Count Usage (TRADE) +const ( + marginCurrentOrderCountEndpoint = "/sapi/v1/margin/rateLimit/order" +) + +type MarginCurrentOrderCountService struct { + c *Client + isIsolated *string + symbol *string +} + +// IsIsolated set isIsolated +func (s *MarginCurrentOrderCountService) IsIsolated(isIsolated string) *MarginCurrentOrderCountService { + s.isIsolated = &isIsolated + return s +} + +// Symbol set symbol +func (s *MarginCurrentOrderCountService) Symbol(symbol string) *MarginCurrentOrderCountService { + s.symbol = &symbol + return s +} + +// Do send request +func (s *MarginCurrentOrderCountService) Do(ctx context.Context, opts ...RequestOption) (res []*MarginCurrentOrderCountResponse, err error) { + r := &request{ + method: http.MethodGet, + endpoint: marginCurrentOrderCountEndpoint, + secType: secTypeSigned, + } + if s.isIsolated != nil { + r.setParam("isIsolated", *s.isIsolated) + } + if s.symbol != nil { + r.setParam("symbol", *s.symbol) + } + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return []*MarginCurrentOrderCountResponse{}, err + } + res = make([]*MarginCurrentOrderCountResponse, 0) + err = json.Unmarshal(data, &res) + if err != nil { + return []*MarginCurrentOrderCountResponse{}, err + } + return res, nil +} + +// MarginCurrentOrderCountService response +type MarginCurrentOrderCountResponse struct { + RateLimitType string `json:"rateLimitType"` + Interval string `json:"interval"` + IntervalNum int `json:"intervalNum"` + Limit int `json:"limit"` + Count int `json:"count"` +} + +// Margin Dustlog (USER_DATA) +const ( + marginDustlogEndpoint = "/sapi/v1/margin/dribblet" +) + +type MarginDustlogService struct { + c *Client + startTime *uint64 + endTime *uint64 +} + +// StartTime set startTime +func (s *MarginDustlogService) StartTime(startTime uint64) *MarginDustlogService { + s.startTime = &startTime + return s +} + +// EndTime set endTime +func (s *MarginDustlogService) EndTime(endTime uint64) *MarginDustlogService { + s.endTime = &endTime + return s +} + +// Do send request +func (s *MarginDustlogService) Do(ctx context.Context, opts ...RequestOption) (res *MarginDustlogResponse, err error) { + r := &request{ + method: http.MethodGet, + endpoint: marginDustlogEndpoint, + secType: secTypeSigned, + } + if s.startTime != nil { + r.setParam("startTime", *s.startTime) + } + if s.endTime != nil { + r.setParam("endTime", *s.endTime) + } + data, err := s.c.callAPI(ctx, r) + if err != nil { + return + } + res = new(MarginDustlogResponse) + err = json.Unmarshal(data, res) + if err != nil { + return + } + return res, nil +} + +type MarginDustlogResponse struct { + Total uint8 `json:"total"` //Total counts of exchange + UserAssetDribblets []UserAssetDribblet `json:"userAssetDribblets"` +} + +// UserAssetDribblet represents one dust log row +type UserAssetDribblet struct { + OperateTime int64 `json:"operateTime"` + TotalTransferedAmount string `json:"totalTransferedAmount"` //Total transfered BNB amount for this exchange. + TotalServiceChargeAmount string `json:"totalServiceChargeAmount"` //Total service charge amount for this exchange. + TransId int64 `json:"transId"` + UserAssetDribbletDetails []UserAssetDribbletDetail `json:"userAssetDribbletDetails"` //Details of this exchange. +} + +// DustLog represents one dust log informations +type UserAssetDribbletDetail struct { + TransId int `json:"transId"` + ServiceChargeAmount string `json:"serviceChargeAmount"` + Amount string `json:"amount"` + OperateTime int64 `json:"operateTime"` //The time of this exchange. + TransferedAmount string `json:"transferedAmount"` + FromAsset string `json:"fromAsset"` +} + +// Cross margin collateral ratio (MARKET_DATA) +const ( + marginCrossCollateralRatioEndpoint = "/sapi/v1/margin/crossMarginCollateralRatio" +) + +type MarginCrossCollateralRatioService struct { + c *Client +} + +// Do send request +func (s *MarginCrossCollateralRatioService) Do(ctx context.Context, opts ...RequestOption) (res []*MarginCrossCollateralRatioResponse, err error) { + r := &request{ + method: http.MethodGet, + endpoint: marginCrossCollateralRatioEndpoint, + secType: secTypeSigned, + } + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return []*MarginCrossCollateralRatioResponse{}, err + } + res = make([]*MarginCrossCollateralRatioResponse, 0) + err = json.Unmarshal(data, &res) + if err != nil { + return []*MarginCrossCollateralRatioResponse{}, err + } + return res, nil +} + +// MarginCrossCollateralRatioService response +type MarginCrossCollateralRatioResponse struct { + Collaterals []*struct { + MinUsdValue string `json:"minUsdValue"` + MaxUsdValue string `json:"maxUsdValue"` + DiscountRate string `json:"discountRate"` + } `json:"collaterals"` + AssetNames []*struct { + Asset string `json:"asset"` + } `json:"assetNames"` +} + +// Get Small Liability Exchange Coin List (USER_DATA) +const ( + marginSmallLiabilityExchangeCoinListEndpoint = "/sapi/v1/margin/exchange-small-liability" +) + +type MarginSmallLiabilityExchangeCoinListService struct { + c *Client +} + +// Do send request +func (s *MarginSmallLiabilityExchangeCoinListService) Do(ctx context.Context, opts ...RequestOption) (res []*MarginSmallLiabilityExchangeCoinListResponse, err error) { + r := &request{ + method: http.MethodGet, + endpoint: marginSmallLiabilityExchangeCoinListEndpoint, + secType: secTypeSigned, + } + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return []*MarginSmallLiabilityExchangeCoinListResponse{}, err + } + res = make([]*MarginSmallLiabilityExchangeCoinListResponse, 0) + err = json.Unmarshal(data, &res) + if err != nil { + return []*MarginSmallLiabilityExchangeCoinListResponse{}, err + } + return res, nil +} + +// MarginSmallLiabilityExchangeCoinListService response +type MarginSmallLiabilityExchangeCoinListResponse struct { + Asset string `json:"asset"` + Interest string `json:"interest"` + Principal string `json:"principal"` + LiabilityOfBUSD string `json:"liabilityOfBUSD"` +} + +// Small Liability Exchange (MARGIN) +const ( + marginSmallLiabilityExchangeEndpoint = "/sapi/v1/margin/exchange-small-liability" +) + +type MarginSmallLiabilityExchangeService struct { + c *Client + assetNames string +} + +// AssetNames set assetNames +func (s *MarginSmallLiabilityExchangeService) AssetNames(assetNames string) *MarginSmallLiabilityExchangeService { + s.assetNames = assetNames + return s +} + +// Do send request +func (s *MarginSmallLiabilityExchangeService) Do(ctx context.Context, opts ...RequestOption) (res []*MarginSmallLiabilityExchangeResponse, err error) { + r := &request{ + method: http.MethodPost, + endpoint: marginSmallLiabilityExchangeEndpoint, + secType: secTypeSigned, + } + m := params{ + "assetNames": s.assetNames, + } + r.setParams(m) + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return []*MarginSmallLiabilityExchangeResponse{}, err + } + res = make([]*MarginSmallLiabilityExchangeResponse, 0) + err = json.Unmarshal(data, &res) + if err != nil { + return []*MarginSmallLiabilityExchangeResponse{}, err + } + return res, nil +} + +// MarginSmallLiabilityExchangeService response +type MarginSmallLiabilityExchangeResponse struct { +} + +// Get Small Liability Exchange History (USER_DATA) +const ( + marginSmallLiabilityExchangeHistoryEndpoint = "/sapi/v1/margin/exchange-small-liability-history" +) + +type MarginSmallLiabilityExchangeHistoryService struct { + c *Client + current int + size int + startTime *uint64 + endTime *uint64 +} + +// Current set current +func (s *MarginSmallLiabilityExchangeHistoryService) Current(current int) *MarginSmallLiabilityExchangeHistoryService { + s.current = current + return s +} + +// Size set size +func (s *MarginSmallLiabilityExchangeHistoryService) Size(size int) *MarginSmallLiabilityExchangeHistoryService { + s.size = size + return s +} + +// StartTime set startTime +func (s *MarginSmallLiabilityExchangeHistoryService) StartTime(startTime uint64) *MarginSmallLiabilityExchangeHistoryService { + s.startTime = &startTime + return s +} + +// EndTime set endTime +func (s *MarginSmallLiabilityExchangeHistoryService) EndTime(endTime uint64) *MarginSmallLiabilityExchangeHistoryService { + s.endTime = &endTime + return s +} + +// Do send request +func (s *MarginSmallLiabilityExchangeHistoryService) Do(ctx context.Context, opts ...RequestOption) (res []*MarginSmallLiabilityExchangeHistoryResponse, err error) { + r := &request{ + method: http.MethodGet, + endpoint: marginSmallLiabilityExchangeHistoryEndpoint, + secType: secTypeSigned, + } + m := params{ + "current": s.current, + "size": s.size, + } + if s.startTime != nil { + m["startTime"] = *s.startTime + } + if s.endTime != nil { + m["endTime"] = *s.endTime + } + r.setParams(m) + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return []*MarginSmallLiabilityExchangeHistoryResponse{}, err + } + res = make([]*MarginSmallLiabilityExchangeHistoryResponse, 0) + err = json.Unmarshal(data, &res) + if err != nil { + return []*MarginSmallLiabilityExchangeHistoryResponse{}, err + } + return res, nil +} + +// MarginSmallLiabilityExchangeHistoryService response +type MarginSmallLiabilityExchangeHistoryResponse struct { + Total int `json:"total"` + Rows []*struct { + Asset string `json:"asset"` + Amount string `json:"amount"` + TargetAsset string `json:"targetAsset"` + TargetAmount string `json:"targetAmount"` + BizType string `json:"bizType"` + Timestamp uint64 `json:"timestamp"` + } `json:"rows"` +} diff --git a/margin_test.go b/margin_test.go new file mode 100644 index 0000000..c0e06ce --- /dev/null +++ b/margin_test.go @@ -0,0 +1,1885 @@ +package binance_connector + +import ( + "context" + "testing" + + "github.com/stretchr/testify/suite" +) + +type marginTestSuite struct { + baseTestSuite +} + +func TestMargin(t *testing.T) { + suite.Run(t, new(marginTestSuite)) +} + +func (s *marginTestSuite) TestTransfer() { + data := []byte(`{ + "tranId": 100000001 + }`) + s.mockDo(data, nil) + defer s.assertDo() + asset := "BTC" + amount := 1.000 + transferType := 1 + s.assertReq(func(r *request) { + e := newSignedRequest().setParams(params{ + "asset": asset, + "amount": amount, + "type": transferType, + }) + s.assertRequestEqual(e, r) + }) + res, err := s.client.NewTransferService().Asset(asset). + Amount(amount).TransferType(transferType).Do(newContext()) + s.r().NoError(err) + e := &TransferResponse{ + TranId: 100000001, + } + s.assertTransactionResponseEqual(e, res) +} + +func (s *marginTestSuite) assertTransactionResponseEqual(a, e *TransferResponse) { + s.r().Equal(a.TranId, e.TranId, "TranID") +} + +func (s *marginTestSuite) TestLoan() { + data := []byte(`{ + "tranId": 100000001 + }`) + s.mockDo(data, nil) + defer s.assertDo() + asset := "BTC" + amount := 1.000 + s.assertReq(func(r *request) { + e := newSignedRequest().setParams(params{ + "asset": asset, + "amount": amount, + }) + s.assertRequestEqual(e, r) + }) + res, err := s.client.NewBorrowService().Asset(asset). + Amount(amount).Do(newContext()) + s.r().NoError(err) + e := &BorrowResponse{ + TranId: 100000001, + } + s.assertBorrowResponseEqual(e, res) +} + +func (s *marginTestSuite) assertBorrowResponseEqual(a, e *BorrowResponse) { + s.r().Equal(a.TranId, e.TranId, "TranID") +} + +func (s *marginTestSuite) TestRepay() { + data := []byte(`{ + "tranId": 100000001 + }`) + s.mockDo(data, nil) + defer s.assertDo() + asset := "BTC" + amount := 1.000 + s.assertReq(func(r *request) { + e := newSignedRequest().setParams(params{ + "asset": asset, + "amount": amount, + }) + s.assertRequestEqual(e, r) + }) + res, err := s.client.NewRepayService().Asset(asset). + Amount(amount).Do(newContext()) + s.r().NoError(err) + e := &RepayResponse{ + TranId: 100000001, + } + s.assertRepayResponseEqual(e, res) +} + +func (s *marginTestSuite) assertRepayResponseEqual(a, e *RepayResponse) { + s.r().Equal(a.TranId, e.TranId, "TranID") +} + +func (s *marginTestSuite) TestGetMaxBorrowable() { + data := []byte(`{ + "amount": "1.69248805" + }`) + s.mockDo(data, nil) + defer s.assertDo() + + s.assertReq(func(r *request) { + e := newSignedRequest().setParams(params{ + "asset": "BNBBTC", + }) + s.assertRequestEqual(e, r) + }) + + borrowable, err := s.client.NewMarginAccountQueryMaxBorrowService(). + Asset("BNBBTC").Do(newContext()) + r := s.r() + r.NoError(err) + e := &MarginAccountQueryMaxBorrowResponse{ + Amount: "1.69248805", + } + s.assertMaxBorrowableEqual(e, borrowable) +} + +func (s *marginTestSuite) assertMaxBorrowableEqual(e, a *MarginAccountQueryMaxBorrowResponse) { + s.r().Equal(e.Amount, a.Amount, "Amount") +} + +func (s *marginTestSuite) TestGetMaxTransferable() { + data := []byte(`{ + "amount": "3.59498107" + }`) + s.mockDo(data, nil) + defer s.assertDo() + + s.assertReq(func(r *request) { + e := newSignedRequest().setParams(params{ + "asset": "BNBBTC", + }) + s.assertRequestEqual(e, r) + }) + + transferable, err := s.client.NewMarginAccountQueryMaxTransferOutAmountService(). + Asset("BNBBTC").Do(newContext()) + r := s.r() + r.NoError(err) + e := &MarginAccountQueryMaxTransferOutAmountResponse{ + Amount: "3.59498107", + } + s.assertMaxTransferableEqual(e, transferable) +} + +func (s *marginTestSuite) assertMaxTransferableEqual(e, a *MarginAccountQueryMaxTransferOutAmountResponse) { + s.r().Equal(e.Amount, a.Amount, "Amount") +} + +func (s *marginTestSuite) TestGetMarginPriceIndex() { + data := []byte(`{ + "calcTime": 1562046418000, + "price": "0.00333930", + "symbol": "BNBBTC" + }`) + s.mockDo(data, nil) + defer s.assertDo() + symbol := "BNBBTC" + s.assertReq(func(r *request) { + e := newRequest() + e.setParam("symbol", symbol) + s.assertRequestEqual(e, r) + }) + res, err := s.client.NewQueryMarginPriceIndexService().Symbol(symbol).Do(newContext()) + s.r().NoError(err) + e := &QueryMarginPriceIndexResponse{ + CalcTime: 1562046418000, + Symbol: symbol, + Price: "0.00333930", + } + s.assertMarginPriceIndexEqual(e, res) +} + +func (s *marginTestSuite) assertMarginPriceIndexEqual(e, a *QueryMarginPriceIndexResponse) { + r := s.r() + r.Equal(e.CalcTime, a.CalcTime, "CalcTime") + r.Equal(e.Symbol, a.Symbol, "Symbol") + r.Equal(e.Price, a.Price, "Price") +} + +func (s *marginTestSuite) TestGetIsolatedMarginAllPairs() { + data := []byte(`[{ + "base": "BNB", + "isBuyAllowed": true, + "isMarginTrade": true, + "isSellAllowed": true, + "quote": "BTC", + "symbol": "BNBBTC" + }, + { + "base": "TRX", + "isBuyAllowed": true, + "isMarginTrade": true, + "isSellAllowed": true, + "quote": "BTC", + "symbol": "TRXBTC" + }]`) + s.mockDo(data, nil) + defer s.assertDo() + + s.assertReq(func(r *request) { + e := newRequest() + s.assertRequestEqual(e, r) + }) + res, err := s.client.NewAllIsolatedMarginSymbolService(). + Do(newContext()) + r := s.r() + r.NoError(err) + r.Len(res, 2) + e := []*MarginIsolatedSymbolResponse{ + { + Symbol: "BNBBTC", + Base: "BNB", + Quote: "BTC", + IsMarginTrade: true, + IsBuyAllowed: true, + IsSellAllowed: true, + }, { + Symbol: "TRXBTC", + Base: "TRX", + Quote: "BTC", + IsMarginTrade: true, + IsBuyAllowed: true, + IsSellAllowed: true, + }, + } + + for i := 0; i < len(res); i++ { + s.assertIsolatedMarginAllPairsEqual(e[i], res[i]) + } +} + +func (s *marginTestSuite) assertIsolatedMarginAllPairsEqual(e, a *MarginIsolatedSymbolResponse) { + r := s.r() + r.Equal(e.Symbol, a.Symbol, "Symbol") + r.Equal(e.Base, a.Base, "Base") + r.Equal(e.Quote, a.Quote, "Quote") + r.Equal(e.IsMarginTrade, a.IsMarginTrade, "IsMarginTrade") + r.Equal(e.IsBuyAllowed, a.IsBuyAllowed, "IsBuyAllowed") + r.Equal(e.IsSellAllowed, a.IsSellAllowed, "IsSellAllowed") +} + +func (s *marginTestSuite) TestGetMarginAsset() { + data := []byte(`{ + "assetFullName": "Binance Coin", + "assetName": "BNB", + "isBorrowable": false, + "isMortgageable": true, + "userMinBorrow": "0.00000000", + "userMinRepay": "0.00000000" + }`) + s.mockDo(data, nil) + defer s.assertDo() + asset := "BNB" + s.assertReq(func(r *request) { + e := newRequest() + e.setParam("asset", asset) + s.assertRequestEqual(e, r) + }) + res, err := s.client.NewQueryMarginAssetService().Asset(asset).Do(newContext()) + s.r().NoError(err) + e := &QueryMarginAssetResponse{ + FullName: "Binance Coin", + Name: asset, + Borrowable: false, + Mortgageable: true, + UserMinBorrow: "0.00000000", + UserMinRepay: "0.00000000", + } + s.assertMarginAssetEqual(e, res) +} + +func (s *marginTestSuite) assertMarginAssetEqual(e, a *QueryMarginAssetResponse) { + r := s.r() + r.Equal(e.FullName, a.FullName, "FullName") + r.Equal(e.Name, a.Name, "Name") + r.Equal(e.Borrowable, a.Borrowable, "Borrowable") + r.Equal(e.Mortgageable, a.Mortgageable, "Mortgageable") + r.Equal(e.UserMinBorrow, a.UserMinBorrow, "UserMinBorrow") + r.Equal(e.UserMinRepay, a.UserMinRepay, "UserMinRepay") +} + +func (s *marginTestSuite) TestGetAllMarginAssets() { + data := []byte(`{ + "assetDetailList": [ + { + "assetFullName": "Bitcoin", + "assetName": "BTC", + "isBorrowable": true, + "isMortgageable": true, + "minLoanAmt": "0.00010000", + "maxLoanAmt": "100000.00000000", + "minMortgageAmt": "0.00010000", + "maxMortgageAmt": "100000.00000000", + "asset": "BTC" + }, + { + "assetFullName": "Ethereum", + "assetName": "ETH", + "isBorrowable": true, + "isMortgageable": true, + "minLoanAmt": "0.01000000", + "maxLoanAmt": "10000.00000000", + "minMortgageAmt": "0.01000000", + "maxMortgageAmt": "10000.00000000", + "asset": "ETH" + } + ] + }`) + + s.mockDo(data, nil) + defer s.assertDo() + + resp, err := s.client.NewGetAllMarginAssetsService().Do(context.Background()) + + s.r().NoError(err) + s.Len(resp.AssetDetailList, 2) + s.Equal("Bitcoin", resp.AssetDetailList[0].AssetFullName) + s.Equal("BTC", resp.AssetDetailList[0].AssetName) + s.True(resp.AssetDetailList[0].IsBorrowable) + s.True(resp.AssetDetailList[0].IsMortgageable) + s.Equal("0.00010000", resp.AssetDetailList[0].MinLoanAmt) + s.Equal("100000.00000000", resp.AssetDetailList[0].MaxLoanAmt) + s.Equal("0.00010000", resp.AssetDetailList[0].MinMortgageAmt) + s.Equal("100000.00000000", resp.AssetDetailList[0].MaxMortgageAmt) + s.Equal("BTC", resp.AssetDetailList[0].Asset) +} + +func (s *marginTestSuite) TestForceLiquidationRecordService() { + data := []byte(`{ + "rows": [ + { + "avgPrice": "0.00333900", + "executedQty": "0.07000000", + "orderId": 1311524, + "price": "0.00333700", + "qty": "0.07000000", + "side": "SELL", + "symbol": "BNBUSDT", + "timeInForce": "GTC", + "isIsolated": false, + "updatedTime": 1620661623199 + }, + { + "avgPrice": "0.00343000", + "executedQty": "0.06000000", + "orderId": 123344, + "price": "0.00343200", + "qty": "0.06000000", + "side": "BUY", + "symbol": "BNBUSDT", + "timeInForce": "GTC", + "isIsolated": false, + "updatedTime": 1620661623167 + } + ], + "total": 2 + }`) + + s.mockDo(data, nil) + defer s.assertDo() + + record, err := s.client.NewForceLiquidationRecordService().Do(context.Background()) + s.r().NoError(err) + + expectedRecord := &ForceLiquidationRecordResponse{ + Rows: []struct { + AvgPrice string `json:"avgPrice"` + ExecutedQty string `json:"executedQty"` + OrderId int `json:"orderId"` + Price string `json:"price"` + Qty string `json:"qty"` + Side string `json:"side"` + Symbol string `json:"symbol"` + TimeInForce string `json:"timeInForce"` + IsIsolated bool `json:"isIsolated"` + UpdatedTime uint64 `json:"updatedTime"` + }{ + { + AvgPrice: "0.00333900", + ExecutedQty: "0.07000000", + OrderId: 1311524, + Price: "0.00333700", + Qty: "0.07000000", + Side: "SELL", + Symbol: "BNBUSDT", + TimeInForce: "GTC", + IsIsolated: false, + UpdatedTime: 1620661623199, + }, + { + AvgPrice: "0.00343000", + ExecutedQty: "0.06000000", + OrderId: 123344, + Price: "0.00343200", + Qty: "0.06000000", + Side: "BUY", + Symbol: "BNBUSDT", + TimeInForce: "GTC", + IsIsolated: false, + UpdatedTime: 1620661623167, + }, + }, + Total: 2, + } + + s.Len(record.Rows, 2) + s.EqualValues(expectedRecord, record) +} + +func (s *marginTestSuite) TestInterestHistory() { + data := []byte(` + { + "rows": [ + { + "txId": 123, + "interestAccruedTime": 1613450271000, + "asset": "BTC", + "rawAsset": "BTC", + "principal": "1.00000000", + "interest": "0.00000005", + "interestRate": "0.00000100", + "type": "NORMAL", + "isolatedSymbol": "" + } + ], + "total": 1 + } + `) + + s.mockDo(data, nil) + defer s.assertDo() + + resp, err := s.client.NewInterestHistoryService(). + Asset("BTC"). + IsolatedSymbol("BTCUSDT"). + StartTime(1613450271000). + EndTime(1613536671000). + Current(1). + Size(500). + Archived("true"). + Do(context.Background()) + + s.r().NoError(err) + s.Len(resp.Rows, 1) + s.Equal(uint64(1613450271000), resp.Rows[0].InterestAccruedTime) + s.Equal("BTC", resp.Rows[0].Asset) + s.Equal("BTC", resp.Rows[0].RawAsset) + s.Equal("1.00000000", resp.Rows[0].Principal) + s.Equal("0.00000005", resp.Rows[0].Interest) + s.Equal("0.00000100", resp.Rows[0].InterestRate) + s.Equal("NORMAL", resp.Rows[0].Type) + s.Equal("", resp.Rows[0].IsolatedSymbol) + s.Equal(1, resp.Total) +} + +func (s *marginTestSuite) TestLoanRecord() { + data := []byte(` + { + "rows": [ + { + "isolatedSymbol": "", + "txId": 123, + "asset": "BTC", + "principal": "1.00000000", + "timestamp": 1613450271000, + "status": "CONFIRMED" + } + ], + "total": 1 + } + `) + + s.mockDo(data, nil) + defer s.assertDo() + + resp, err := s.client.NewLoanRecordService(). + Asset("BTC"). + IsolatedSymbol("BTCUSDT"). + StartTime(1613450271000). + EndTime(1613536671000). + Current(1). + Size(500). + Archived("true"). + Do(context.Background()) + + s.r().NoError(err) + s.Len(resp.Rows, 1) + s.Equal("", resp.Rows[0].IsolatedSymbol) + s.Equal("BTC", resp.Rows[0].Asset) + s.Equal("1.00000000", resp.Rows[0].Principal) + s.Equal(uint64(1613450271000), resp.Rows[0].Timestamp) + s.Equal("CONFIRMED", resp.Rows[0].Status) + s.Equal(1, resp.Total) +} + +func (s *marginTestSuite) TestMarginAccountAllOrderService() { + data := []byte(` + { + "orders": [ + { + "clientOrderId": "example-client-order-id", + "cumulativeQuoteQty": "100.00000000", + "executedQty": "1.00000000", + "icebergQty": "0.00000000", + "isWorking": false, + "orderId": 123, + "origQty": "1.00000000", + "price": "100.00000000", + "side": "BUY", + "status": "FILLED", + "stopPrice": "0.00000000", + "symbol": "BTCUSDT", + "isIsolated": true, + "time": 1613450271000, + "updateTime": 1613450271000 + } + ] + } + `) + + s.mockDo(data, nil) + defer s.assertDo() + + resp, err := s.client.NewMarginAccountAllOrderService(). + Symbol("BTCUSDT"). + IsIsolated("TRUE"). + OrderId(123). + StartTime(1613450271000). + EndTime(1613450271000). + Limit(500). + Do(context.Background()) + + s.r().NoError(err) + s.Len(resp.Orders, 1) + s.Equal("example-client-order-id", resp.Orders[0].ClientOrderId) + s.Equal("100.00000000", resp.Orders[0].CumulativeQuoteQty) + s.Equal("1.00000000", resp.Orders[0].ExecutedQty) + s.Equal("0.00000000", resp.Orders[0].IcebergQty) + s.False(resp.Orders[0].IsWorking) + s.Equal(123, resp.Orders[0].OrderId) + s.Equal("1.00000000", resp.Orders[0].OrigQty) + s.Equal("100.00000000", resp.Orders[0].Price) + s.Equal("BUY", resp.Orders[0].Side) + s.Equal("FILLED", resp.Orders[0].Status) + s.Equal("0.00000000", resp.Orders[0].StopPrice) + s.Equal("BTCUSDT", resp.Orders[0].Symbol) + s.True(resp.Orders[0].IsIsolated) + s.Equal(uint64(1613450271000), resp.Orders[0].Time) + s.Equal(uint64(1613450271000), resp.Orders[0].UpdateTime) +} + +func (s *marginTestSuite) TestMarginAccountCancelAllOrders() { + data := []byte(`{"symbol":"BTCUSDT","isIsolated":false,"origClientOrderId":"a0e0a6f7-8b38-44d5-9dc5-87e3b9bd2d31","orderId":123456789,"orderListId":-1,"clientOrderId":"my_order_id","price":"10000.00000000","origQty":"1.00000000","executedQty":"0.00000000","cumulativeQuoteQty":"0.00000000","status":"CANCELED","timeInForce":"GTC","type":"LIMIT","side":"BUY"}`) + + s.mockDo(data, nil) + defer s.assertDo() + + resp, err := s.client.NewMarginAccountCancelAllOrdersService(). + Symbol("BTCUSDT"). + IsIsolated("false"). + Do(context.Background()) + + s.r().NoError(err) + s.Equal("BTCUSDT", resp.Symbol) + s.False(resp.IsIsolated) + s.Equal("a0e0a6f7-8b38-44d5-9dc5-87e3b9bd2d31", resp.OrigClientOrderId) + s.Equal(123456789, resp.OrderId) + s.Equal(-1, resp.OrderListId) + s.Equal("my_order_id", resp.ClientOrderId) + s.Equal("10000.00000000", resp.Price) + s.Equal("1.00000000", resp.OrigQty) + s.Equal("0.00000000", resp.ExecutedQty) + s.Equal("0.00000000", resp.CumulativeQuoteQty) + s.Equal("CANCELED", resp.Status) + s.Equal("GTC", resp.TimeInForce) + s.Equal("LIMIT", resp.Type) + s.Equal("BUY", resp.Side) +} + +func (s *marginTestSuite) TestMarginAccountCancelOCO() { + data := []byte(` + { + "orderListId": 400000005, + "contingencyType": "OCO", + "listStatusType": "ALL_DONE", + "listOrderStatus": "ALL_DONE", + "listClientOrderId": "twxFWSEZrlzfOeNHDGwOCl", + "transactionTime": 1629187528733, + "symbol": "BNBUSDT", + "isIsolated": false, + "orders": [ + { + "symbol": "BNBUSDT", + "orderId": 2, + "clientOrderId": "EkxGkowgJHXEtlMpoxqtXl" + }, + { + "symbol": "BNBUSDT", + "orderId": 3, + "clientOrderId": "QnTwYPMEnzQKfUwJSaFgWo" + } + ], + "orderReports": [ + { + "symbol": "BNBUSDT", + "origClientOrderId": "my6d5q5u5SxS2fVbYJ1imM", + "orderId": 2, + "orderListId": 400000005, + "clientOrderId": "EkxGkowgJHXEtlMpoxqtXl", + "price": "3600.00000000", + "origQty": "0.00500000", + "executedQty": "0.00000000", + "cummulativeQuoteQty": "0.00000000", + "status": "CANCELED", + "timeInForce": "GTC", + "type": "STOP_LOSS_LIMIT", + "side": "BUY", + "stopPrice": "3700.00000000" + }, + { + "symbol": "BNBUSDT", + "origClientOrderId": "hEgRiLFF2Cv6Gdcy6lSnfE", + "orderId": 3, + "orderListId": 400000005, + "clientOrderId": "QnTwYPMEnzQKfUwJSaFgWo", + "price": "3400.00000000", + "origQty": "0.00500000", + "executedQty": "0.00000000", + "cummulativeQuoteQty": "0.00000000", + "status": "CANCELED", + "timeInForce": "GTC", + "type": "LIMIT_MAKER", + "side": "SELL" + } + ] + } + `) + + s.mockDo(data, nil) + defer s.assertDo() + + resp, err := s.client.NewMarginAccountCancelOCOService(). + Symbol("BNBUSDT"). + OrderListId(400000005). + ListClientOrderId("twxFWSEZrlzfOeNHDGwOCl"). + Do(context.Background()) + + s.r().NoError(err) + s.Equal(400000005, resp.OrderListId) + s.Equal("OCO", resp.ContingencyType) + s.Equal("ALL_DONE", resp.ListStatusType) + s.Equal("ALL_DONE", resp.ListOrderStatus) + s.Equal("twxFWSEZrlzfOeNHDGwOCl", resp.ListClientOrderId) + s.Equal(uint64(1629187528733), resp.TransactionTime) + s.Equal("BNBUSDT", resp.Symbol) + s.False(resp.IsIsolated) + s.Len(resp.Orders, 2) + s.Len(resp.OrderReports, 2) +} + +func (s *marginTestSuite) TestMarginAccountCancelOrder() { + data := []byte(`{ + "symbol": "BTCUSDT", + "isIsolated": false, + "orderId": 12345, + "origClientOrderId": "my_order_id", + "clientOrderId": "new_order_id", + "price": "100.00000000", + "origQty": "1.00000000", + "executedQty": "0.00000000", + "cumulativeQuoteQty": "0.00000000", + "status": "CANCELED", + "timeInForce": "GTC", + "type": "LIMIT", + "side": "BUY" + }`) + + s.mockDo(data, nil) + defer s.assertDo() + + resp, err := s.client.NewMarginAccountCancelOrderService(). + Symbol("BTCUSDT"). + OrderId(12345). + OrigClientOrderId("my_order_id"). + NewClientOrderId("new_order_id"). + Do(context.Background()) + + s.r().NoError(err) + s.Equal("BTCUSDT", resp.Symbol) + s.False(resp.IsIsolated) + s.Equal(12345, resp.OrderId) + s.Equal("my_order_id", resp.OrigClientOrderId) + s.Equal("new_order_id", resp.ClientOrderId) + s.Equal("100.00000000", resp.Price) + s.Equal("1.00000000", resp.OrigQty) + s.Equal("0.00000000", resp.ExecutedQty) + s.Equal("0.00000000", resp.CumulativeQuoteQty) + s.Equal("CANCELED", resp.Status) + s.Equal("GTC", resp.TimeInForce) + s.Equal("LIMIT", resp.Type) + s.Equal("BUY", resp.Side) +} + +func (s *marginTestSuite) TestMarginAccountNewOCO() { + data := []byte(` + { + "orderListId": 0, + "contingencyType": "OCO", + "listStatusType": "EXEC_STARTED", + "listOrderStatus": "EXECUTING", + "listClientOrderId": "xVpDCr1DvuaVwRz8QULNjF", + "transactionTime": 1618776703825, + "symbol": "BTCUSDT", + "orders": [ + { + "symbol": "BTCUSDT", + "orderId": 678101264, + "clientOrderId": "NCPLVlIz4vQ7YDHdkb1V5E" + }, + { + "symbol": "BTCUSDT", + "orderId": 678101265, + "clientOrderId": "OXQ2tX0TUJlDAM7JeKVcZd" + } + ] + } + `) + + s.mockDo(data, nil) + defer s.assertDo() + + resp, err := s.client.NewMarginAccountNewOCOService(). + Symbol("BTCUSDT"). + IsIsolated("false"). + ListClientOrderId("xVpDCr1DvuaVwRz8QULNjF"). + Side("SELL"). + Quantity(1). + LimitClientOrderId("limit-client-order-id"). + Price(40000). + LimitIcebergQty(0.5). + StopClientOrderId("stop-client-order-id"). + StopPrice(50000). + StopLimitPrice(45000). + StopIcebergQty(0.5). + StopLimitTimeInForce("GTC"). + NewOrderRespType("FULL"). + SideEffectType("NO_SIDE_EFFECT"). + Do(context.Background()) + + s.r().NoError(err) + s.Equal(int(0), resp.OrderListId) + s.Equal("OCO", resp.ContingencyType) + s.Equal("EXEC_STARTED", resp.ListStatusType) + s.Equal("EXECUTING", resp.ListOrderStatus) + s.Equal("xVpDCr1DvuaVwRz8QULNjF", resp.ListClientOrderId) + s.Equal(uint64(1618776703825), resp.TransactionTime) + s.Equal("BTCUSDT", resp.Symbol) + s.Len(resp.Orders, 2) + s.Equal("BTCUSDT", resp.Orders[0].Symbol) + s.Equal(int(678101264), resp.Orders[0].OrderId) + s.Equal("NCPLVlIz4vQ7YDHdkb1V5E", resp.Orders[0].ClientOrderId) + s.Equal("BTCUSDT", resp.Orders[1].Symbol) + s.Equal(int(678101265), resp.Orders[1].OrderId) + s.Equal("OXQ2tX0TUJlDAM7JeKVcZd", resp.Orders[1].ClientOrderId) +} + +func (s *marginTestSuite) TestMarginAccountNewOrder() { + data := []byte(`{ + "symbol": "BTCUSDT", + "orderId": 28, + "clientOrderId": "6gCrw2kRUAF9CvJDGP16IP", + "transactTime": 1507725176595, + "price": "1.00000000", + "origQty": "10.00000000", + "executedQty": "10.00000000", + "cummulativeQuoteQty": "10.00000000", + "status": "FILLED", + "timeInForce": "GTC", + "type": "MARKET", + "isIsolated": true, + "side": "SELL" + }`) + + s.mockDo(data, nil) + defer s.assertDo() + + resp, err := s.client.NewMarginAccountNewOrderService(). + Symbol("BTCUSDT"). + Side("SELL"). + Quantity(10.0). + Price(1.00). + NewClientOrderId("6gCrw2kRUAF9CvJDGP16IP"). + TimeInForce("GTC"). + OrderType("MARKET"). + Do(context.Background()) + + s.r().NoError(err) + s.Equal("BTCUSDT", resp.Symbol) + s.Equal(int64(28), resp.OrderId) + s.Equal("6gCrw2kRUAF9CvJDGP16IP", resp.ClientOrderId) + s.Equal(uint64(1507725176595), resp.TransactTime) + s.Equal("1.00000000", resp.Price) + s.Equal("10.00000000", resp.OrigQty) + s.Equal("10.00000000", resp.ExecutedQty) + s.Equal("10.00000000", resp.CumulativeQuoteQty) + s.Equal("FILLED", resp.Status) + s.Equal("GTC", resp.TimeInForce) + s.Equal("MARKET", resp.Type) + s.True(resp.IsIsolated) + s.Equal("SELL", resp.Side) +} + +func (s *marginTestSuite) TestMarginAccountOpenOrder() { + data := []byte(` + { + "orders": [ + { + "clientOrderId": "abc123", + "cumulativeQuoteQty": "1.00000000", + "executedQty": "1.00000000", + "icebergQty": "0.00000000", + "isWorking": false, + "orderId": 123, + "origQty": "1.00000000", + "price": "10000.00000000", + "side": "BUY", + "status": "FILLED", + "stopPrice": "0.00000000", + "symbol": "BTCUSDT", + "isIsolated": false, + "time": 1619549055345, + "timeInForce": "GTC", + "type": "LIMIT", + "updateTime": 1619549055345 + } + ] + } + `) + + s.mockDo(data, nil) + defer s.assertDo() + + resp, err := s.client.NewMarginAccountOpenOrderService(). + Symbol("BTCUSDT"). + IsIsolated("FALSE"). + Do(context.Background()) + + s.r().NoError(err) + s.Len(resp.Orders, 1) + s.Equal("abc123", resp.Orders[0].ClientOrderId) + s.Equal("1.00000000", resp.Orders[0].CumulativeQuoteQty) + s.Equal("1.00000000", resp.Orders[0].ExecutedQty) + s.Equal("0.00000000", resp.Orders[0].IcebergQty) + s.Equal(false, resp.Orders[0].IsWorking) + s.Equal(123, resp.Orders[0].OrderId) + s.Equal("1.00000000", resp.Orders[0].OrigQty) + s.Equal("10000.00000000", resp.Orders[0].Price) + s.Equal("BUY", resp.Orders[0].Side) + s.Equal("FILLED", resp.Orders[0].Status) + s.Equal("0.00000000", resp.Orders[0].StopPrice) + s.Equal("BTCUSDT", resp.Orders[0].Symbol) + s.Equal(false, resp.Orders[0].IsIsolated) + s.Equal(uint64(1619549055345), resp.Orders[0].Time) + s.Equal("GTC", resp.Orders[0].TimeInForce) + s.Equal("LIMIT", resp.Orders[0].OrderType) + s.Equal(uint64(1619549055345), resp.Orders[0].UpdateTime) +} + +func (s *marginTestSuite) TestMarginAccountOrder() { + data := []byte(` + { + "clientOrderId": "myclientorderid", + "cumulativeQuoteQty": "1.00000000", + "executedQty": "1.00000000", + "icebergQty": "0.00000000", + "isWorking": false, + "orderId": 12345, + "origQty": "1.00000000", + "price": "10000.00000000", + "side": "BUY", + "status": "FILLED", + "stopPrice": "0.00000000", + "symbol": "BTCUSDT", + "isIsolated": true, + "time": 1613450271000, + "timeInForce": "GTC", + "type": "LIMIT", + "updateTime": 1613450271000 + } + `) + + s.mockDo(data, nil) + defer s.assertDo() + + resp, err := s.client.NewMarginAccountOrderService(). + Symbol("BTCUSDT"). + IsIsolated("BTC"). + OrderId(12345). + OrigClientOrderId("myclientorderid"). + Do(context.Background()) + + s.r().NoError(err) + s.Equal("myclientorderid", resp.ClientOrderId) + s.Equal("1.00000000", resp.CumulativeQuoteQty) + s.Equal("1.00000000", resp.ExecutedQty) + s.Equal("0.00000000", resp.IcebergQty) + s.False(resp.IsWorking) + s.Equal(12345, resp.OrderId) + s.Equal("1.00000000", resp.OrigQty) + s.Equal("10000.00000000", resp.Price) + s.Equal("BUY", resp.Side) + s.Equal("FILLED", resp.Status) + s.Equal("0.00000000", resp.StopPrice) + s.Equal("BTCUSDT", resp.Symbol) + s.True(resp.IsIsolated) + s.Equal(uint64(1613450271000), resp.Time) + s.Equal("GTC", resp.TimeInForce) + s.Equal("LIMIT", resp.OrderType) + s.Equal(uint64(1613450271000), resp.UpdateTime) +} + +func (s *marginTestSuite) TestMarginAccountQueryOCO() { + data := []byte(` + { + "orderListId": 0, + "contingencyType": "OCO", + "listStatusType": "EXEC_STARTED", + "listOrderStatus": "EXECUTING", + "listClientOrderId": "c3a3c32efeb04d40b42f6e9f2a2b094d", + "transactionTime": 1618856676234, + "symbol": "BTCUSDT", + "isIsolated": false, + "orders": [ + { + "symbol": "BTCUSDT", + "orderId": 2950247107, + "clientOrderId": "O5GLM3Bkg3xy49ATtF8rKX" + }, + { + "symbol": "BTCUSDT", + "orderId": 2950247108, + "clientOrderId": "jKk3m21pJb8wU6TlvF6zAb" + } + ] + } + `) + + s.mockDo(data, nil) + defer s.assertDo() + + resp, err := s.client.NewMarginAccountQueryOCOService(). + IsIsolated("false"). + Symbol("BTCUSDT"). + OrderListId(0). + OrigClientOrderId(""). + Do(context.Background()) + + s.r().NoError(err) + s.Equal(0, resp.OrderListId) + s.Equal("OCO", resp.ContingencyType) + s.Equal("EXEC_STARTED", resp.ListStatusType) + s.Equal("EXECUTING", resp.ListOrderStatus) + s.Equal("c3a3c32efeb04d40b42f6e9f2a2b094d", resp.ListClientOrderId) + s.Equal(uint64(1618856676234), resp.TransactionTime) + s.Equal("BTCUSDT", resp.Symbol) + s.False(resp.IsIsolated) + s.Len(resp.Orders, 2) + s.Equal("BTCUSDT", resp.Orders[0].Symbol) + s.Equal(2950247107, resp.Orders[0].OrderId) + s.Equal("O5GLM3Bkg3xy49ATtF8rKX", resp.Orders[0].ClientOrderId) + s.Equal("BTCUSDT", resp.Orders[1].Symbol) + s.Equal(2950247108, resp.Orders[1].OrderId) + s.Equal("jKk3m21pJb8wU6TlvF6zAb", resp.Orders[1].ClientOrderId) +} + +func (s *marginTestSuite) TestMarginAccountQueryOpenOCO() { + data := []byte(`{ + "orderListId": 1613450271000, + "contingencyType": "OCO", + "listStatusType": "EXEC_STARTED", + "listOrderStatus": "EXECUTING", + "listClientOrderId": "JYVppVf2SgZdG8", + "transactionTime": 1613450271000, + "symbol": "BTCUSDT", + "isIsolated": true, + "orders": [ + { + "symbol": "BTCUSDT", + "orderId": 123, + "clientOrderId": "abc123" + }, + { + "symbol": "BTCUSDT", + "orderId": 456, + "clientOrderId": "def456" + } + ] + }`) + + s.mockDo(data, nil) + defer s.assertDo() + + resp, err := s.client.NewMarginAccountQueryOpenOCOService(). + IsIsolated("true"). + Symbol("BTCUSDT"). + Do(context.Background()) + + s.r().NoError(err) + s.Equal(1613450271000, resp.OrderListId) + s.Equal("OCO", resp.ContingencyType) + s.Equal("EXEC_STARTED", resp.ListStatusType) + s.Equal("EXECUTING", resp.ListOrderStatus) + s.Equal("JYVppVf2SgZdG8", resp.ListClientOrderId) + s.Equal(uint64(1613450271000), resp.TransactionTime) + s.Equal("BTCUSDT", resp.Symbol) + s.True(resp.IsIsolated) + s.Len(resp.Orders, 2) + s.Equal("BTCUSDT", resp.Orders[0].Symbol) + s.Equal(123, resp.Orders[0].OrderId) + s.Equal("abc123", resp.Orders[0].ClientOrderId) + s.Equal("BTCUSDT", resp.Orders[1].Symbol) + s.Equal(456, resp.Orders[1].OrderId) + s.Equal("def456", resp.Orders[1].ClientOrderId) +} + +func (s *marginTestSuite) TestMarginAccountSummary() { + data := []byte(` + { + "normalBar": "10", + "marginCallBar": "20", + "forceLiquidationBar": "30" + } + `) + + s.mockDo(data, nil) + defer s.assertDo() + + resp, err := s.client.NewMarginAccountSummaryService().Do(context.Background()) + + s.r().NoError(err) + s.Equal("10", resp.NormalBar) + s.Equal("20", resp.MarginCallBar) + s.Equal("30", resp.ForceLiquidationBar) +} + +func (s *marginTestSuite) TestMarginBnbBurnStatus() { + data := []byte(` + { + "spotBNBBurn": true, + "interestBNBBurn": true + } + `) + + s.mockDo(data, nil) + defer s.assertDo() + + resp, err := s.client.NewMarginBnbBurnStatusService().Do(context.Background()) + + s.r().NoError(err) + s.True(resp.SpotBNBBurn) + s.True(resp.InterestBNBBurn) +} + +func (s *marginTestSuite) TestMarginCrossCollateralRatio() { + data := []byte(` + [ + { + "collaterals": [ + { + "minUsdValue": "0", + "maxUsdValue": "10000", + "discountRate": "0.9000" + }, + { + "minUsdValue": "10000", + "maxUsdValue": "20000", + "discountRate": "0.8500" + } + ], + "assetNames": [ + { + "asset": "BTC" + }, + { + "asset": "ETH" + } + ] + } + ] + `) + + s.mockDo(data, nil) + defer s.assertDo() + + resp, err := s.client.NewMarginCrossCollateralRatioService().Do(context.Background()) + + s.r().NoError(err) + s.Len(resp[0].Collaterals, 2) + s.Equal("0", resp[0].Collaterals[0].MinUsdValue) + s.Equal("10000", resp[0].Collaterals[0].MaxUsdValue) + s.Equal("0.9000", resp[0].Collaterals[0].DiscountRate) + s.Equal("10000", resp[0].Collaterals[1].MinUsdValue) + s.Equal("20000", resp[0].Collaterals[1].MaxUsdValue) + s.Equal("0.8500", resp[0].Collaterals[1].DiscountRate) + s.Len(resp[0].AssetNames, 2) + s.Equal("BTC", resp[0].AssetNames[0].Asset) + s.Equal("ETH", resp[0].AssetNames[1].Asset) +} + +func (s *marginTestSuite) TestMarginCrossMarginFee() { + data := []byte(`[ + { + "vipLevel": 0, + "coin": "BTC", + "transferIn": true, + "transferOut": true, + "dailyInterest": "0.00001000", + "yearlyInterest": "0.36500000", + "borrowLimit": "0.00000000", + "marginablePairs": { + "pair": "BTCBUSD" + } + } + ]`) + + s.mockDo(data, nil) + defer s.assertDo() + + resp, err := s.client.NewMarginCrossMarginFeeService(). + Coin("BTC"). + VipLevel(0). + Do(context.Background()) + + s.r().NoError(err) + s.Len(resp, 1) + s.Equal(0, resp[0].VIPLevel) + s.Equal("BTC", resp[0].Coin) + s.True(resp[0].TransferIn) + s.True(resp[0].Borrowable) + s.Equal("0.00001000", resp[0].DailyInterest) + s.Equal("0.36500000", resp[0].YearlyInterest) + s.Equal("0.00000000", resp[0].BorrowLimit) + s.Equal("BTCBUSD", resp[0].MarginablePairs.Pair) +} + +func (s *marginTestSuite) TestMarginCurrentOrderCount() { + data := []byte(` + [ + { + "rateLimitType": "REQUEST_WEIGHT", + "interval": "MINUTE", + "intervalNum": 1, + "limit": 1200, + "count": 0 + } + ] + `) + + s.mockDo(data, nil) + defer s.assertDo() + + resp, err := s.client.NewMarginCurrentOrderCountService(). + Symbol("BTCUSDT"). + IsIsolated("TRUE"). + Do(context.Background()) + + s.r().NoError(err) + s.Len(resp, 1) + s.Equal("REQUEST_WEIGHT", resp[0].RateLimitType) + s.Equal("MINUTE", resp[0].Interval) + s.Equal(1, resp[0].IntervalNum) + s.Equal(1200, resp[0].Limit) + s.Equal(0, resp[0].Count) +} + +func (s *marginTestSuite) TestListDustLog() { + data := []byte(` + { + "total": 8, + "userAssetDribblets": [ + { + "totalTransferedAmount": "0.00132256", + "totalServiceChargeAmount": "0.00002699", + "transId": 45178372831, + "userAssetDribbletDetails": [ + { + "transId": 4359321, + "serviceChargeAmount": "0.000009", + "amount": "0.0009", + "operateTime": 1615985535000, + "transferedAmount": "0.000441", + "fromAsset": "USDT" + }, + { + "transId": 4359321, + "serviceChargeAmount": "0.00001799", + "amount": "0.0009", + "operateTime": 1615985535000, + "transferedAmount": "0.00088156", + "fromAsset": "ETH" + } + ] + }, + { + "operateTime":1616203180000, + "totalTransferedAmount": "0.00058795", + "totalServiceChargeAmount": "0.000012", + "transId": 4357015, + "userAssetDribbletDetails": [ + { + "transId": 4357015, + "serviceChargeAmount": "0.00001", + "amount": "0.001", + "operateTime": 1616203180000, + "transferedAmount": "0.00049", + "fromAsset": "USDT" + }, + { + "transId": 4357015, + "serviceChargeAmount": "0.000002", + "amount": "0.0001", + "operateTime": 1616203180000, + "transferedAmount": "0.00009795", + "fromAsset": "ETH" + } + ] + } + ] + } + `) + s.mockDo(data, nil) + defer s.assertDo() + + s.assertReq(func(r *request) { + e := newSignedRequest() + s.assertRequestEqual(e, r) + }) + + res, err := s.client.NewMarginDustlogService().Do(context.Background()) + r := s.r() + r.NoError(err) + rows := res.UserAssetDribblets + s.Len(rows, 2) + s.Len(rows[0].UserAssetDribbletDetails, 2) + s.Len(rows[1].UserAssetDribbletDetails, 2) + + s.assertUserAssetDribbletEqual(&UserAssetDribblet{ + TotalTransferedAmount: "0.00132256", + TotalServiceChargeAmount: "0.00002699", + TransId: 45178372831, + UserAssetDribbletDetails: []UserAssetDribbletDetail{ + { + TransId: 4359321, + ServiceChargeAmount: "0.000009", + Amount: "0.0009", + OperateTime: 1615985535000, + TransferedAmount: "0.000441", + FromAsset: "USDT", + }, + { + TransId: 4359321, + ServiceChargeAmount: "0.00001799", + Amount: "0.0009", + OperateTime: 1615985535000, + TransferedAmount: "0.00088156", + FromAsset: "ETH", + }, + }, + }, &rows[0]) + s.assertUserAssetDribbletEqual(&UserAssetDribblet{ + TotalTransferedAmount: "0.00058795", + TotalServiceChargeAmount: "0.000012", + TransId: 4357015, + UserAssetDribbletDetails: []UserAssetDribbletDetail{ + { + TransId: 4357015, + ServiceChargeAmount: "0.00001", + Amount: "0.001", + OperateTime: 1616203180000, + TransferedAmount: "0.00049", + FromAsset: "USDT", + }, + { + TransId: 4357015, + ServiceChargeAmount: "0.000002", + Amount: "0.0001", + OperateTime: 1616203180000, + TransferedAmount: "0.00009795", + FromAsset: "ETH", + }, + }, + OperateTime: 1616203180000, + }, &rows[1]) +} + +func (s *marginTestSuite) assertUserAssetDribbletEqual(e, a *UserAssetDribblet) { + r := s.r() + r.Equal(e.TotalTransferedAmount, a.TotalTransferedAmount, `TotalTransferedAmount`) + r.Equal(e.TotalServiceChargeAmount, a.TotalServiceChargeAmount, `TotalServiceChargeAmount`) + r.Equal(e.TransId, a.TransId, `TransID`) + s.assertUserAssetDribbletDetailEqual(&e.UserAssetDribbletDetails[0], &a.UserAssetDribbletDetails[0]) + s.assertUserAssetDribbletDetailEqual(&e.UserAssetDribbletDetails[1], &a.UserAssetDribbletDetails[1]) + r.Equal(e.OperateTime, a.OperateTime, `OperateTime`) +} + +func (s *marginTestSuite) assertUserAssetDribbletDetailEqual(e, a *UserAssetDribbletDetail) { + r := s.r() + r.Equal(e.TransId, a.TransId, `TransID`) + r.Equal(e.ServiceChargeAmount, a.ServiceChargeAmount, `ServiceChargeAmount`) + r.Equal(e.Amount, a.Amount, `Amount`) + r.Equal(e.OperateTime, a.OperateTime, `OperateTime`) + r.Equal(e.TransferedAmount, a.TransferedAmount, `TransferedAmount`) + r.Equal(e.FromAsset, a.FromAsset, `FromAsset`) +} + +func (s *marginTestSuite) TestMarginInterestRateHistory() { + data := []byte(` + [ + { + "asset": "BTC", + "vipLevel": 0, + "timestamp": 1616697600000, + "dailyInterestRate": 0.00025000 + }, + { + "asset": "BNB", + "vipLevel": 0, + "timestamp": 1616697600000, + "dailyInterestRate": 0.00100000 + } + ] + `) + + s.mockDo(data, nil) + defer s.assertDo() + + resp, err := s.client.NewMarginInterestRateHistoryService(). + Asset("BTC"). + VipLevel(0). + StartTime(1616697600000). + EndTime(1616784000000). + Do(context.Background()) + + s.r().NoError(err) + s.Len(resp, 2) + s.Equal("BTC", resp[0].Asset) + s.Equal(0.00025, resp[0].DailyInterestRate) + s.Equal(uint64(1616697600000), resp[0].Timestamp) + s.Equal(0, resp[0].VIPLevel) + + s.Equal("BNB", resp[1].Asset) + s.Equal(0.001, resp[1].DailyInterestRate) + s.Equal(uint64(1616697600000), resp[1].Timestamp) + s.Equal(0, resp[1].VIPLevel) +} + +func (s *marginTestSuite) TestMarginIsolatedAccountDisable() { + data := []byte(`{"success": true}`) + + s.mockDo(data, nil) + defer s.assertDo() + + resp, err := s.client.NewMarginIsolatedAccountDisableService(). + Symbol("BTCUSDT"). + Do(context.Background()) + + s.r().NoError(err) + s.Equal(true, resp.Success) +} + +func (s *marginTestSuite) TestMarginIsolatedAccountEnable() { + data := []byte(`{"success": true}`) + + s.mockDo(data, nil) + defer s.assertDo() + + resp, err := s.client.NewMarginIsolatedAccountEnableService(). + Symbol("BTCUSDT"). + Do(context.Background()) + + s.r().NoError(err) + s.Equal(true, resp.Success) +} + +func (s *marginTestSuite) TestMarginIsolatedAccountInfo() { + data := []byte(` + { + "assets": [ + { + "baseAsset": { + "asset": "BNB", + "borrowEnabled": true, + "free": "0.00000000", + "interest": "0.00000000", + "locked": "0.00000000", + "netAsset": "0.00000000", + "netAssetOfBtc": "0.00000000", + "repayEnabled": true, + "totalAsset": "0.00000000" + }, + "quoteAsset": { + "asset": "USDT", + "borrowEnabled": true, + "free": "10000.00000000", + "interest": "0.00000000", + "locked": "0.00000000", + "netAsset": "10000.00000000", + "netAssetOfBtc": "10000.00000000", + "repayEnabled": true, + "totalAsset": "10000.00000000" + }, + "symbol": "BNBUSDT", + "isolatedCreated": true, + "enabled": true, + "marginLevel": "0.00000", + "marginLevelStatus": "EXCESSIVE", + "marginRatio": "0.00000", + "indexPrice": "48.81190000", + "liquidatePrice": "0.00000000", + "liquidateRate": "0.00000000", + "tradeEnabled": true + } + ] + } + `) + + s.mockDo(data, nil) + defer s.assertDo() + + resp, err := s.client.NewMarginIsolatedAccountInfoService().Do(context.Background()) + s.r().NoError(err) + s.Len(resp.Assets, 1) + + baseAsset := resp.Assets[0].BaseAsset + s.Equal("BNB", baseAsset.Asset) + s.True(baseAsset.BorrowEnabled) + s.Equal("0.00000000", baseAsset.Free) + s.Equal("0.00000000", baseAsset.Interest) + s.Equal("0.00000000", baseAsset.Locked) + s.Equal("0.00000000", baseAsset.NetAsset) + s.Equal("0.00000000", baseAsset.NetAssetOfBtc) + s.True(baseAsset.RepayEnabled) + s.Equal("0.00000000", baseAsset.TotalAsset) + + quoteAsset := resp.Assets[0].QuoteAsset + s.Equal("USDT", quoteAsset.Asset) + s.True(quoteAsset.BorrowEnabled) + s.Equal("10000.00000000", quoteAsset.Free) + s.Equal("0.00000000", quoteAsset.Interest) + s.Equal("0.00000000", quoteAsset.Locked) + s.Equal("10000.00000000", quoteAsset.NetAsset) + s.Equal("10000.00000000", quoteAsset.NetAssetOfBtc) + s.True(quoteAsset.RepayEnabled) + s.Equal("10000.00000000", quoteAsset.TotalAsset) + + s.Equal("BNBUSDT", resp.Assets[0].Symbol) + s.True(resp.Assets[0].IsolatedCreated) + s.True(resp.Assets[0].Enabled) + s.Equal("0.00000", resp.Assets[0].MarginLevel) + s.Equal("EXCESSIVE", resp.Assets[0].MarginLevelStatus) + s.Equal("0.00000", resp.Assets[0].MarginRatio) + s.Equal("48.81190000", resp.Assets[0].IndexPrice) + s.Equal("0.00000000", resp.Assets[0].LiquidatePrice) + s.Equal("0.00000000", resp.Assets[0].LiquidateRate) + s.True(resp.Assets[0].TradeEnabled) +} + +func (s *marginTestSuite) TestMarginIsolatedAccountLimit() { + data := []byte(` + { + "enabledAccount": 5, + "maxAccount": 10 + } + `) + + s.mockDo(data, nil) + defer s.assertDo() + + resp, err := s.client.NewMarginIsolatedAccountLimitService().Do(context.Background()) + + s.r().NoError(err) + s.Equal(5, resp.EnabledAccount) + s.Equal(10, resp.MaxAccount) +} + +func (s *marginTestSuite) TestMarginIsolatedAccountTransfer() { + data := []byte(`{"tranId":"12345"}`) + s.mockDo(data, nil) + defer s.assertDo() + + resp, err := s.client.NewMarginIsolatedAccountTransferService(). + Asset("BTC"). + Symbol("BTCUSDT"). + TransFrom("BTC"). + TransTo("USDT"). + Amount(1.0). + Do(context.Background()) + + s.r().NoError(err) + s.Equal("12345", resp.TranId) +} + +func (s *marginTestSuite) TestMarginIsolatedAccountTransferHistory() { + data := []byte(`{ + "rows": [ + { + "amount": "1.0", + "asset": "BTC", + "status": "CONFIRMED", + "timestamp": 1527777532000, + "txId": 100000001, + "transferId": 200000001, + "transFrom": "ETH", + "transTo": "BTC" + }, + { + "amount": "2.0", + "asset": "BTC", + "status": "CONFIRMED", + "type": "ROLL_OUT", + "timestamp": 1527777532000, + "txId": 100000002, + "transferId": 200000002, + "transFrom": "BTC", + "transTo": "ETH" + } + ], + "total": 2 + }`) + + s.mockDo(data, nil) + defer s.assertDo() + + resp, err := s.client.NewMarginIsolatedAccountTransferHistoryService(). + Symbol("BTCUSDT"). + Asset("BTC"). + TransFrom("BTC"). + TransTo("ETH"). + StartTime(1527777532000). + EndTime(1527777532000). + Current(1). + Size(500). + Archived("true"). + Do(context.Background()) + + s.r().NoError(err) + s.Len(resp.Rows, 2) + s.Equal("BTC", resp.Rows[0].Asset) + s.Equal("1.0", resp.Rows[0].Amount) + s.Equal("CONFIRMED", resp.Rows[0].Status) + s.Equal(uint64(1527777532000), resp.Rows[0].TimeStamp) + s.Equal(int64(100000001), resp.Rows[0].TxId) + s.Equal("ETH", resp.Rows[0].TransFrom) + s.Equal("BTC", resp.Rows[0].TransTo) + s.Equal("BTC", resp.Rows[1].Asset) + s.Equal("2.0", resp.Rows[1].Amount) + s.Equal("CONFIRMED", resp.Rows[1].Status) + s.Equal(uint64(1527777532000), resp.Rows[1].TimeStamp) + s.Equal(int64(100000002), resp.Rows[1].TxId) + s.Equal("BTC", resp.Rows[1].TransFrom) + s.Equal("ETH", resp.Rows[1].TransTo) + s.Equal(int64(2), resp.Total) +} + +func (s *marginTestSuite) TestMarginIsolatedMarginFee() { + data := []byte(` + [ + { + "vipLevel": 0, + "symbol": "BTCUSDT", + "leverage": "3", + "data": { + "coin": "BTC", + "dailyInterest": "0.0015", + "borrowLimit": "1.00000000" + } + }, + { + "vipLevel": 1, + "symbol": "BTCUSDT", + "leverage": "5", + "data": { + "coin": "BTC", + "dailyInterest": "0.0014", + "borrowLimit": "2.00000000" + } + } + ] + `) + + s.mockDo(data, nil) + defer s.assertDo() + + resp, err := s.client.NewMarginIsolatedMarginFeeService(). + Symbol("BTCUSDT"). + VipLevel(0). + Do(context.Background()) + + s.r().NoError(err) + s.Len(resp, 2) + + s.Equal(0, resp[0].VIPLevel) + s.Equal("BTCUSDT", resp[0].Symbol) + s.Equal("3", resp[0].Leverage) + s.Equal("BTC", resp[0].Data.Coin) + s.Equal("0.0015", resp[0].Data.DailyInterest) + s.Equal("1.00000000", resp[0].Data.BorrowLimit) + + s.Equal(1, resp[1].VIPLevel) + s.Equal("BTCUSDT", resp[1].Symbol) + s.Equal("5", resp[1].Leverage) + s.Equal("BTC", resp[1].Data.Coin) + s.Equal("0.0014", resp[1].Data.DailyInterest) + s.Equal("2.00000000", resp[1].Data.BorrowLimit) +} + +func (s *marginTestSuite) TestMarginIsolatedMarginTier() { + data := []byte(` + [ + { + "symbol": "BTCUSDT", + "tier": 1, + "effectiveMultiple": "5", + "initialRiskRatio": "150", + "liquidationRiskRatio": "110", + "baseAssetMaxBorrowable": "0.10000000", + "quoteAssetMaxBorrowable": "50.00000000" + } + ] + `) + + s.mockDo(data, nil) + defer s.assertDo() + + resp, err := s.client.NewMarginIsolatedMarginTierService(). + Symbol("BTCUSDT"). + Tier(1). + Do(context.Background()) + + s.r().NoError(err) + s.Len(resp, 1) + s.Equal("BTCUSDT", resp[0].Symbol) + s.Equal(1, resp[0].Tier) + s.Equal("5", resp[0].EffectiveMultiple) + s.Equal("150", resp[0].InitialRiskRatio) + s.Equal("110", resp[0].LiquidationRiskRatio) + s.Equal("0.10000000", resp[0].BaseAssetMaxBorrowable) + s.Equal("50.00000000", resp[0].QuoteAssetMaxBorrowable) +} + +func (s *marginTestSuite) TestMarginIsolatedSymbol() { + data := []byte(`{ + "symbol": "BTCUSDT", + "base": "BTC", + "quote": "USDT", + "isMarginTrade": true, + "isBuyAllowed": true, + "isSellAllowed": true + }`) + + s.mockDo(data, nil) + defer s.assertDo() + + resp, err := s.client.NewMarginIsolatedSymbolService(). + Symbol("BTCUSDT"). + Do(context.Background()) + + s.r().NoError(err) + s.Equal("BTCUSDT", resp.Symbol) + s.Equal("BTC", resp.Base) + s.Equal("USDT", resp.Quote) + s.True(resp.IsMarginTrade) + s.True(resp.IsBuyAllowed) + s.True(resp.IsSellAllowed) +} + +func (s *marginTestSuite) TestMarginSmallLiabilityExchange() { + data := []byte(`[{}]`) + s.mockDo(data, nil) + defer s.assertDo() + + resp, err := s.client.NewMarginSmallLiabilityExchangeService(). + AssetNames("BTC"). + Do(context.Background()) + + s.r().NoError(err) + s.Len(resp, 1) +} + +func (s *marginTestSuite) TestMarginSmallLiabilityExchangeCoinList() { + data := []byte(` + [ + { + "asset": "BTC", + "interest": "0.00000005", + "principal": "1.00000000", + "liabilityOfBUSD": "0.00000000" + }, + { + "asset": "ETH", + "interest": "0.00000000", + "principal": "0.00000000", + "liabilityOfBUSD": "0.00000000" + } + ] + `) + + s.mockDo(data, nil) + defer s.assertDo() + + resp, err := s.client.NewMarginSmallLiabilityExchangeCoinListService().Do(context.Background()) + + s.r().NoError(err) + s.Len(resp, 2) + s.Equal("BTC", resp[0].Asset) + s.Equal("0.00000005", resp[0].Interest) + s.Equal("1.00000000", resp[0].Principal) + s.Equal("0.00000000", resp[0].LiabilityOfBUSD) + s.Equal("ETH", resp[1].Asset) + s.Equal("0.00000000", resp[1].Interest) + s.Equal("0.00000000", resp[1].Principal) + s.Equal("0.00000000", resp[1].LiabilityOfBUSD) +} + +func (s *marginTestSuite) TestMarginSmallLiabilityExchangeHistory() { + data := []byte(`[ + { + "total": 1, + "rows": [ + { + "asset": "BTC", + "amount": "1.00000000", + "targetAsset": "USDT", + "targetAmount": "50000.00000000", + "bizType": "REPAY", + "timestamp": 1613450271000 + } + ] + } + ]`) + + s.mockDo(data, nil) + defer s.assertDo() + + resp, err := s.client.NewMarginSmallLiabilityExchangeHistoryService(). + Current(1). + Size(500). + StartTime(1613450271000). + EndTime(1613536671000). + Do(context.Background()) + + s.r().NoError(err) + s.Len(resp, 1) + s.Equal(1, resp[0].Total) + s.Len(resp[0].Rows, 1) + s.Equal("BTC", resp[0].Rows[0].Asset) + s.Equal("1.00000000", resp[0].Rows[0].Amount) + s.Equal("USDT", resp[0].Rows[0].TargetAsset) + s.Equal("50000.00000000", resp[0].Rows[0].TargetAmount) + s.Equal("REPAY", resp[0].Rows[0].BizType) + s.Equal(uint64(1613450271000), resp[0].Rows[0].Timestamp) +} + +func (s *marginTestSuite) TestMarginToggleBnbBurn() { + data := []byte(`{"spotBNBBurn":true,"interestBNBBurn":false}`) + s.mockDo(data, nil) + defer s.assertDo() + + resp, err := s.client.NewMarginToggleBnbBurnService(). + SpotBNBBurn("true"). + InterestBNBBurn("false"). + Do(context.Background()) + + s.r().NoError(err) + s.Equal(true, resp.SpotBNBBurn) + s.Equal(false, resp.InterestBNBBurn) +} + +func (s *marginTestSuite) TestQueryCrossMarginPair() { + data := []byte(` + { + "symbolDetail": { + "symbol": "BTCUSDT", + "isMarginTrade": true, + "isBuyAllowed": true, + "isSellAllowed": true + } + }`) + + s.mockDo(data, nil) + defer s.assertDo() + + resp, err := s.client.NewQueryCrossMarginPairService(). + Symbol("BTCUSDT"). + Do(context.Background()) + + s.r().NoError(err) + s.Equal("BTCUSDT", resp.SymbolDetail.Symbol) + s.True(resp.SymbolDetail.IsMarginTrade) + s.True(resp.SymbolDetail.IsBuyAllowed) + s.True(resp.SymbolDetail.IsSellAllowed) +} + +func (s *marginTestSuite) TestQueryMarginAsset() { + data := []byte(` + { + "assetFullName": "Bitcoin", + "assetName": "BTC", + "isBorrowable": true, + "isMortgageable": true, + "userMinBorrow": "0.00100000", + "userMinRepay": "0.00000000" + } + `) + + s.mockDo(data, nil) + defer s.assertDo() + + resp, err := s.client.NewQueryMarginAssetService(). + Asset("BTC"). + Do(context.Background()) + + s.r().NoError(err) + s.Equal("Bitcoin", resp.FullName) + s.Equal("BTC", resp.Name) + s.True(resp.Borrowable) + s.True(resp.Mortgageable) + s.Equal("0.00100000", resp.UserMinBorrow) + s.Equal("0.00000000", resp.UserMinRepay) +} + +func (s *marginTestSuite) TestRepayRecord() { + data := []byte(` + { + "rows": [ + { + "isolatedSymbol": "BTCUSDT", + "amount": "1.00000000", + "asset": "BTC", + "interest": "0.00000005", + "principal": "1.00000000", + "status": "CONFIRMED", + "timestamp": 1613450271000, + "txId": 123 + } + ], + "total": 1 + } + `) + + s.mockDo(data, nil) + defer s.assertDo() + + resp, err := s.client.NewRepayRecordService(). + Asset("BTC"). + IsolatedSymbol("BTCUSDT"). + StartTime(1613450271000). + EndTime(1613536671000). + Current(1). + Size(500). + Archived("true"). + Do(context.Background()) + + s.r().NoError(err) + s.Len(resp.Rows, 1) + s.Equal("BTCUSDT", resp.Rows[0].IsolatedSymbol) + s.Equal("1.00000000", resp.Rows[0].Amount) + s.Equal("BTC", resp.Rows[0].Asset) + s.Equal("0.00000005", resp.Rows[0].Interest) + s.Equal("1.00000000", resp.Rows[0].Principal) + s.Equal("CONFIRMED", resp.Rows[0].Status) + s.Equal(uint64(1613450271000), resp.Rows[0].Timestamp) + s.Equal(1, resp.Total) +} diff --git a/market.go b/market.go new file mode 100644 index 0000000..3d5fde6 --- /dev/null +++ b/market.go @@ -0,0 +1,908 @@ +package binance_connector + +import ( + "context" + "encoding/json" + "math/big" + "net/http" +) + +// Binance Test Connectivity endpoint (GET /api/v3/ping) +type Ping struct { + c *Client +} + +// Send the request +func (s *Ping) Do(ctx context.Context, opts ...RequestOption) (err error) { + r := &request{ + method: http.MethodGet, + endpoint: "/api/v3/ping", + secType: secTypeNone, + } + _, err = s.c.callAPI(ctx, r, opts...) + if err != nil { + return err + } + return nil +} + +// Binance Check Server Time endpoint (GET /api/v3/time) +type ServerTime struct { + c *Client +} + +// Send the request +func (s *ServerTime) Do(ctx context.Context, opts ...RequestOption) (res *ServerTimeResponse, err error) { + r := &request{ + method: http.MethodGet, + endpoint: "/api/v3/time", + secType: secTypeNone, + } + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return nil, err + } + res = new(ServerTimeResponse) + err = json.Unmarshal(data, res) + if err != nil { + return nil, err + } + return res, nil +} + +// ServerTimeResponse define server time response +type ServerTimeResponse struct { + ServerTime uint64 `json:"serverTime"` +} + +// Binance Exchange Information endpoint (GET /api/v3/exchangeInfo) +type ExchangeInfo struct { + c *Client +} + +// Send the request +func (s *ExchangeInfo) Do(ctx context.Context, opts ...RequestOption) (res *ExchangeInfoResponse, err error) { + r := &request{ + method: http.MethodGet, + endpoint: "/api/v3/exchangeInfo", + secType: secTypeNone, + } + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return nil, err + } + res = new(ExchangeInfoResponse) + err = json.Unmarshal(data, res) + if err != nil { + return nil, err + } + return res, nil +} + +// ExchangeInfoResponse define exchange info response +type ExchangeInfoResponse struct { + Timezone string `json:"timezone"` + ServerTime uint64 `json:"serverTime"` + RateLimits []*RateLimit `json:"rateLimits"` + ExchangeFilters []*ExchangeFilter `json:"exchangeFilters"` + Symbols []*SymbolInfo `json:"symbols"` +} + +// RateLimit define rate limit +type RateLimit struct { + RateLimitType string `json:"rateLimitType"` + Interval string `json:"interval"` + Limit int `json:"limit"` +} + +// ExchangeFilter define exchange filter +type ExchangeFilter struct { + FilterType string `json:"filterType"` + MaxNumAlgo int64 `json:"maxNumAlgoOrders"` +} + +// Symbol define symbol +type SymbolInfo struct { + Symbol string `json:"symbol"` + Status string `json:"status"` + BaseAsset string `json:"baseAsset"` + BaseAssetPrecision int64 `json:"baseAssetPrecision"` + QuoteAsset string `json:"quoteAsset"` + QuotePrecision int64 `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 []*SymbolFilter `json:"filters"` + Permissions []string `json:"permissions"` +} + +// SymbolFilter define symbol filter +type SymbolFilter struct { + FilterType string `json:"filterType"` + MinPrice string `json:"minPrice"` + MaxPrice string `json:"maxPrice"` + TickSize string `json:"tickSize"` + MinQty string `json:"minQty"` + MaxQty string `json:"maxQty"` + StepSize string `json:"stepSize"` + MinNotional string `json:"minNotional"` + Limit uint `json:"limit"` + MaxNumAlgoOrders int64 `json:"maxNumAlgoOrders"` +} + +// Binance Order Book endpoint (GET /api/v3/depth) +type OrderBook struct { + c *Client + symbol string + limit *int +} + +// Symbol set symbol +func (s *OrderBook) Symbol(symbol string) *OrderBook { + s.symbol = symbol + return s +} + +// Limit set limit +func (s *OrderBook) Limit(limit int) *OrderBook { + s.limit = &limit + return s +} + +// Send the request +func (s *OrderBook) Do(ctx context.Context, opts ...RequestOption) (res *OrderBookResponse, err error) { + r := &request{ + method: http.MethodGet, + endpoint: "/api/v3/depth", + secType: secTypeNone, + } + r.setParam("symbol", s.symbol) + if s.limit != nil { + r.setParam("limit", *s.limit) + } + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return nil, err + } + res = new(OrderBookResponse) + err = json.Unmarshal(data, res) + if err != nil { + return nil, err + } + return res, nil +} + +// OrderBookResponse define order book response +type OrderBookResponse struct { + LastUpdateId uint64 `json:"lastUpdateId"` + Bids [][]*big.Float `json:"bids"` + Asks [][]*big.Float `json:"asks"` +} + +// Binance Recent Trades List endpoint (GET /api/v3/trades) +type RecentTradesList struct { + c *Client + symbol string + limit *int +} + +// Symbol set symbol +func (s *RecentTradesList) Symbol(symbol string) *RecentTradesList { + s.symbol = symbol + return s +} + +// Limit set limit +func (s *RecentTradesList) Limit(limit int) *RecentTradesList { + s.limit = &limit + return s +} + +// Send the request +func (s *RecentTradesList) Do(ctx context.Context, opts ...RequestOption) (res []*RecentTradesListResponse, err error) { + r := &request{ + method: http.MethodGet, + endpoint: "/api/v3/trades", + secType: secTypeNone, + } + r.setParam("symbol", s.symbol) + if s.limit != nil { + r.setParam("limit", *s.limit) + } + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return nil, err + } + err = json.Unmarshal(data, &res) + if err != nil { + return nil, err + } + return res, nil +} + +// RecentTradesListResponse define recent trades list response +type RecentTradesListResponse struct { + Id uint64 `json:"id"` + Price string `json:"price"` + Qty string `json:"qty"` + Time uint64 `json:"time"` + QuoteQty string `json:"quoteQty"` + IsBuyerMaker bool `json:"isBuyerMaker"` + IsBest bool `json:"isBestMatch"` +} + +// Binance Old Trade Lookup endpoint (GET /api/v3/historicalTrades) +type HistoricalTradeLookup struct { + c *Client + symbol string + limit *uint + fromId *int64 +} + +// Symbol set symbol +func (s *HistoricalTradeLookup) Symbol(symbol string) *HistoricalTradeLookup { + s.symbol = symbol + return s +} + +// Limit set limit +func (s *HistoricalTradeLookup) Limit(limit uint) *HistoricalTradeLookup { + s.limit = &limit + return s +} + +// FromId set fromId +func (s *HistoricalTradeLookup) FromId(fromId int64) *HistoricalTradeLookup { + s.fromId = &fromId + return s +} + +// Send the request +func (s *HistoricalTradeLookup) Do(ctx context.Context, opts ...RequestOption) (res []*RecentTradesListResponse, err error) { + r := &request{ + method: http.MethodGet, + endpoint: "/api/v3/historicalTrades", + secType: secTypeAPIKey, + } + r.setParam("symbol", s.symbol) + if s.limit != nil { + r.setParam("limit", *s.limit) + } + if s.fromId != nil { + r.setParam("fromId", *s.fromId) + } + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return nil, err + } + err = json.Unmarshal(data, &res) + if err != nil { + return nil, err + } + return res, nil +} + +// Binance Compressed/Aggregate Trades List endpoint (GET /api/v3/aggTrades) +type AggTradesList struct { + c *Client + symbol string + limit *int + fromId *int + startTime *uint64 + endTime *uint64 +} + +// Symbol set symbol +func (s *AggTradesList) Symbol(symbol string) *AggTradesList { + s.symbol = symbol + return s +} + +// Limit set limit +func (s *AggTradesList) Limit(limit int) *AggTradesList { + s.limit = &limit + return s +} + +// FromId set fromId +func (s *AggTradesList) FromId(fromId int) *AggTradesList { + s.fromId = &fromId + return s +} + +// StartTime set startTime +func (s *AggTradesList) StartTime(startTime uint64) *AggTradesList { + s.startTime = &startTime + return s +} + +// EndTime set endTime +func (s *AggTradesList) EndTime(endTime uint64) *AggTradesList { + s.endTime = &endTime + return s +} + +// Send the request +func (s *AggTradesList) Do(ctx context.Context, opts ...RequestOption) (res []*AggTradesListResponse, err error) { + r := &request{ + method: http.MethodGet, + endpoint: "/api/v3/aggTrades", + secType: secTypeNone, + } + r.setParam("symbol", s.symbol) + if s.limit != nil { + r.setParam("limit", *s.limit) + } + if s.fromId != nil { + r.setParam("fromId", *s.fromId) + } + if s.startTime != nil { + r.setParam("startTime", *s.startTime) + } + if s.endTime != nil { + r.setParam("endTime", *s.endTime) + } + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return nil, err + } + err = json.Unmarshal(data, &res) + if err != nil { + return nil, err + } + return res, nil +} + +// AggTradesListResponse define compressed trades list response +type AggTradesListResponse struct { + AggTradeId uint64 `json:"a"` + Price string `json:"p"` + Qty string `json:"q"` + FirstTradeId uint64 `json:"f"` + LastTradeId uint64 `json:"l"` + Time uint64 `json:"T"` + IsBuyer bool `json:"m"` + IsBest bool `json:"M"` +} + +// Binance Kline/Candlestick Data endpoint (GET /api/v3/klines) +type Klines struct { + c *Client + symbol string + interval string + limit *int + startTime *uint64 + endTime *uint64 +} + +// Symbol set symbol +func (s *Klines) Symbol(symbol string) *Klines { + s.symbol = symbol + return s +} + +// Interval set interval +func (s *Klines) Interval(interval string) *Klines { + s.interval = interval + return s +} + +// Limit set limit +func (s *Klines) Limit(limit int) *Klines { + s.limit = &limit + return s +} + +// StartTime set startTime +func (s *Klines) StartTime(startTime uint64) *Klines { + s.startTime = &startTime + return s +} + +// EndTime set endTime +func (s *Klines) EndTime(endTime uint64) *Klines { + s.endTime = &endTime + return s +} + +func (s *Klines) Do(ctx context.Context, opts ...RequestOption) (res []*KlinesResponse, err error) { + r := &request{ + method: http.MethodGet, + endpoint: "/api/v3/klines", + secType: secTypeNone, + } + r.setParam("symbol", s.symbol) + r.setParam("interval", s.interval) + if s.limit != nil { + r.setParam("interval", *s.limit) + } + if s.startTime != nil { + r.setParam("startTime", *s.startTime) + } + if s.endTime != nil { + r.setParam("endTime", *s.endTime) + } + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return nil, err + } + var klinesResponseArray KlinesResponseArray + err = json.Unmarshal(data, &klinesResponseArray) + if err != nil { + return nil, err + } + var klines []*KlinesResponse + for _, kline := range klinesResponseArray { + openTime := kline[0].(float64) + open := kline[1].(string) + high := kline[2].(string) + low := kline[3].(string) + close := kline[4].(string) + volume := kline[5].(string) + closeTime := kline[6].(float64) + quoteAssetVolume := kline[7].(string) + numberOfTrades := kline[8].(float64) + takerBuyBaseAssetVolume := kline[9].(string) + takerBuyQuoteAssetVolume := kline[10].(string) + + // create a KlinesResponse struct using the parsed fields + klinesResponse := &KlinesResponse{ + OpenTime: uint64(openTime), + Open: open, + High: high, + Low: low, + Close: close, + Volume: volume, + CloseTime: uint64(closeTime), + QuoteAssetVolume: quoteAssetVolume, + NumberOfTrades: uint64(numberOfTrades), + TakerBuyBaseAssetVolume: takerBuyBaseAssetVolume, + TakerBuyQuoteAssetVolume: takerBuyQuoteAssetVolume, + } + klines = append(klines, klinesResponse) + } + return klines, nil +} + +type KlinesResponseArray [][]interface{} + +// Define Klines response data +type KlinesResponse struct { + OpenTime uint64 `json:"openTime"` + Open string `json:"open"` + High string `json:"high"` + Low string `json:"low"` + Close string `json:"close"` + Volume string `json:"volume"` + CloseTime uint64 `json:"closeTime"` + QuoteAssetVolume string `json:"quoteAssetVolume"` + NumberOfTrades uint64 `json:"numberOfTrades"` + TakerBuyBaseAssetVolume string `json:"takerBuyBaseAssetVolume"` + TakerBuyQuoteAssetVolume string `json:"takerBuyQuoteAssetVolume"` +} + +// Binance UI Klines GET /api/v3/uiKlines +type UiKlines struct { + c *Client + symbol string + interval string + limit *int + startTime *uint64 + endTime *uint64 +} + +// Symbol set symbol +func (s *UiKlines) Symbol(symbol string) *UiKlines { + s.symbol = symbol + return s +} + +// Interval set interval +func (s *UiKlines) Interval(interval string) *UiKlines { + s.interval = interval + return s +} + +// Limit set limit +func (s *UiKlines) Limit(limit int) *UiKlines { + s.limit = &limit + return s +} + +// StartTime set startTime +func (s *UiKlines) StartTime(startTime uint64) *UiKlines { + s.startTime = &startTime + return s +} + +// EndTime set endTime +func (s *UiKlines) EndTime(endTime uint64) *UiKlines { + s.endTime = &endTime + return s +} + +// Send the request +func (s *UiKlines) Do(ctx context.Context, opts ...RequestOption) (res []*UiKlinesResponse, err error) { + r := &request{ + method: http.MethodGet, + endpoint: "/api/v3/uiKlines", + secType: secTypeNone, + } + r.setParam("symbol", s.symbol) + r.setParam("interval", s.interval) + if s.limit != nil { + r.setParam("interval", *s.limit) + } + if s.startTime != nil { + r.setParam("startTime", *s.startTime) + } + if s.endTime != nil { + r.setParam("endTime", *s.endTime) + } + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return nil, err + } + var uiklinesResponseArray UiKlinesResponseArray + err = json.Unmarshal(data, &uiklinesResponseArray) + if err != nil { + return nil, err + } + var uiklines []*UiKlinesResponse + for _, uikline := range uiklinesResponseArray { + openTime := uikline[0].(float64) + open := uikline[1].(string) + high := uikline[2].(string) + low := uikline[3].(string) + close := uikline[4].(string) + volume := uikline[5].(string) + closeTime := uikline[6].(float64) + quoteAssetVolume := uikline[7].(string) + numberOfTrades := uikline[8].(float64) + takerBuyBaseAssetVolume := uikline[9].(string) + takerBuyQuoteAssetVolume := uikline[10].(string) + + // create a KlinesResponse struct using the parsed fields + uiklinesResponse := &UiKlinesResponse{ + OpenTime: uint64(openTime), + Open: open, + High: high, + Low: low, + Close: close, + Volume: volume, + CloseTime: uint64(closeTime), + QuoteAssetVolume: quoteAssetVolume, + NumberOfTrades: uint64(numberOfTrades), + TakerBuyBaseAssetVolume: takerBuyBaseAssetVolume, + TakerBuyQuoteAssetVolume: takerBuyQuoteAssetVolume, + } + uiklines = append(uiklines, uiklinesResponse) + } + return uiklines, nil +} + +type UiKlinesResponseArray [][]interface{} + +// Define UiKlines response data +type UiKlinesResponse struct { + OpenTime uint64 `json:"openTime"` + Open string `json:"open"` + High string `json:"high"` + Low string `json:"low"` + Close string `json:"close"` + Volume string `json:"volume"` + CloseTime uint64 `json:"closeTime"` + QuoteAssetVolume string `json:"quoteAssetVolume"` + NumberOfTrades uint64 `json:"numberOfTrades"` + TakerBuyBaseAssetVolume string `json:"takerBuyBaseAssetVolume"` + TakerBuyQuoteAssetVolume string `json:"takerBuyQuoteAssetVolume"` +} + +// Binance Current Average Price (GET /api/v3/avgPrice) +type AvgPrice struct { + c *Client + symbol string +} + +// Symbol set symbol +func (s *AvgPrice) Symbol(symbol string) *AvgPrice { + s.symbol = symbol + return s +} + +// Send the request +func (s *AvgPrice) Do(ctx context.Context, opts ...RequestOption) (res *AvgPriceResponse, err error) { + r := &request{ + method: http.MethodGet, + endpoint: "/api/v3/avgPrice", + secType: secTypeNone, + } + r.setParam("symbol", s.symbol) + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return nil, err + } + res = new(AvgPriceResponse) + err = json.Unmarshal(data, res) + if err != nil { + return nil, err + } + return res, nil +} + +// Define AvgPrice response data +type AvgPriceResponse struct { + Mins uint64 `json:"mins"` + Price string `json:"price"` +} + +// Binance 24hr Ticker Price Change Statistics (GET /api/v3/ticker/24hr) +type Ticker24hr struct { + c *Client + symbol *string + symbols *[]string +} + +// Symbol set symbol +func (s *Ticker24hr) Symbol(symbol string) *Ticker24hr { + s.symbol = &symbol + return s +} + +// Symbols set symbols +func (s *Ticker24hr) Symbols(symbols []string) *Ticker24hr { + s.symbols = &symbols + return s +} + +// Send the request +func (s *Ticker24hr) Do(ctx context.Context, opts ...RequestOption) (res *Ticker24hrResponse, err error) { + r := &request{ + method: http.MethodGet, + endpoint: "/api/v3/ticker/24hr", + secType: secTypeNone, + } + if s.symbol != nil { + r.setParam("symbol", *s.symbol) + } + if s.symbols != nil { + r.setParam("symbols", *s.symbols) + } + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return nil, err + } + res = new(Ticker24hrResponse) + err = json.Unmarshal(data, res) + if err != nil { + return nil, err + } + return res, nil +} + +// Define Ticker24hr response data +type Ticker24hrResponse struct { + Symbol string `json:"symbol"` + PriceChange string `json:"priceChange"` + PriceChangePercent string `json:"priceChangePercent"` + WeightedAvgPrice string `json:"weightedAvgPrice"` + PrevClosePrice string `json:"prevClosePrice"` + LastPrice string `json:"lastPrice"` + LastQty string `json:"lastQty"` + BidPrice string `json:"bidPrice"` + AskPrice string `json:"askPrice"` + OpenPrice string `json:"openPrice"` + HighPrice string `json:"highPrice"` + LowPrice string `json:"lowPrice"` + Volume string `json:"volume"` + QuoteVolume string `json:"quoteVolume"` + OpenTime uint64 `json:"openTime"` + CloseTime uint64 `json:"closeTime"` + FirstId uint64 `json:"firstId"` + LastId uint64 `json:"lastId"` + Count uint64 `json:"count"` +} + +// Binance Symbol Price Ticker (GET /api/v3/ticker/price) +type TickerPrice struct { + c *Client + symbol *string + symbols *[]string +} + +// Symbol set symbol +func (s *TickerPrice) Symbol(symbol string) *TickerPrice { + s.symbol = &symbol + return s +} + +// Symbols set symbols +func (s *TickerPrice) Symbols(symbols []string) *TickerPrice { + s.symbols = &symbols + return s +} + +// Send the request +func (s *TickerPrice) Do(ctx context.Context, opts ...RequestOption) (res *TickerPriceResponse, err error) { + r := &request{ + method: http.MethodGet, + endpoint: "/api/v3/ticker/price", + secType: secTypeNone, + } + if s.symbol != nil { + r.setParam("symbol", *s.symbol) + } + if s.symbols != nil { + r.setParam("symbols", *s.symbols) + } + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return nil, err + } + res = new(TickerPriceResponse) + err = json.Unmarshal(data, res) + if err != nil { + return nil, err + } + return res, nil +} + +// Define TickerPrice response data +type TickerPriceResponse struct { + Symbol string `json:"symbol"` + Price string `json:"price"` +} + +// Binance Symbol Order Book Ticker (GET /api/v3/ticker/bookTicker) +type TickerBookTicker struct { + c *Client + symbol *string + symbols *[]string +} + +// Symbol set symbol +func (s *TickerBookTicker) Symbol(symbol string) *TickerBookTicker { + s.symbol = &symbol + return s +} + +// Symbols set symbols +func (s *TickerBookTicker) Symbols(symbols []string) *TickerBookTicker { + s.symbols = &symbols + return s +} + +/* +func (s *ListBookTickersService) Do(ctx context.Context, opts ...RequestOption) (res []*BookTicker, err error) { + r := &request{ + method: http.MethodGet, + endpoint: "/api/v3/ticker/bookTicker", + } + if s.symbol != nil { + r.setParam("symbol", *s.symbol) + } + data, err := s.c.callAPI(ctx, r, opts...) + data = common.ToJSONList(data) + if err != nil { + return []*BookTicker{}, err + } + res = make([]*BookTicker, 0) + err = json.Unmarshal(data, &res) + if err != nil { + return []*BookTicker{}, err + } + return res, nil +} +*/ +// Send the request +func (s *TickerBookTicker) Do(ctx context.Context, opts ...RequestOption) (res []*TickerBookTickerResponse, err error) { + r := &request{ + method: http.MethodGet, + endpoint: "/api/v3/ticker/bookTicker", + secType: secTypeNone, + } + if s.symbol != nil { + r.setParam("symbol", *s.symbol) + } + if s.symbols != nil { + s, _ := json.Marshal(s.symbols) + r.setParam("symbols", string(s)) + } + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return []*TickerBookTickerResponse{}, err + } + res = make([]*TickerBookTickerResponse, 0) + err = json.Unmarshal(data, &res) + if err != nil { + return []*TickerBookTickerResponse{}, err + } + return res, nil +} + +// Define TickerBookTicker response data +type TickerBookTickerResponse struct { + Symbol string `json:"symbol"` + BidPrice string `json:"bidPrice"` + BidQty string `json:"bidQty"` + AskPrice string `json:"askPrice"` + AskQty string `json:"askQty"` +} + +// Binance Rolling window price change statistics (GET /api/v3/ticker) +type Ticker struct { + c *Client + symbol string + windowSize *string + tickerType *string +} + +// Symbol set symbol +func (s *Ticker) Symbol(symbol string) *Ticker { + s.symbol = symbol + return s +} + +// WindowSize set windowSize +func (s *Ticker) WindowSize(windowSize string) *Ticker { + s.windowSize = &windowSize + return s +} + +// Type set type +func (s *Ticker) Type(tickerType string) *Ticker { + s.tickerType = &tickerType + return s +} + +// Send the request +func (s *Ticker) Do(ctx context.Context, opts ...RequestOption) (res *TickerResponse, err error) { + r := &request{ + method: http.MethodGet, + endpoint: "/api/v3/ticker", + secType: secTypeNone, + } + r.setParam("symbol", s.symbol) + if s.windowSize != nil { + r.setParam("windowSize", *s.windowSize) + } + if s.tickerType != nil { + r.setParam("type", *s.tickerType) + } + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return nil, err + } + res = new(TickerResponse) + err = json.Unmarshal(data, res) + if err != nil { + return nil, err + } + return res, nil +} + +// Define Ticker response data +type TickerResponse struct { + Symbol string `json:"symbol"` + PriceChange string `json:"priceChange"` + PriceChangePercent string `json:"priceChangePercent"` + WeightedAvgPrice string `json:"weightedAvgPrice"` + PrevClosePrice string `json:"prevClosePrice"` + LastPrice string `json:"lastPrice"` + LastQty string `json:"lastQty"` + BidPrice string `json:"bidPrice"` + AskPrice string `json:"askPrice"` + OpenPrice string `json:"openPrice"` + HighPrice string `json:"highPrice"` + LowPrice string `json:"lowPrice"` + Volume string `json:"volume"` + QuoteVolume string `json:"quoteVolume"` + OpenTime uint64 `json:"openTime"` + CloseTime uint64 `json:"closeTime"` + FirstId uint64 `json:"firstId"` + LastId uint64 `json:"lastId"` + Count uint64 `json:"count"` +} diff --git a/market_test.go b/market_test.go new file mode 100644 index 0000000..af0af5c --- /dev/null +++ b/market_test.go @@ -0,0 +1,380 @@ +package binance_connector + +import ( + "testing" + + "github.com/stretchr/testify/suite" +) + +type marketTestSuite struct { + baseTestSuite +} + +func TestMarket(t *testing.T) { + suite.Run(t, new(marketTestSuite)) +} + +func (s *marketTestSuite) TestPing() { + data := []byte(`{}`) + s.mockDo(data, nil) + defer s.assertDo() + + s.assertReq(func(r *request) { + e := newRequest() + s.assertRequestEqual(e, r) + }) + + err := s.client.NewPingService().Do(newContext()) + s.r().NoError(err) +} + +func (s *marketTestSuite) TestAggTradesList() { + data := []byte(`[ + { + "a": 26129, + "p": "0.01633102", + "q": "4.70443515", + "f": 27781, + "l": 27781, + "T": 1498793709153, + "m": true, + "M": true + } + ]`) + s.mockDo(data, nil) + defer s.assertDo() + + symbol := "LTCBTC" + fromID := int(1) + startTime := uint64(1498793709153) + endTime := uint64(1498793709156) + limit := 1 + s.assertReq(func(r *request) { + e := newRequest().setParams(params{ + "symbol": symbol, + "fromId": fromID, + "startTime": startTime, + "endTime": endTime, + "limit": limit, + }) + s.assertRequestEqual(e, r) + }) + + aggTrades, err := s.client.NewAggTradesListService().Symbol(symbol). + FromId(fromID).StartTime(startTime).EndTime(endTime).Limit(limit). + Do(newContext()) + r := s.r() + r.NoError(err) + r.Len(aggTrades, 1) + e := &AggTradesListResponse{ + AggTradeId: 26129, + Price: "0.01633102", + Qty: "4.70443515", + FirstTradeId: 27781, + LastTradeId: 27781, + Time: 1498793709153, + IsBuyer: true, + IsBest: true, + } + s.assertAggTradeEqual(e, aggTrades[0]) +} + +func (s *marketTestSuite) assertAggTradeEqual(e, a *AggTradesListResponse) { + r := s.r() + r.Equal(e.AggTradeId, a.AggTradeId, "AggTradeID") + r.Equal(e.Price, a.Price, "Price") + r.Equal(e.Qty, a.Qty, "Quantity") + r.Equal(e.FirstTradeId, a.FirstTradeId, "FirstTradeID") + r.Equal(e.LastTradeId, a.LastTradeId, "LastTradeID") + r.Equal(e.Time, a.Time, "Timestamp") + r.Equal(e.IsBuyer, a.IsBuyer, "IsBuyerMaker") + r.Equal(e.IsBest, a.IsBest, "IsBestPriceMatch") +} + +func (s *marketTestSuite) TestServerTime() { + data := []byte(`{ + "serverTime": 1499827319559 + }`) + s.mockDo(data, nil) + defer s.assertDo() + + s.assertReq(func(r *request) { + e := newRequest() + s.assertRequestEqual(e, r) + }) + + serverTime, err := s.client.NewServerTimeService().Do(newContext()) + + e1 := &ServerTimeResponse{ + ServerTime: 1499827319559, + } + s.r().NoError(err) + s.assertServerTimeEqual(e1, serverTime) +} + +func (s *marketTestSuite) assertServerTimeEqual(e, a *ServerTimeResponse) { + r := s.r() + r.Equal(e.ServerTime, a.ServerTime, "ServerTime") +} + +func (s *marketTestSuite) TestExchangeInfo() { + +} + +func (s *marketTestSuite) TestListBookTickers() { + data := []byte(`[ + { + "symbol": "LTCBTC", + "bidPrice": "4.00000000", + "bidQty": "431.00000000", + "askPrice": "4.00000200", + "askQty": "9.00000000" + }, + { + "symbol": "ETHBTC", + "bidPrice": "0.07946700", + "bidQty": "9.00000000", + "askPrice": "100000.00000000", + "askQty": "1000.00000000" + } + ]`) + s.mockDo(data, nil) + defer s.assertDo() + + s.assertReq(func(r *request) { + e := newRequest() + s.assertRequestEqual(e, r) + }) + + tickers, err := s.client.NewTickerBookTickerService().Do(newContext()) + r := s.r() + r.NoError(err) + r.Len(tickers, 2) + e1 := &TickerBookTickerResponse{ + Symbol: "LTCBTC", + BidPrice: "4.00000000", + BidQty: "431.00000000", + AskPrice: "4.00000200", + AskQty: "9.00000000", + } + e2 := &TickerBookTickerResponse{ + Symbol: "ETHBTC", + BidPrice: "0.07946700", + BidQty: "9.00000000", + AskPrice: "100000.00000000", + AskQty: "1000.00000000", + } + s.assertBookTickerEqual(e1, tickers[0]) + s.assertBookTickerEqual(e2, tickers[1]) +} + +func (s *marketTestSuite) assertBookTickerEqual(e, a *TickerBookTickerResponse) { + r := s.r() + r.Equal(e.Symbol, a.Symbol, "Symbol") + r.Equal(e.BidPrice, a.BidPrice, "BidPrice") + r.Equal(e.BidQty, a.BidQty, "BidQuantity") + r.Equal(e.AskPrice, a.AskPrice, "AskPrice") + r.Equal(e.AskQty, a.AskQty, "AskQuantity") +} + +func (s *marketTestSuite) TestRecentTrades() { + data := []byte(`[ + { + "id": 28457, + "price": "4.00000100", + "qty": "12.00000000", + "quoteQty": "48.000012", + "time": 1499865549590, + "isBuyerMaker": true, + "isBestMatch": true + } + ]`) + s.mockDo(data, nil) + defer s.assertDo() + + symbol := "LTCBTC" + limit := 3 + s.assertReq(func(r *request) { + e := newRequest().setParams(params{ + "symbol": symbol, + "limit": limit, + }) + s.assertRequestEqual(e, r) + }) + + trades, err := s.client.NewRecentTradesListService().Symbol(symbol).Limit(limit).Do(newContext()) + r := s.r() + r.NoError(err) + r.Len(trades, 1) + e := &RecentTradesListResponse{ + Id: 28457, + Price: "4.00000100", + Qty: "12.00000000", + QuoteQty: "48.000012", + Time: 1499865549590, + IsBuyerMaker: true, + IsBest: true, + } + s.assertTradeEqual(e, trades[0]) +} + +func (s *marketTestSuite) assertTradeEqual(e, a *RecentTradesListResponse) { + r := s.r() + r.Equal(e.Id, a.Id, "ID") + r.Equal(e.Price, a.Price, "Price") + r.Equal(e.Qty, a.Qty, "Qty") + r.Equal(e.QuoteQty, a.QuoteQty, "QuoteQty") + r.Equal(e.Time, a.Time, "Time") + r.Equal(e.IsBuyerMaker, a.IsBuyerMaker, "IsBuyerMaker") + r.Equal(e.IsBest, a.IsBest, "IsBest") +} + +func (s *marketTestSuite) TestHistoricalTrades() { + data := []byte(`[ + { + "id": 28457, + "price": "4.00000100", + "qty": "12.00000000", + "quoteQty": "48.000012", + "time": 1499865549590, + "isBuyerMaker": true, + "isBestMatch": true + } + ]`) + s.mockDo(data, nil) + defer s.assertDo() + + symbol := "LTCBTC" + limit := uint(3) + fromId := int64(1) + s.assertReq(func(r *request) { + e := newRequest().setParams(params{ + "symbol": symbol, + "limit": limit, + "fromId": fromId, + }) + s.assertRequestEqual(e, r) + }) + + trades, err := s.client.NewHistoricalTradeLookupService().Symbol(symbol). + Limit(limit).FromId(fromId).Do(newContext()) + r := s.r() + r.NoError(err) + r.Len(trades, 1) + e := &RecentTradesListResponse{ + Id: 28457, + Price: "4.00000100", + Qty: "12.00000000", + QuoteQty: "48.000012", + Time: 1499865549590, + IsBuyerMaker: true, + IsBest: true, + } + s.assertTradeEqual(e, trades[0]) +} + +func (s *marketTestSuite) TestAveragePrice() { + data := []byte(`{ + "mins": 5, + "price": "9.35751834" + }`) + s.mockDo(data, nil) + defer s.assertDo() + + symbol := "LTCBTC" + s.assertReq(func(r *request) { + e := newRequest().setParam("symbol", symbol) + s.assertRequestEqual(e, r) + }) + + res, err := s.client.NewAvgPriceService().Symbol(symbol).Do(newContext()) + r := s.r() + r.NoError(err) + e := &AvgPriceResponse{ + Mins: 5, + Price: "9.35751834", + } + s.assertAvgPrice(e, res) +} + +func (s *marketTestSuite) assertAvgPrice(e, a *AvgPriceResponse) { + s.r().Equal(e.Mins, a.Mins, "Mins") + s.r().Equal(e.Price, a.Price, "Price") +} + +func (s *marketTestSuite) Test24hrTicker() { + data := []byte(`{ + "symbol": "BNBBTC", + "priceChange": "-94.99999800", + "priceChangePercent": "-95.960", + "weightedAvgPrice": "0.29628482", + "prevClosePrice": "0.10002000", + "lastPrice": "4.00000200", + "lastQty": "200.00000000", + "bidPrice": "4.00000000", + "askPrice": "4.00000200", + "openPrice": "99.00000000", + "highPrice": "100.00000000", + "lowPrice": "0.10000000", + "volume": "8913.30000000", + "openTime": 1499783499040, + "closeTime": 1499869899040, + "firstId": 28385, + "lastId": 28460, + "count": 76 + }`) + s.mockDo(data, nil) + defer s.assertDo() + + symbol := "BNBBTC" + s.assertReq(func(r *request) { + e := newRequest().setParam("symbol", symbol) + s.assertRequestEqual(e, r) + }) + stats, err := s.client.NewTicker24hrService().Symbol(symbol).Do(newContext()) + r := s.r() + r.NoError(err) + e := &Ticker24hrResponse{ + Symbol: "BNBBTC", + PriceChange: "-94.99999800", + PriceChangePercent: "-95.960", + WeightedAvgPrice: "0.29628482", + PrevClosePrice: "0.10002000", + LastPrice: "4.00000200", + LastQty: "200.00000000", + BidPrice: "4.00000000", + AskPrice: "4.00000200", + OpenPrice: "99.00000000", + HighPrice: "100.00000000", + LowPrice: "0.10000000", + Volume: "8913.30000000", + OpenTime: 1499783499040, + CloseTime: 1499869899040, + FirstId: 28385, + LastId: 28460, + Count: 76, + } + s.assertPriceChangeStatsEqual(e, stats) +} + +func (s *marketTestSuite) assertPriceChangeStatsEqual(e, a *Ticker24hrResponse) { + r := s.r() + r.Equal(e.Symbol, a.Symbol, "Symbol") + r.Equal(e.PriceChange, a.PriceChange, "PriceChange") + r.Equal(e.PriceChangePercent, a.PriceChangePercent, "PriceChangePercent") + r.Equal(e.WeightedAvgPrice, a.WeightedAvgPrice, "WeightedAvgPrice") + r.Equal(e.PrevClosePrice, a.PrevClosePrice, "PrevClosePrice") + r.Equal(e.LastPrice, a.LastPrice, "LastPrice") + r.Equal(e.LastQty, a.LastQty, "LastQty") + r.Equal(e.BidPrice, a.BidPrice, "BidPrice") + r.Equal(e.AskPrice, a.AskPrice, "AskPrice") + r.Equal(e.OpenPrice, a.OpenPrice, "OpenPrice") + r.Equal(e.HighPrice, a.HighPrice, "HighPrice") + r.Equal(e.LowPrice, a.LowPrice, "LowPrice") + r.Equal(e.Volume, a.Volume, "Volume") + r.Equal(e.OpenTime, a.OpenTime, "OpenTime") + r.Equal(e.CloseTime, a.CloseTime, "CloseTime") + r.Equal(e.FirstId, a.FirstId, "FristID") + r.Equal(e.LastId, a.LastId, "LastID") + r.Equal(e.Count, a.Count, "Count") +} diff --git a/request.go b/request.go new file mode 100644 index 0000000..3d99cbc --- /dev/null +++ b/request.go @@ -0,0 +1,115 @@ +package binance_connector + +import ( + "fmt" + "io" + "net/http" + "net/url" +) + +type secType int + +const ( + secTypeNone secType = iota + secTypeAPIKey + secTypeSigned // if the 'timestamp' parameter is required +) + +type params map[string]interface{} + +// request define an API request +type request struct { + method string + endpoint string + query url.Values + form url.Values + recvWindow int64 + secType secType + header http.Header + body io.Reader + fullURL string +} + +// addParam add param with key/value to query string +func (r *request) addParam(key string, value interface{}) *request { + if r.query == nil { + r.query = url.Values{} + } + r.query.Add(key, fmt.Sprintf("%v", value)) + return r +} + +// setParam set param with key/value to query string +func (r *request) setParam(key string, value interface{}) *request { + if r.query == nil { + r.query = url.Values{} + } + r.query.Set(key, fmt.Sprintf("%v", value)) + return r +} + +// setParams set params with key/values to query string +func (r *request) setParams(m params) *request { + for k, v := range m { + r.setParam(k, v) + } + return r +} + +// setFormParam set param with key/value to request form body +func (r *request) setFormParam(key string, value interface{}) *request { + if r.form == nil { + r.form = url.Values{} + } + r.form.Set(key, fmt.Sprintf("%v", value)) + return r +} + +// setFormParams set params with key/values to request form body +func (r *request) setFormParams(m params) *request { + for k, v := range m { + r.setFormParam(k, v) + } + return r +} + +func (r *request) validate() (err error) { + if r.query == nil { + r.query = url.Values{} + } + if r.form == nil { + r.form = url.Values{} + } + return nil +} + +// RequestOption define option type for request +type RequestOption func(*request) + +// WithRecvWindow set recvWindow param for the request +func WithRecvWindow(recvWindow int64) RequestOption { + return func(r *request) { + r.recvWindow = recvWindow + } +} + +// WithHeader set or add a header value to the request +func WithHeader(key, value string, replace bool) RequestOption { + return func(r *request) { + if r.header == nil { + r.header = http.Header{} + } + if replace { + r.header.Set(key, value) + } else { + r.header.Add(key, value) + } + } +} + +// WithHeaders set or replace the headers of the request +func WithHeaders(header http.Header) RequestOption { + return func(r *request) { + r.header = header.Clone() + } +} diff --git a/scripts/checks.sh b/scripts/checks.sh new file mode 100755 index 0000000..617a7b6 --- /dev/null +++ b/scripts/checks.sh @@ -0,0 +1,46 @@ +#!/bin/bash + +set -e + +ACTION=$1 + +function format() { + echo "Running gofmt ..." + if [[ $1 == "-w" ]]; then + gofmt -w $(find . -type f -name '*.go' -not -path "./vendor/*") + elif [[ $1 == "-l" ]]; then + gofmt -l $(find . -type f -name '*.go' -not -path "./vendor/*") + else + test -z "$(gofmt -l $(find . -type f -name '*.go' -not -path "./vendor/*"))" + fi +} + +function lint() { + echo "Running golint ..." + go install golang.org/x/lint/golint + golint -set_exit_status ./... +} + +function vet() { + echo "Running go vet ..." + ( + go vet ./... + ) +} + +function unittest() { + echo "Running go test ..." + ( + go test -v -race -coverprofile=coverage.txt -covermode=atomic ./... + ) +} + +if [[ -z $ACTION ]]; then + format + # lint + vet + unittest +else + shift + $ACTION "$@" +fi diff --git a/subaccount.go b/subaccount.go new file mode 100644 index 0000000..9d61c66 --- /dev/null +++ b/subaccount.go @@ -0,0 +1,2632 @@ +package binance_connector + +import ( + "context" + "encoding/json" + "net/http" + "strconv" +) + +// Create a Virtual Sub-account(For Master Account) +const ( + enableSubAccountEndpoint = "/sapi/v1/sub-account/virtualSubAccount" +) + +type CreateSubAccountService struct { + c *Client + subAccountString string +} + +func (s *CreateSubAccountService) SubAccountString(subAccountString string) *CreateSubAccountService { + s.subAccountString = subAccountString + return s +} + +func (s *CreateSubAccountService) Do(ctx context.Context) (res *CreateSubAccountResp, err error) { + r := &request{ + method: http.MethodPost, + endpoint: enableSubAccountEndpoint, + secType: secTypeSigned, + } + r.setParam("subAccountString", s.subAccountString) + data, err := s.c.callAPI(ctx, r) + if err != nil { + return nil, err + } + res = new(CreateSubAccountResp) + err = json.Unmarshal(data, res) + if err != nil { + return nil, err + } + return res, nil +} + +type CreateSubAccountResp struct { + Email string `json:"email"` +} + +// Query Sub-account List (For Master Account) +const ( + querySubAccountListEndpoint = "/sapi/v1/sub-account/list" +) + +type QuerySubAccountListService struct { + c *Client + email *string + isFreeze *string + page *int + limit *int +} + +func (s *QuerySubAccountListService) Email(email string) *QuerySubAccountListService { + s.email = &email + return s +} + +func (s *QuerySubAccountListService) IsFreeze(isFreeze string) *QuerySubAccountListService { + s.isFreeze = &isFreeze + return s +} + +func (s *QuerySubAccountListService) Page(page int) *QuerySubAccountListService { + s.page = &page + return s +} + +func (s *QuerySubAccountListService) Limit(limit int) *QuerySubAccountListService { + s.limit = &limit + return s +} + +func (s *QuerySubAccountListService) Do(ctx context.Context) (res *SubAccountListResp, err error) { + r := &request{ + method: http.MethodGet, + endpoint: querySubAccountListEndpoint, + secType: secTypeSigned, + } + if s.email != nil { + r.setParam("email", s.email) + } + if s.isFreeze != nil { + r.setParam("isFreeze", s.isFreeze) + } + if s.page != nil { + r.setParam("page", s.page) + } + if s.limit != nil { + r.setParam("limit", s.limit) + } + data, err := s.c.callAPI(ctx, r) + if err != nil { + return nil, err + } + res = new(SubAccountListResp) + err = json.Unmarshal(data, res) + if err != nil { + return nil, err + } + return res, nil +} + +type SubAccountListResp struct { + SubAccounts []SubAccount `json:"subAccounts"` +} + +type SubAccount struct { + Email string `json:"email"` + IsFreeze bool `json:"isFreeze"` + CreateTime uint64 `json:"createTime"` + IsManagedSubAccount bool `json:"isManagedSubAccount"` + IsAssetManagementSubAccount bool `json:"isAssetManagementSubAccount"` +} + +// Query Sub-account Spot Asset Transfer History (For Master Account) +const ( + querySubAccountSpotAssetTransferHistoryEndpoint = "/sapi/v1/sub-account/sub/transfer/history" +) + +type QuerySubAccountSpotAssetTransferHistoryService struct { + c *Client + fromEmail *string + toEmail *string + startTime *uint64 + endTime *uint64 + page *int + limit *int +} + +func (s *QuerySubAccountSpotAssetTransferHistoryService) FromEmail(fromEmail string) *QuerySubAccountSpotAssetTransferHistoryService { + s.fromEmail = &fromEmail + return s +} + +func (s *QuerySubAccountSpotAssetTransferHistoryService) ToEmail(toEmail string) *QuerySubAccountSpotAssetTransferHistoryService { + s.toEmail = &toEmail + return s +} + +func (s *QuerySubAccountSpotAssetTransferHistoryService) StartTime(startTime uint64) *QuerySubAccountSpotAssetTransferHistoryService { + s.startTime = &startTime + return s +} + +func (s *QuerySubAccountSpotAssetTransferHistoryService) EndTime(endTime uint64) *QuerySubAccountSpotAssetTransferHistoryService { + s.endTime = &endTime + return s +} + +func (s *QuerySubAccountSpotAssetTransferHistoryService) Page(page int) *QuerySubAccountSpotAssetTransferHistoryService { + s.page = &page + return s +} + +func (s *QuerySubAccountSpotAssetTransferHistoryService) Limit(limit int) *QuerySubAccountSpotAssetTransferHistoryService { + s.limit = &limit + return s +} + +func (s *QuerySubAccountSpotAssetTransferHistoryService) Do(ctx context.Context) (res *QuerySubAccountSpotAssetTransferHistoryResp, err error) { + r := &request{ + method: http.MethodGet, + endpoint: querySubAccountSpotAssetTransferHistoryEndpoint, + secType: secTypeSigned, + } + if s.fromEmail != nil { + r.setParam("fromEmail", s.fromEmail) + } + if s.toEmail != nil { + r.setParam("toEmail", s.toEmail) + } + if s.startTime != nil { + r.setParam("startTime", s.startTime) + } + if s.endTime != nil { + r.setParam("endTime", s.endTime) + } + if s.page != nil { + r.setParam("page", s.page) + } + if s.limit != nil { + r.setParam("limit", s.limit) + } + data, err := s.c.callAPI(ctx, r) + if err != nil { + return nil, err + } + res = new(QuerySubAccountSpotAssetTransferHistoryResp) + err = json.Unmarshal(data, res) + if err != nil { + return nil, err + } + return res, nil +} + +type QuerySubAccountSpotAssetTransferHistoryResp struct { + Rows []struct { + From string `json:"from"` + To string `json:"to"` + Asset string `json:"asset"` + Qty string `json:"qty"` + Status string `json:"status"` + TranId int64 `json:"tranId"` + Time uint64 `json:"time"` + } +} + +// Query Sub-account Futures Asset Transfer History (For Master Account) +const ( + querySubAccountFuturesAssetTransferHistoryEndpoint = "/sapi/v1/sub-account/futures/internalTransfer" +) + +type QuerySubAccountFuturesAssetTransferHistoryService struct { + c *Client + email string + futuresType int + startTime *uint64 + endTime *uint64 + page *int + limit *int +} + +func (s *QuerySubAccountFuturesAssetTransferHistoryService) Email(email string) *QuerySubAccountFuturesAssetTransferHistoryService { + s.email = email + return s +} + +func (s *QuerySubAccountFuturesAssetTransferHistoryService) FuturesType(futuresType int) *QuerySubAccountFuturesAssetTransferHistoryService { + s.futuresType = futuresType + return s +} + +func (s *QuerySubAccountFuturesAssetTransferHistoryService) StartTime(startTime uint64) *QuerySubAccountFuturesAssetTransferHistoryService { + s.startTime = &startTime + return s +} + +func (s *QuerySubAccountFuturesAssetTransferHistoryService) EndTime(endTime uint64) *QuerySubAccountFuturesAssetTransferHistoryService { + s.endTime = &endTime + return s +} + +func (s *QuerySubAccountFuturesAssetTransferHistoryService) Page(page int) *QuerySubAccountFuturesAssetTransferHistoryService { + s.page = &page + return s +} + +func (s *QuerySubAccountFuturesAssetTransferHistoryService) Limit(limit int) *QuerySubAccountFuturesAssetTransferHistoryService { + s.limit = &limit + return s +} + +func (s *QuerySubAccountFuturesAssetTransferHistoryService) Do(ctx context.Context) (res *QuerySubAccountFuturesAssetTransferHistoryResp, err error) { + r := &request{ + method: http.MethodGet, + endpoint: querySubAccountFuturesAssetTransferHistoryEndpoint, + secType: secTypeSigned, + } + r.setParam("email", s.email) + r.setParam("futuresType", s.futuresType) + if s.startTime != nil { + r.setParam("startTime", s.startTime) + } + if s.endTime != nil { + r.setParam("endTime", s.endTime) + } + if s.page != nil { + r.setParam("page", s.page) + } + if s.limit != nil { + r.setParam("limit", s.limit) + } + data, err := s.c.callAPI(ctx, r) + if err != nil { + return nil, err + } + res = new(QuerySubAccountFuturesAssetTransferHistoryResp) + err = json.Unmarshal(data, res) + if err != nil { + return nil, err + } + return res, nil +} + +type QuerySubAccountFuturesAssetTransferHistoryResp struct { + Success bool `json:"success"` + FuturesType int64 `json:"futuresType"` + Transfers []struct { + From string `json:"from"` + To string `json:"to"` + Asset string `json:"asset"` + Qty string `json:"qty"` + TranId int64 `json:"tranId"` + Time uint64 `json:"time"` + } `json:"transfers"` +} + +// Sub-account Futures Asset Transfer (For Master Account) +const ( + subAccountFuturesAssetTransferEndpoint = "/sapi/v1/sub-account/futures/internalTransfer" +) + +type SubAccountFuturesAssetTransferService struct { + c *Client + fromEmail string + toEmail string + futuresType int64 + asset string + amount float32 +} + +func (s *SubAccountFuturesAssetTransferService) FromEmail(fromEmail string) *SubAccountFuturesAssetTransferService { + s.fromEmail = fromEmail + return s +} + +func (s *SubAccountFuturesAssetTransferService) ToEmail(toEmail string) *SubAccountFuturesAssetTransferService { + s.toEmail = toEmail + return s +} + +func (s *SubAccountFuturesAssetTransferService) FuturesType(futuresType int64) *SubAccountFuturesAssetTransferService { + s.futuresType = futuresType + return s +} + +func (s *SubAccountFuturesAssetTransferService) Asset(asset string) *SubAccountFuturesAssetTransferService { + s.asset = asset + return s +} + +func (s *SubAccountFuturesAssetTransferService) Amount(amount float32) *SubAccountFuturesAssetTransferService { + s.amount = amount + return s +} + +func (s *SubAccountFuturesAssetTransferService) Do(ctx context.Context) (res *SubAccountFuturesAssetTransferResp, err error) { + r := &request{ + method: http.MethodPost, + endpoint: subAccountFuturesAssetTransferEndpoint, + secType: secTypeSigned, + } + r.setParam("fromEmail", s.fromEmail) + r.setParam("toEmail", s.toEmail) + r.setParam("futuresType", s.futuresType) + r.setParam("asset", s.asset) + r.setParam("amount", s.amount) + data, err := s.c.callAPI(ctx, r) + if err != nil { + return nil, err + } + res = new(SubAccountFuturesAssetTransferResp) + err = json.Unmarshal(data, res) + if err != nil { + return nil, err + } + return res, nil +} + +type SubAccountFuturesAssetTransferResp struct { + Success bool `json:"success"` + TxnId string `json:"txnId"` +} + +// Query Sub-account Assets (For Master Account) +const ( + querySubAccountAssetsEndpoint = "/sapi/v3/sub-account/assets" +) + +type QuerySubAccountAssetsService struct { + c *Client + email string +} + +func (s *QuerySubAccountAssetsService) Email(email string) *QuerySubAccountAssetsService { + s.email = email + return s +} + +func (s *QuerySubAccountAssetsService) Do(ctx context.Context) (res *QuerySubAccountAssetsResp, err error) { + r := &request{ + method: http.MethodGet, + endpoint: querySubAccountAssetsEndpoint, + secType: secTypeSigned, + } + r.setParam("email", s.email) + data, err := s.c.callAPI(ctx, r) + if err != nil { + return nil, err + } + res = new(QuerySubAccountAssetsResp) + err = json.Unmarshal(data, res) + if err != nil { + return nil, err + } + return res, nil +} + +type QuerySubAccountAssetsResp struct { + Balances []struct { + Asset string `json:"asset"` + Free string `json:"free"` + Locked string `json:"locked"` + } `json:"balances"` +} + +// Query Sub-account Spot Assets Summary (For Master Account) +const ( + querySubAccountSpotAssetsSummaryEndpoint = "/sapi/v1/sub-account/spotSummary" +) + +type QuerySubAccountSpotAssetsSummaryService struct { + c *Client + email *string + page *int + size *int +} + +func (s *QuerySubAccountSpotAssetsSummaryService) Email(email string) *QuerySubAccountSpotAssetsSummaryService { + s.email = &email + return s +} + +func (s *QuerySubAccountSpotAssetsSummaryService) Page(page int) *QuerySubAccountSpotAssetsSummaryService { + s.page = &page + return s +} + +func (s *QuerySubAccountSpotAssetsSummaryService) Size(size int) *QuerySubAccountSpotAssetsSummaryService { + s.size = &size + return s +} + +func (s *QuerySubAccountSpotAssetsSummaryService) Do(ctx context.Context) (res *QuerySubAccountSpotAssetsSummaryResp, err error) { + r := &request{ + method: http.MethodGet, + endpoint: querySubAccountSpotAssetsSummaryEndpoint, + secType: secTypeSigned, + } + if s.email != nil { + r.setParam("email", *s.email) + } + if s.page != nil { + r.setParam("page", *s.page) + } + if s.size != nil { + r.setParam("size", *s.size) + } + data, err := s.c.callAPI(ctx, r) + if err != nil { + return nil, err + } + res = new(QuerySubAccountSpotAssetsSummaryResp) + err = json.Unmarshal(data, res) + if err != nil { + return nil, err + } + return res, nil +} + +type QuerySubAccountSpotAssetsSummaryResp struct { + TotalCount int64 `json:"totalCount"` + MasterAccountTotalAsset string `json:"masterAccountTotalAsset"` + SpotSubUserAssetBtcVoList []struct { + Email string `json:"email"` + ToAsset string `json:"toAsset"` + } `json:"spotSubUserAssetBtcVoList"` +} + +// Get Sub-account Deposit Address (For Master Account) +const ( + getSubAccountDepositAddressEndpoint = "/sapi/v1/capital/deposit/subAddress" +) + +type GetSubAccountDepositAddressService struct { + c *Client + email string + coin string + network *string +} + +func (s *GetSubAccountDepositAddressService) Email(email string) *GetSubAccountDepositAddressService { + s.email = email + return s +} + +func (s *GetSubAccountDepositAddressService) Coin(coin string) *GetSubAccountDepositAddressService { + s.coin = coin + return s +} + +func (s *GetSubAccountDepositAddressService) Network(network string) *GetSubAccountDepositAddressService { + s.network = &network + return s +} + +func (s *GetSubAccountDepositAddressService) Do(ctx context.Context) (res *GetSubAccountDepositAddressResp, err error) { + r := &request{ + method: http.MethodGet, + endpoint: getSubAccountDepositAddressEndpoint, + secType: secTypeSigned, + } + r.setParam("email", s.email) + r.setParam("coin", s.coin) + if s.network != nil { + r.setParam("network", *s.network) + } + data, err := s.c.callAPI(ctx, r) + if err != nil { + return nil, err + } + res = new(GetSubAccountDepositAddressResp) + err = json.Unmarshal(data, res) + if err != nil { + return nil, err + } + return res, nil +} + +type GetSubAccountDepositAddressResp struct { + Address string `json:"address"` + Coin string `json:"coin"` + Tag string `json:"tag"` + Url string `json:"url"` +} + +// Get Sub-account Deposit History (For Master Account) +const ( + getSubAccountDepositHistoryEndpoint = "/sapi/v1/capital/deposit/subHisrec" +) + +type GetSubAccountDepositHistoryService struct { + c *Client + email string + coin string + status *int64 + startTime *uint64 + endTime *uint64 + limit *int + offset *int64 +} + +func (s *GetSubAccountDepositHistoryService) Email(email string) *GetSubAccountDepositHistoryService { + s.email = email + return s +} + +func (s *GetSubAccountDepositHistoryService) Coin(coin string) *GetSubAccountDepositHistoryService { + s.coin = coin + return s +} + +func (s *GetSubAccountDepositHistoryService) Status(status int64) *GetSubAccountDepositHistoryService { + s.status = &status + return s +} + +func (s *GetSubAccountDepositHistoryService) StartTime(startTime uint64) *GetSubAccountDepositHistoryService { + s.startTime = &startTime + return s +} + +func (s *GetSubAccountDepositHistoryService) EndTime(endTime uint64) *GetSubAccountDepositHistoryService { + s.endTime = &endTime + return s +} + +func (s *GetSubAccountDepositHistoryService) Limit(limit int) *GetSubAccountDepositHistoryService { + s.limit = &limit + return s +} + +func (s *GetSubAccountDepositHistoryService) Offset(offset int64) *GetSubAccountDepositHistoryService { + s.offset = &offset + return s +} + +func (s *GetSubAccountDepositHistoryService) Do(ctx context.Context) (res *GetSubAccountDepositHistoryResp, err error) { + r := &request{ + method: http.MethodGet, + endpoint: getSubAccountDepositHistoryEndpoint, + secType: secTypeSigned, + } + r.setParam("email", s.email) + r.setParam("coin", s.coin) + if s.status != nil { + r.setParam("status", *s.status) + } + if s.startTime != nil { + r.setParam("startTime", *s.startTime) + } + if s.endTime != nil { + r.setParam("endTime", *s.endTime) + } + if s.limit != nil { + r.setParam("limit", *s.limit) + } + if s.offset != nil { + r.setParam("offset", *s.offset) + } + data, err := s.c.callAPI(ctx, r) + if err != nil { + return nil, err + } + res = new(GetSubAccountDepositHistoryResp) + err = json.Unmarshal(data, res) + if err != nil { + return nil, err + } + return res, nil +} + +type GetSubAccountDepositHistoryResp struct { + DepositList []struct { + Id int64 `json:"id"` + Amount string `json:"amount"` + Coin string `json:"coin"` + Network string `json:"network"` + Status int64 `json:"status"` + Address string `json:"address"` + AddressTag string `json:"addressTag"` + TxId string `json:"txId"` + InsertTime uint64 `json:"insertTime"` + TransferType int64 `json:"transferType"` + ConfirmTimes string `json:"confirmTimes"` + UnlockConfirm int64 `json:"unlockConfirm"` + WalletType int `json:"walletType"` + } +} + +// Get Sub-account's Status on Margin/Futures (For Master Account) +const ( + getSubAccountStatusEndpoint = "/sapi/v1/sub-account/status" +) + +type GetSubAccountStatusService struct { + c *Client + email *string +} + +func (s *GetSubAccountStatusService) Email(email string) *GetSubAccountStatusService { + s.email = &email + return s +} + +func (s *GetSubAccountStatusService) Do(ctx context.Context) (res *GetSubAccountStatusResp, err error) { + r := &request{ + method: http.MethodGet, + endpoint: getSubAccountStatusEndpoint, + secType: secTypeSigned, + } + if s.email != nil { + r.setParam("email", *s.email) + } + data, err := s.c.callAPI(ctx, r) + if err != nil { + return nil, err + } + res = new(GetSubAccountStatusResp) + err = json.Unmarshal(data, res) + if err != nil { + return nil, err + } + return res, nil +} + +type GetSubAccountStatusResp struct { + Email string `json:"email"` + IsSubUserEnabled bool `json:"isSubUserEnabled"` + IsUserActive bool `json:"isUserActive"` + InsertTime uint64 `json:"insertTime"` + IsMarginEnabled bool `json:"isMarginEnabled"` + IsFuturesEnabled bool `json:"isFuturesEnabled"` + Mobile int64 `json:"mobile"` +} + +// Enable Margin for Sub-account (For Master Account) +const ( + enableMarginForSubAccountEndpoint = "/sapi/v1/sub-account/margin/enable" +) + +type EnableMarginForSubAccountService struct { + c *Client + email string +} + +func (s *EnableMarginForSubAccountService) Email(email string) *EnableMarginForSubAccountService { + s.email = email + return s +} + +func (s *EnableMarginForSubAccountService) Do(ctx context.Context) (res *EnableMarginForSubAccountResp, err error) { + r := &request{ + method: http.MethodPost, + endpoint: enableMarginForSubAccountEndpoint, + secType: secTypeSigned, + } + r.setParam("email", s.email) + data, err := s.c.callAPI(ctx, r) + if err != nil { + return nil, err + } + res = new(EnableMarginForSubAccountResp) + err = json.Unmarshal(data, res) + if err != nil { + return nil, err + } + return res, nil +} + +type EnableMarginForSubAccountResp struct { + Email string `json:"email"` + IsMarginEnabled bool `json:"isMarginEnabled"` +} + +// Get Detail on Sub-account's Margin Account (For Master Account) +const ( + getDetailOnSubAccountMarginAccountEndpoint = "/sapi/v1/sub-account/margin/account" +) + +type GetDetailOnSubAccountMarginAccountService struct { + c *Client + email string +} + +func (s *GetDetailOnSubAccountMarginAccountService) Email(email string) *GetDetailOnSubAccountMarginAccountService { + s.email = email + return s +} + +func (s *GetDetailOnSubAccountMarginAccountService) Do(ctx context.Context) (res *GetDetailOnSubAccountMarginAccountResp, err error) { + r := &request{ + method: http.MethodGet, + endpoint: getDetailOnSubAccountMarginAccountEndpoint, + secType: secTypeSigned, + } + r.setParam("email", s.email) + data, err := s.c.callAPI(ctx, r) + if err != nil { + return nil, err + } + res = new(GetDetailOnSubAccountMarginAccountResp) + err = json.Unmarshal(data, res) + if err != nil { + return nil, err + } + return res, nil +} + +type GetDetailOnSubAccountMarginAccountResp struct { + Email string `json:"email"` + MarginLevel string `json:"marginLevel"` + TotalAssetOfBtc string `json:"totalAssetOfBtc"` + TotalLiabilityOfBtc string `json:"totalLiabilityOfBtc"` + TotalNetAssetOfBtc string `json:"totalNetAssetOfBtc"` + MarginTradeCoeffVo struct { + ForceLiquidationRate string `json:"forceLiquidationRate"` + MarginCallBar string `json:"marginCallBar"` + NormalBar string `json:"normalBar"` + } `json:"marginTradeCoeffVo"` + MarginUserAssetVoList []struct { + Asset string `json:"asset"` + Borrowed string `json:"borrowed"` + Free string `json:"free"` + Interest string `json:"interest"` + Locked string `json:"locked"` + NetAsset string `json:"netAsset"` + } +} + +// Get Summary of Sub-account's Margin Account (For Master Account) +const ( + getSummaryOfSubAccountMarginAccountEndpoint = "/sapi/v1/sub-account/margin/accountSummary" +) + +type GetSummaryOfSubAccountMarginAccountService struct { + c *Client +} + +func (s *GetSummaryOfSubAccountMarginAccountService) Do(ctx context.Context) (res *GetSummaryOfSubAccountMarginAccountResp, err error) { + r := &request{ + method: http.MethodGet, + endpoint: getSummaryOfSubAccountMarginAccountEndpoint, + secType: secTypeSigned, + } + data, err := s.c.callAPI(ctx, r) + if err != nil { + return nil, err + } + res = new(GetSummaryOfSubAccountMarginAccountResp) + err = json.Unmarshal(data, res) + if err != nil { + return nil, err + } + return res, nil +} + +type GetSummaryOfSubAccountMarginAccountResp struct { + TotalAssetOfBtc string `json:"totalAssetOfBtc"` + TotalLiabilityOfBtc string `json:"totalLiabilityOfBtc"` + TotalNetAssetOfBtc string `json:"totalNetAssetOfBtc"` + SubAccountList []struct { + Email string `json:"email"` + TotalAssetOfBtc string `json:"totalAssetOfBtc"` + TotalLiabilityOfBtc string `json:"totalLiabilityOfBtc"` + TotalNetAssetOfBtc string `json:"totalNetAssetOfBtc"` + } `json:"subAccountList"` +} + +// Enable Futures for Sub-account (For Master Account) +const ( + enableFuturesForSubAccountEndpoint = "/sapi/v1/sub-account/futures/enable" +) + +type EnableFuturesForSubAccountService struct { + c *Client + email string +} + +func (s *EnableFuturesForSubAccountService) Email(email string) *EnableFuturesForSubAccountService { + s.email = email + return s +} + +func (s *EnableFuturesForSubAccountService) Do(ctx context.Context) (res *EnableFuturesForSubAccountResp, err error) { + r := &request{ + method: http.MethodPost, + endpoint: enableFuturesForSubAccountEndpoint, + secType: secTypeSigned, + } + r.setParam("email", s.email) + data, err := s.c.callAPI(ctx, r) + if err != nil { + return nil, err + } + res = new(EnableFuturesForSubAccountResp) + err = json.Unmarshal(data, res) + if err != nil { + return nil, err + } + return res, nil +} + +type EnableFuturesForSubAccountResp struct { + Email string `json:"email"` + IsFuturesEnabled bool `json:"isFuturesEnabled"` +} + +// Get Detail on Sub-account's Futures Account (For Master Account) +const ( + getDetailOnSubAccountFuturesAccountEndpoint = "/sapi/v1/sub-account/futures/account" +) + +type GetDetailOnSubAccountFuturesAccountService struct { + c *Client + email string +} + +func (s *GetDetailOnSubAccountFuturesAccountService) Email(email string) *GetDetailOnSubAccountFuturesAccountService { + s.email = email + return s +} + +func (s *GetDetailOnSubAccountFuturesAccountService) Do(ctx context.Context) (res *GetDetailOnSubAccountFuturesAccountResp, err error) { + r := &request{ + method: http.MethodGet, + endpoint: getDetailOnSubAccountFuturesAccountEndpoint, + secType: secTypeSigned, + } + r.setParam("email", s.email) + data, err := s.c.callAPI(ctx, r) + if err != nil { + return nil, err + } + res = new(GetDetailOnSubAccountFuturesAccountResp) + err = json.Unmarshal(data, res) + if err != nil { + return nil, err + } + return res, nil +} + +type GetDetailOnSubAccountFuturesAccountResp struct { + Email string `json:"email"` + Asset string `json:"asset"` + Assets []struct { + Asset string `json:"asset"` + InitialMargin string `json:"initialMargin"` + MaintenanceMargin string `json:"maintenanceMargin"` + MarginBalance string `json:"marginBalance"` + MaxWithdrawAmount string `json:"maxWithdrawAmount"` + OpenOrderInitialMargin string `json:"openOrderInitialMargin"` + PositionInitialMargin string `json:"positionInitialMargin"` + UnrealizedProfit string `json:"unrealizedProfit"` + WalletBalance string `json:"walletBalance"` + } `json:"assets"` + CanDeposit bool `json:"canDeposit"` + CanTrade bool `json:"canTrade"` + CanWithdraw bool `json:"canWithdraw"` + FeeTier int `json:"feeTier"` + MaxWithdrawAmount string `json:"maxWithdrawAmount"` + TotalInitialMargin string `json:"totalInitialMargin"` + TotalMaintenanceMargin string `json:"totalMaintenanceMargin"` + TotalMarginBalance string `json:"totalMarginBalance"` + TotalOpenOrderInitialMargin string `json:"totalOpenOrderInitialMargin"` + TotalPositionInitialMargin string `json:"totalPositionInitialMargin"` + TotalUnrealizedProfit string `json:"totalUnrealizedProfit"` + TotalWalletBalance string `json:"totalWalletBalance"` + UpdateTime uint64 `json:"updateTime"` +} + +// Get Summary of Sub-account's Futures Account (For Master Account) +const ( + getSummaryOfSubAccountFuturesAccountEndpoint = "/sapi/v1/sub-account/futures/accountSummary" +) + +type GetSummaryOfSubAccountFuturesAccountService struct { + c *Client +} + +func (s *GetSummaryOfSubAccountFuturesAccountService) Do(ctx context.Context) (res *GetSummaryOfSubAccountFuturesAccountResp, err error) { + r := &request{ + method: http.MethodGet, + endpoint: getSummaryOfSubAccountFuturesAccountEndpoint, + secType: secTypeSigned, + } + data, err := s.c.callAPI(ctx, r) + if err != nil { + return nil, err + } + res = new(GetSummaryOfSubAccountFuturesAccountResp) + err = json.Unmarshal(data, res) + if err != nil { + return nil, err + } + return res, nil +} + +type GetSummaryOfSubAccountFuturesAccountResp struct { + TotalInitialMargin string `json:"totalInitialMargin"` + TotalMaintenanceMargin string `json:"totalMaintenanceMargin"` + TotalMarginBalance string `json:"totalMarginBalance"` + TotalOpenOrderInitialMargin string `json:"totalOpenOrderInitialMargin"` + TotalPositionInitialMargin string `json:"totalPositionInitialMargin"` + TotalUnrealizedProfit string `json:"totalUnrealizedProfit"` + TotalWalletBalance string `json:"totalWalletBalance"` + Asset string `json:"asset"` + SubAccountList []struct { + Email string `json:"email"` + TotalInitialMargin string `json:"totalInitialMargin"` + TotalMaintenanceMargin string `json:"totalMaintenanceMargin"` + TotalMarginBalance string `json:"totalMarginBalance"` + TotalOpenOrderInitialMargin string `json:"totalOpenOrderInitialMargin"` + TotalPositionInitialMargin string `json:"totalPositionInitialMargin"` + TotalUnrealizedProfit string `json:"totalUnrealizedProfit"` + TotalWalletBalance string `json:"totalWalletBalance"` + Asset string `json:"asset"` + } `json:"subAccountList"` +} + +// Get Futures Position-Risk of Sub-account (For Master Account) +const ( + getFuturesPositionRiskOfSubAccountEndpoint = "/sapi/v1/sub-account/futures/positionRisk" +) + +type GetFuturesPositionRiskOfSubAccountService struct { + c *Client + email string +} + +func (s *GetFuturesPositionRiskOfSubAccountService) Email(email string) *GetFuturesPositionRiskOfSubAccountService { + s.email = email + return s +} + +func (s *GetFuturesPositionRiskOfSubAccountService) Do(ctx context.Context) (res *GetFuturesPositionRiskOfSubAccountResp, err error) { + r := &request{ + method: http.MethodGet, + endpoint: getFuturesPositionRiskOfSubAccountEndpoint, + secType: secTypeSigned, + } + r.setParam("email", s.email) + data, err := s.c.callAPI(ctx, r) + if err != nil { + return nil, err + } + res = new(GetFuturesPositionRiskOfSubAccountResp) + err = json.Unmarshal(data, res) + if err != nil { + return nil, err + } + return res, nil +} + +type GetFuturesPositionRiskOfSubAccountResp struct { + EntryPrice string `json:"entryPrice"` + Leverage string `json:"leverage"` + MaxNotional string `json:"maxNotional"` + LiquidationPrice string `json:"liquidationPrice"` + MarkPrice string `json:"markPrice"` + PositionAmount string `json:"positionAmount"` + Symbol string `json:"symbol"` + UnrealizedProfit string `json:"unrealizedProfit"` +} + +// Futures Transfer for Sub-account (For Master Account) +const ( + futuresTransferForSubAccountEndpoint = "/sapi/v1/sub-account/futures/transfer" +) + +type FuturesTransferForSubAccountService struct { + c *Client + email string + asset string + amount float64 + transferType int +} + +func (s *FuturesTransferForSubAccountService) Email(email string) *FuturesTransferForSubAccountService { + s.email = email + return s +} + +func (s *FuturesTransferForSubAccountService) Asset(asset string) *FuturesTransferForSubAccountService { + s.asset = asset + return s +} + +func (s *FuturesTransferForSubAccountService) Amount(amount float64) *FuturesTransferForSubAccountService { + s.amount = amount + return s +} + +func (s *FuturesTransferForSubAccountService) TransferType(transferType int) *FuturesTransferForSubAccountService { + s.transferType = transferType + return s +} + +func (s *FuturesTransferForSubAccountService) Do(ctx context.Context) (res *FuturesTransferForSubAccountResp, err error) { + r := &request{ + method: http.MethodPost, + endpoint: futuresTransferForSubAccountEndpoint, + secType: secTypeSigned, + } + r.setParam("email", s.email) + r.setParam("asset", s.asset) + r.setParam("amount", s.amount) + r.setParam("type", s.transferType) + data, err := s.c.callAPI(ctx, r) + if err != nil { + return nil, err + } + res = new(FuturesTransferForSubAccountResp) + err = json.Unmarshal(data, res) + if err != nil { + return nil, err + } + return res, nil +} + +type FuturesTransferForSubAccountResp struct { + TxnId int `json:"txnId"` +} + +// Margin Transfer for Sub-account (For Master Account) +const ( + marginTransferForSubAccountEndpoint = "/sapi/v1/sub-account/margin/transfer" +) + +type MarginTransferForSubAccountService struct { + c *Client + email string + asset string + amount float32 + transferType int +} + +func (s *MarginTransferForSubAccountService) Email(email string) *MarginTransferForSubAccountService { + s.email = email + return s +} + +func (s *MarginTransferForSubAccountService) Asset(asset string) *MarginTransferForSubAccountService { + s.asset = asset + return s +} + +func (s *MarginTransferForSubAccountService) Amount(amount float32) *MarginTransferForSubAccountService { + s.amount = amount + return s +} + +func (s *MarginTransferForSubAccountService) TransferType(transferType int) *MarginTransferForSubAccountService { + s.transferType = transferType + return s +} + +func (s *MarginTransferForSubAccountService) Do(ctx context.Context) (res *MarginTransferForSubAccountResp, err error) { + r := &request{ + method: http.MethodPost, + endpoint: marginTransferForSubAccountEndpoint, + secType: secTypeSigned, + } + r.setParam("email", s.email) + r.setParam("asset", s.asset) + r.setParam("amount", s.amount) + r.setParam("type", s.transferType) + data, err := s.c.callAPI(ctx, r) + if err != nil { + return nil, err + } + res = new(MarginTransferForSubAccountResp) + err = json.Unmarshal(data, res) + if err != nil { + return nil, err + } + return res, nil +} + +type MarginTransferForSubAccountResp struct { + TxnId int `json:"txnId"` +} + +// Transfer to Sub-account of Same Master (For Sub-account) +const ( + transferToSubAccountOfSameMasterEndpoint = "/sapi/v1/sub-account/transfer/subToSub" +) + +type TransferToSubAccountOfSameMasterService struct { + c *Client + toEmail string + asset string + amount float64 +} + +func (s *TransferToSubAccountOfSameMasterService) ToEmail(toEmail string) *TransferToSubAccountOfSameMasterService { + s.toEmail = toEmail + return s +} + +func (s *TransferToSubAccountOfSameMasterService) Asset(asset string) *TransferToSubAccountOfSameMasterService { + s.asset = asset + return s +} + +func (s *TransferToSubAccountOfSameMasterService) Amount(amount float64) *TransferToSubAccountOfSameMasterService { + s.amount = amount + return s +} + +func (s *TransferToSubAccountOfSameMasterService) Do(ctx context.Context) (res *TransferToSubAccountOfSameMasterResp, err error) { + r := &request{ + method: http.MethodPost, + endpoint: transferToSubAccountOfSameMasterEndpoint, + secType: secTypeSigned, + } + r.setParam("toEmail", s.toEmail) + r.setParam("asset", s.asset) + r.setParam("amount", s.amount) + data, err := s.c.callAPI(ctx, r) + if err != nil { + return nil, err + } + res = new(TransferToSubAccountOfSameMasterResp) + err = json.Unmarshal(data, res) + if err != nil { + return nil, err + } + return res, nil +} + +type TransferToSubAccountOfSameMasterResp struct { + TxnId int `json:"txnId"` +} + +// Transfer to Master (For Sub-account) +const ( + transferToMasterEndpoint = "/sapi/v1/sub-account/transfer/subToMaster" +) + +type TransferToMasterService struct { + c *Client + asset string + amount float64 +} + +func (s *TransferToMasterService) Asset(asset string) *TransferToMasterService { + s.asset = asset + return s +} + +func (s *TransferToMasterService) Amount(amount float64) *TransferToMasterService { + s.amount = amount + return s +} + +func (s *TransferToMasterService) Do(ctx context.Context) (res *TransferToMasterResp, err error) { + r := &request{ + method: http.MethodPost, + endpoint: transferToMasterEndpoint, + secType: secTypeSigned, + } + r.setParam("asset", s.asset) + r.setParam("amount", s.amount) + data, err := s.c.callAPI(ctx, r) + if err != nil { + return nil, err + } + res = new(TransferToMasterResp) + err = json.Unmarshal(data, res) + if err != nil { + return nil, err + } + return res, nil +} + +type TransferToMasterResp struct { + TxnId int `json:"txnId"` +} + +// Sub-account Transfer History (For Sub-account) +const ( + subAccountTransferHistoryEndpoint = "/sapi/v1/sub-account/transfer/subUserHistory" +) + +type SubAccountTransferHistoryService struct { + c *Client + asset *string + transferType *int + startTime *uint64 + endTime *uint64 + limit *int +} + +func (s *SubAccountTransferHistoryService) Asset(asset string) *SubAccountTransferHistoryService { + s.asset = &asset + return s +} + +func (s *SubAccountTransferHistoryService) TransferType(transferType int) *SubAccountTransferHistoryService { + s.transferType = &transferType + return s +} + +func (s *SubAccountTransferHistoryService) StartTime(startTime uint64) *SubAccountTransferHistoryService { + s.startTime = &startTime + return s +} + +func (s *SubAccountTransferHistoryService) EndTime(endTime uint64) *SubAccountTransferHistoryService { + s.endTime = &endTime + return s +} + +func (s *SubAccountTransferHistoryService) Limit(limit int) *SubAccountTransferHistoryService { + s.limit = &limit + return s +} + +func (s *SubAccountTransferHistoryService) Do(ctx context.Context) (res *SubAccountTransferHistoryResp, err error) { + r := &request{ + method: http.MethodGet, + endpoint: subAccountTransferHistoryEndpoint, + secType: secTypeSigned, + } + if s.asset != nil { + r.setParam("asset", *s.asset) + } + if s.transferType != nil { + r.setParam("type", *s.transferType) + } + if s.startTime != nil { + r.setParam("startTime", *s.startTime) + } + if s.endTime != nil { + r.setParam("endTime", *s.endTime) + } + if s.limit != nil { + r.setParam("limit", *s.limit) + } + data, err := s.c.callAPI(ctx, r) + if err != nil { + return nil, err + } + res = new(SubAccountTransferHistoryResp) + err = json.Unmarshal(data, res) + if err != nil { + return nil, err + } + return res, nil +} + +type SubAccountTransferHistoryResp struct { + CounterParty string `json:"counterParty"` + Email string `json:"email"` + Type int `json:"type"` + Asset string `json:"asset"` + Qty string `json:"qty"` + FromAccountType string `json:"fromAccountType"` + ToAccountType string `json:"toAccountType"` + Status string `json:"status"` + TranId int `json:"tranId"` + Time uint64 `json:"time"` +} + +// Universal Transfer (For Master Account) +const ( + universalTransferEndpoint = "/sapi/v1/asset/universalTransfer" +) + +type UniversalTransferService struct { + c *Client + fromEmail *string + toEmail *string + fromAccountType string + toAccountType string + clientTranId *string + symbol *string + asset string + amount float64 +} + +func (s *UniversalTransferService) FromEmail(fromEmail string) *UniversalTransferService { + s.fromEmail = &fromEmail + return s +} + +func (s *UniversalTransferService) ToEmail(toEmail string) *UniversalTransferService { + s.toEmail = &toEmail + return s +} + +func (s *UniversalTransferService) FromAccountType(fromAccountType string) *UniversalTransferService { + s.fromAccountType = fromAccountType + return s +} + +func (s *UniversalTransferService) ToAccountType(toAccountType string) *UniversalTransferService { + s.toAccountType = toAccountType + return s +} + +func (s *UniversalTransferService) ClientTranId(clientTranId string) *UniversalTransferService { + s.clientTranId = &clientTranId + return s +} + +func (s *UniversalTransferService) Symbol(symbol string) *UniversalTransferService { + s.symbol = &symbol + return s +} + +func (s *UniversalTransferService) Asset(asset string) *UniversalTransferService { + s.asset = asset + return s +} + +func (s *UniversalTransferService) Amount(amount float64) *UniversalTransferService { + s.amount = amount + return s +} + +func (s *UniversalTransferService) Do(ctx context.Context) (res *UniversalTransferResp, err error) { + r := &request{ + method: http.MethodPost, + endpoint: universalTransferEndpoint, + secType: secTypeSigned, + } + r.setParam("fromAccountType", s.fromAccountType) + r.setParam("toAccountType", s.toAccountType) + if s.fromEmail != nil { + r.setParam("fromEmail", *s.fromEmail) + } + if s.toEmail != nil { + r.setParam("toEmail", *s.toEmail) + } + if s.clientTranId != nil { + r.setParam("clientTranId", *s.clientTranId) + } + if s.symbol != nil { + r.setParam("symbol", *s.symbol) + } + r.setParam("asset", s.asset) + r.setParam("amount", s.amount) + data, err := s.c.callAPI(ctx, r) + if err != nil { + return nil, err + } + res = new(UniversalTransferResp) + err = json.Unmarshal(data, res) + if err != nil { + return nil, err + } + return res, nil +} + +type UniversalTransferResp struct { + TranId int `json:"tranId"` + ClientTranId string `json:"clientTranId"` +} + +// Query Universal Transfer History (For Master Account) +const ( + queryUniversalTransferHistoryEndpoint = "/sapi/v1/asset/universalTransfer" +) + +type QueryUniversalTransferHistoryService struct { + c *Client + fromEmail *string + toEmail *string + clientTranId *string + startTime *uint64 + endTime *uint64 + page *int + limit *int +} + +func (s *QueryUniversalTransferHistoryService) FromEmail(fromEmail string) *QueryUniversalTransferHistoryService { + s.fromEmail = &fromEmail + return s +} + +func (s *QueryUniversalTransferHistoryService) ToEmail(toEmail string) *QueryUniversalTransferHistoryService { + s.toEmail = &toEmail + return s +} + +func (s *QueryUniversalTransferHistoryService) ClientTranId(clientTranId string) *QueryUniversalTransferHistoryService { + s.clientTranId = &clientTranId + return s +} + +func (s *QueryUniversalTransferHistoryService) StartTime(startTime uint64) *QueryUniversalTransferHistoryService { + s.startTime = &startTime + return s +} + +func (s *QueryUniversalTransferHistoryService) EndTime(endTime uint64) *QueryUniversalTransferHistoryService { + s.endTime = &endTime + return s +} + +func (s *QueryUniversalTransferHistoryService) Page(page int) *QueryUniversalTransferHistoryService { + s.page = &page + return s +} + +func (s *QueryUniversalTransferHistoryService) Limit(limit int) *QueryUniversalTransferHistoryService { + s.limit = &limit + return s +} + +func (s *QueryUniversalTransferHistoryService) Do(ctx context.Context, opts ...RequestOption) (res QueryUniversalTransferHistoryResp, err error) { + r := &request{ + method: http.MethodGet, + endpoint: queryUniversalTransferHistoryEndpoint, + secType: secTypeSigned, + } + if s.fromEmail != nil { + r.setParam("fromEmail", *s.fromEmail) + } + if s.toEmail != nil { + r.setParam("toEmail", *s.toEmail) + } + if s.clientTranId != nil { + r.setParam("clientTranId", *s.clientTranId) + } + if s.startTime != nil { + r.setParam("startTime", *s.startTime) + } + if s.endTime != nil { + r.setParam("endTime", *s.endTime) + } + if s.page != nil { + r.setParam("page", *s.page) + } + if s.limit != nil { + r.setParam("limit", *s.limit) + } + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return + } + res.Result = make([]*InternalUniversalTransfer, 0) + err = json.Unmarshal(data, &res) + if err != nil { + return + } + return res, nil +} + +type QueryUniversalTransferHistoryResp struct { + Result []*InternalUniversalTransfer `json:"result"` + TotalCount int `json:"totalCount"` +} + +type InternalUniversalTransfer struct { + TranId int64 `json:"tranId"` + ClientTranId string `json:"clientTranId"` + FromEmail string `json:"fromEmail"` + ToEmail string `json:"toEmail"` + Asset string `json:"asset"` + Amount string `json:"amount"` + FromAccountType string `json:"fromAccountType"` + ToAccountType string `json:"toAccountType"` + Status string `json:"status"` + CreateTimeStamp uint64 `json:"createTimeStamp"` +} + +// Get Detail on Sub-account's Futures Account V2 (For Master Account) +const ( + getDetailOnSubAccountFuturesAccountV2Endpoint = "/sapi/v1/sub-account/futures/internalTransfer" +) + +type GetDetailOnSubAccountFuturesAccountV2Service struct { + c *Client + email string + futuresType int +} + +func (s *GetDetailOnSubAccountFuturesAccountV2Service) Email(email string) *GetDetailOnSubAccountFuturesAccountV2Service { + s.email = email + return s +} + +func (s *GetDetailOnSubAccountFuturesAccountV2Service) FuturesType(futuresType int) *GetDetailOnSubAccountFuturesAccountV2Service { + s.futuresType = futuresType + return s +} + +func (s *GetDetailOnSubAccountFuturesAccountV2Service) Do(ctx context.Context) (res *GetDetailOnSubAccountFuturesAccountV2Resp, err error) { + r := &request{ + method: http.MethodGet, + endpoint: getDetailOnSubAccountFuturesAccountV2Endpoint, + secType: secTypeSigned, + } + r.setParam("email", s.email) + r.setParam("futuresType", s.futuresType) + data, err := s.c.callAPI(ctx, r) + if err != nil { + return nil, err + } + res = new(GetDetailOnSubAccountFuturesAccountV2Resp) + err = json.Unmarshal(data, res) + if err != nil { + return nil, err + } + return res, nil +} + +type GetDetailOnSubAccountFuturesAccountV2Resp struct { + Success bool `json:"success"` + FuturesType int `json:"futuresType"` + Transfers []struct { + From string `json:"from"` + To string `json:"to"` + Asset string `json:"asset"` + Qty string `json:"qty"` + TranId int64 `json:"tranId"` + Time uint64 `json:"time"` + } `json:"transfers"` +} + +// Get Summary of Sub-account's Futures Account V2 (For Master Account) +const ( + getSummaryOfSubAccountFuturesAccountV2Endpoint = "/sapi/v1/sub-account/futures/accountSummary" +) + +type GetSummaryOfSubAccountFuturesAccountV2Service struct { + c *Client + futuresType int + page *int + limit *int +} + +func (s *GetSummaryOfSubAccountFuturesAccountV2Service) FuturesType(futuresType int) *GetSummaryOfSubAccountFuturesAccountV2Service { + s.futuresType = futuresType + return s +} + +func (s *GetSummaryOfSubAccountFuturesAccountV2Service) Page(page int) *GetSummaryOfSubAccountFuturesAccountV2Service { + s.page = &page + return s +} + +func (s *GetSummaryOfSubAccountFuturesAccountV2Service) Limit(limit int) *GetSummaryOfSubAccountFuturesAccountV2Service { + s.limit = &limit + return s +} + +func (s *GetSummaryOfSubAccountFuturesAccountV2Service) Do(ctx context.Context) (res *GetSummaryOfSubAccountFuturesAccountV2Resp, err error) { + r := &request{ + method: http.MethodGet, + endpoint: getSummaryOfSubAccountFuturesAccountV2Endpoint, + secType: secTypeSigned, + } + r.setParam("futuresType", s.futuresType) + if s.page != nil { + r.setParam("page", *s.page) + } + if s.limit != nil { + r.setParam("limit", *s.limit) + } + data, err := s.c.callAPI(ctx, r) + if err != nil { + return nil, err + } + res = new(GetSummaryOfSubAccountFuturesAccountV2Resp) + err = json.Unmarshal(data, res) + if err != nil { + return nil, err + } + return res, nil +} + +type GetSummaryOfSubAccountFuturesAccountV2Resp struct { + FutureAccountSummaryResp struct { + TotalInitialMargin string `json:"totalInitialMargin"` + TotalMaintenanceMargin string `json:"totalMaintenanceMargin"` + TotalMarginBalance string `json:"totalMarginBalance"` + TotalOpenOrderInitialMargin string `json:"totalOpenOrderInitialMargin"` + TotalPositionInitialMargin string `json:"totalPositionInitialMargin"` + TotalUnrealizedProfit string `json:"totalUnrealizedProfit"` + TotalWalletBalance string `json:"totalWalletBalance"` + Asset string `json:"asset"` + SubAccountList []struct { + Email string `json:"email"` + TotalInitialMargin string `json:"totalInitialMargin"` + TotalMaintenanceMargin string `json:"totalMaintenanceMargin"` + TotalMarginBalance string `json:"totalMarginBalance"` + TotalOpenOrderInitialMargin string `json:"totalOpenOrderInitialMargin"` + TotalPositionInitialMargin string `json:"totalPositionInitialMargin"` + TotalUnrealizedProfit string `json:"totalUnrealizedProfit"` + TotalWalletBalance string `json:"totalWalletBalance"` + Asset string `json:"asset"` + } `json:"subAccountList"` + } `json:"futureAccountSummaryResp"` +} + +// Get Futures Position-Risk of Sub-account V2 (For Master Account) +const ( + getFuturesPositionRiskOfSubAccountV2Endpoint = "/sapi/v1/sub-account/futures/positionRisk" +) + +type GetFuturesPositionRiskOfSubAccountV2Service struct { + c *Client + email string + futuresType int +} + +func (s *GetFuturesPositionRiskOfSubAccountV2Service) Email(email string) *GetFuturesPositionRiskOfSubAccountV2Service { + s.email = email + return s +} + +func (s *GetFuturesPositionRiskOfSubAccountV2Service) FuturesType(futuresType int) *GetFuturesPositionRiskOfSubAccountV2Service { + s.futuresType = futuresType + return s +} + +func (s *GetFuturesPositionRiskOfSubAccountV2Service) Do(ctx context.Context) (res *GetFuturesPositionRiskOfSubAccountV2Resp, err error) { + r := &request{ + method: http.MethodGet, + endpoint: getFuturesPositionRiskOfSubAccountV2Endpoint, + secType: secTypeSigned, + } + r.setParam("email", s.email) + r.setParam("futuresType", s.futuresType) + data, err := s.c.callAPI(ctx, r) + if err != nil { + return nil, err + } + res = new(GetFuturesPositionRiskOfSubAccountV2Resp) + err = json.Unmarshal(data, res) + if err != nil { + return nil, err + } + return res, nil +} + +type GetFuturesPositionRiskOfSubAccountV2Resp struct { + FuturePositionRiskVos []struct { + EntryPrice string `json:"entryPrice"` + Leverage string `json:"leverage"` + MaxNotional string `json:"maxNotional"` + LiquidationPrice string `json:"liquidationPrice"` + MarkPrice string `json:"markPrice"` + PositionAmount string `json:"positionAmount"` + Symbol string `json:"symbol"` + UnrealizedProfit string `json:"unrealizedProfit"` + } `json:"futurePositionRiskVos"` +} + +// Enable Leverage Token for Sub-account (For Master Account) +const ( + enableLeverageTokenForSubAccountEndpoint = "/sapi/v1/sub-account/blvt/enable" +) + +type EnableLeverageTokenForSubAccountService struct { + c *Client + email string + enableBlvt bool +} + +func (s *EnableLeverageTokenForSubAccountService) Email(email string) *EnableLeverageTokenForSubAccountService { + s.email = email + return s +} + +func (s *EnableLeverageTokenForSubAccountService) EnableBlvt(enableBlvt bool) *EnableLeverageTokenForSubAccountService { + s.enableBlvt = enableBlvt + return s +} + +func (s *EnableLeverageTokenForSubAccountService) Do(ctx context.Context) (res *EnableLeverageTokenForSubAccountResp, err error) { + r := &request{ + method: http.MethodPost, + endpoint: enableLeverageTokenForSubAccountEndpoint, + secType: secTypeSigned, + } + r.setParam("email", s.email) + r.setParam("enableBlvt", s.enableBlvt) + data, err := s.c.callAPI(ctx, r) + if err != nil { + return nil, err + } + res = new(EnableLeverageTokenForSubAccountResp) + err = json.Unmarshal(data, res) + if err != nil { + return nil, err + } + return res, nil +} + +type EnableLeverageTokenForSubAccountResp struct { + Email string `json:"email"` + EnableBlvt bool `json:"enableBlvt"` +} + +// Get IP Restriction for a Sub-account API Key (For Master Account) + +const ( + getIPRestrictionForSubAccountAPIKeyEndpoint = "/sapi/v1/sub-account/subaccountApi/ipRestriction" +) + +type GetIPRestrictionForSubAccountAPIKeyService struct { + c *Client + email string + subAccountApiKey string +} + +func (s *GetIPRestrictionForSubAccountAPIKeyService) Email(email string) *GetIPRestrictionForSubAccountAPIKeyService { + s.email = email + return s +} + +func (s *GetIPRestrictionForSubAccountAPIKeyService) SubAccountApiKey(subAccountApiKey string) *GetIPRestrictionForSubAccountAPIKeyService { + s.subAccountApiKey = subAccountApiKey + return s +} + +func (s *GetIPRestrictionForSubAccountAPIKeyService) Do(ctx context.Context) (res *GetIPRestrictionForSubAccountAPIKeyResp, err error) { + r := &request{ + method: http.MethodGet, + endpoint: getIPRestrictionForSubAccountAPIKeyEndpoint, + secType: secTypeSigned, + } + r.setParam("email", s.email) + r.setParam("subAccountApiKey", s.subAccountApiKey) + data, err := s.c.callAPI(ctx, r) + if err != nil { + return nil, err + } + res = new(GetIPRestrictionForSubAccountAPIKeyResp) + err = json.Unmarshal(data, res) + if err != nil { + return nil, err + } + return res, nil +} + +type GetIPRestrictionForSubAccountAPIKeyResp struct { + IpRestrict string `json:"ipRestrict"` + IpList []struct { + Ip string `json:"ip"` + } `json:"ipList"` + UpdateTime uint64 `json:"updateTime"` + ApiKey string `json:"apiKey"` +} + +// Delete IP List For a Sub-account API Key (For Master Account) + +const ( + deleteIPListForSubAccountAPIKeyEndpoint = "/sapi/v1/sub-account/subaccountApi/ipRestriction/ipList" +) + +type DeleteIPListForSubAccountAPIKeyService struct { + c *Client + email string + subAccountApiKey string + ipAddress *string +} + +func (s *DeleteIPListForSubAccountAPIKeyService) Email(email string) *DeleteIPListForSubAccountAPIKeyService { + s.email = email + return s +} + +func (s *DeleteIPListForSubAccountAPIKeyService) SubAccountApiKey(subAccountApiKey string) *DeleteIPListForSubAccountAPIKeyService { + s.subAccountApiKey = subAccountApiKey + return s +} + +func (s *DeleteIPListForSubAccountAPIKeyService) IpAddress(ipAddress string) *DeleteIPListForSubAccountAPIKeyService { + s.ipAddress = &ipAddress + return s +} + +func (s *DeleteIPListForSubAccountAPIKeyService) Do(ctx context.Context) (res *DeleteIPListForSubAccountAPIKeyResp, err error) { + r := &request{ + method: http.MethodDelete, + endpoint: deleteIPListForSubAccountAPIKeyEndpoint, + secType: secTypeSigned, + } + r.setParam("email", s.email) + r.setParam("subAccountApiKey", s.subAccountApiKey) + if s.ipAddress != nil { + r.setParam("ipAddress", *s.ipAddress) + } + data, err := s.c.callAPI(ctx, r) + if err != nil { + return nil, err + } + res = new(DeleteIPListForSubAccountAPIKeyResp) + err = json.Unmarshal(data, res) + if err != nil { + return nil, err + } + return res, nil +} + +type DeleteIPListForSubAccountAPIKeyResp struct { + IpRestrict string `json:"ipRestrict"` + IpList []struct { + Ip string `json:"ip"` + } `json:"ipList"` + UpdateTime uint64 `json:"updateTime"` + ApiKey string `json:"apiKey"` +} + +// Update IP Restriction for Sub-Account API key (For Master Account) + +const ( + updateIPRestrictionForSubAccountAPIKeyEndpoint = "/sapi/v2/sub-account/subaccountApi/ipRestriction" +) + +type UpdateIPRestrictionForSubAccountAPIKeyService struct { + c *Client + email string + subAccountApiKey string + status string + ipAddress *string +} + +func (s *UpdateIPRestrictionForSubAccountAPIKeyService) Email(email string) *UpdateIPRestrictionForSubAccountAPIKeyService { + s.email = email + return s +} + +func (s *UpdateIPRestrictionForSubAccountAPIKeyService) SubAccountApiKey(subAccountApiKey string) *UpdateIPRestrictionForSubAccountAPIKeyService { + s.subAccountApiKey = subAccountApiKey + return s +} + +func (s *UpdateIPRestrictionForSubAccountAPIKeyService) Status(status string) *UpdateIPRestrictionForSubAccountAPIKeyService { + s.status = status + return s +} + +func (s *UpdateIPRestrictionForSubAccountAPIKeyService) IpAddress(ipAddress string) *UpdateIPRestrictionForSubAccountAPIKeyService { + s.ipAddress = &ipAddress + return s +} + +func (s *UpdateIPRestrictionForSubAccountAPIKeyService) Do(ctx context.Context) (res *UpdateIPRestrictionForSubAccountAPIKeyResp, err error) { + r := &request{ + method: http.MethodPut, + endpoint: updateIPRestrictionForSubAccountAPIKeyEndpoint, + secType: secTypeSigned, + } + r.setParam("email", s.email) + r.setParam("subAccountApiKey", s.subAccountApiKey) + r.setParam("status", s.status) + if s.ipAddress != nil { + r.setParam("ipAddress", *s.ipAddress) + } + data, err := s.c.callAPI(ctx, r) + if err != nil { + return nil, err + } + res = new(UpdateIPRestrictionForSubAccountAPIKeyResp) + err = json.Unmarshal(data, res) + if err != nil { + return nil, err + } + return res, nil +} + +type UpdateIPRestrictionForSubAccountAPIKeyResp struct { + Status string `json:"status"` + IpList []struct { + Ip string `json:"ip"` + } `json:"ipList"` + UpdateTime uint64 `json:"updateTime"` + ApiKey string `json:"apiKey"` +} + +// Deposit Assets Into The Managed Sub-account(For Investor Master Account) + +const ( + depositAssetsIntoTheManagedSubAccountEndpoint = "/sapi/v1/managed-subaccount/deposit" +) + +type DepositAssetsIntoTheManagedSubAccountService struct { + c *Client + toEmail string + asset string + amount float64 +} + +func (s *DepositAssetsIntoTheManagedSubAccountService) ToEmail(toEmail string) *DepositAssetsIntoTheManagedSubAccountService { + s.toEmail = toEmail + return s +} + +func (s *DepositAssetsIntoTheManagedSubAccountService) Asset(asset string) *DepositAssetsIntoTheManagedSubAccountService { + s.asset = asset + return s +} + +func (s *DepositAssetsIntoTheManagedSubAccountService) Amount(amount float64) *DepositAssetsIntoTheManagedSubAccountService { + s.amount = amount + return s +} + +func (s *DepositAssetsIntoTheManagedSubAccountService) Do(ctx context.Context) (res *DepositAssetsIntoTheManagedSubAccountResp, err error) { + r := &request{ + method: http.MethodPost, + endpoint: depositAssetsIntoTheManagedSubAccountEndpoint, + secType: secTypeSigned, + } + r.setParam("toEmail", s.toEmail) + r.setParam("asset", s.asset) + r.setParam("amount", s.amount) + data, err := s.c.callAPI(ctx, r) + if err != nil { + return nil, err + } + res = new(DepositAssetsIntoTheManagedSubAccountResp) + err = json.Unmarshal(data, res) + if err != nil { + return nil, err + } + return res, nil +} + +type DepositAssetsIntoTheManagedSubAccountResp struct { + TranId int64 `json:"tranId"` +} + +// Query Managed Sub-account Asset Details(For Investor Master Account) + +const ( + queryManagedSubAccountAssetDetailsEndpoint = "/sapi/v1/sub-account/managed-subaccount/asset" +) + +type QueryManagedSubAccountAssetDetailsService struct { + c *Client + email string +} + +func (s *QueryManagedSubAccountAssetDetailsService) Email(email string) *QueryManagedSubAccountAssetDetailsService { + s.email = email + return s +} + +func (s *QueryManagedSubAccountAssetDetailsService) Do(ctx context.Context) (res *QueryManagedSubAccountAssetDetailsResp, err error) { + r := &request{ + method: http.MethodGet, + endpoint: queryManagedSubAccountAssetDetailsEndpoint, + secType: secTypeSigned, + } + r.setParam("email", s.email) + data, err := s.c.callAPI(ctx, r) + if err != nil { + return nil, err + } + res = new(QueryManagedSubAccountAssetDetailsResp) + err = json.Unmarshal(data, res) + if err != nil { + return nil, err + } + return res, nil +} + +type QueryManagedSubAccountAssetDetailsResp struct { + AssetDetail []struct { + Coin string `json:"coin"` + Name string `json:"name"` + TotalBalance string `json:"totalBalance"` + AvailableBalance string `json:"availableBalance"` + InOrder string `json:"inOrder"` + BtcValue string `json:"btcValue"` + } `json:"assetDetail"` +} + +// Withdrawl Assets From The Managed Sub-account(For Investor Master Account) + +const ( + withdrawAssetsFromTheManagedSubAccountEndpoint = "/sapi/v1/sub-account/managed-subaccount/withdraw" +) + +type WithdrawAssetsFromTheManagedSubAccountService struct { + c *Client + fromEmail string + asset string + amount float32 + transferDate *int64 +} + +func (s *WithdrawAssetsFromTheManagedSubAccountService) FromEmail(fromEmail string) *WithdrawAssetsFromTheManagedSubAccountService { + s.fromEmail = fromEmail + return s +} + +func (s *WithdrawAssetsFromTheManagedSubAccountService) Asset(asset string) *WithdrawAssetsFromTheManagedSubAccountService { + s.asset = asset + return s +} + +func (s *WithdrawAssetsFromTheManagedSubAccountService) Amount(amount float32) *WithdrawAssetsFromTheManagedSubAccountService { + s.amount = amount + return s +} + +func (s *WithdrawAssetsFromTheManagedSubAccountService) TransferDate(transferDate int64) *WithdrawAssetsFromTheManagedSubAccountService { + s.transferDate = &transferDate + return s +} + +func (s *WithdrawAssetsFromTheManagedSubAccountService) Do(ctx context.Context) (res *WithdrawAssetsFromTheManagedSubAccountResp, err error) { + r := &request{ + method: http.MethodPost, + endpoint: withdrawAssetsFromTheManagedSubAccountEndpoint, + secType: secTypeSigned, + } + r.setParam("fromEmail", s.fromEmail) + r.setParam("asset", s.asset) + r.setParam("amount", s.amount) + if s.transferDate != nil { + r.setParam("transferDate", *s.transferDate) + } + data, err := s.c.callAPI(ctx, r) + if err != nil { + return nil, err + } + res = new(WithdrawAssetsFromTheManagedSubAccountResp) + err = json.Unmarshal(data, res) + if err != nil { + return nil, err + } + return res, nil +} + +type WithdrawAssetsFromTheManagedSubAccountResp struct { + TranId int64 `json:"tranId"` +} + +// Query Managed Sub-account Snapshot(For Investor Master Account) + +const ( + queryManagedSubAccountSnapshotEndpoint = "/sapi/v1/managed-subaccount/accountSnapshot" +) + +type QueryManagedSubAccountSnapshotService struct { + c *Client + email string + subType string + startTime *uint64 + endTime *uint64 + limit *int +} + +func (s *QueryManagedSubAccountSnapshotService) Email(email string) *QueryManagedSubAccountSnapshotService { + s.email = email + return s +} + +func (s *QueryManagedSubAccountSnapshotService) SubType(subType string) *QueryManagedSubAccountSnapshotService { + s.subType = subType + return s +} + +func (s *QueryManagedSubAccountSnapshotService) StartTime(startTime uint64) *QueryManagedSubAccountSnapshotService { + s.startTime = &startTime + return s +} + +func (s *QueryManagedSubAccountSnapshotService) EndTime(endTime uint64) *QueryManagedSubAccountSnapshotService { + s.endTime = &endTime + return s +} + +func (s *QueryManagedSubAccountSnapshotService) Limit(limit int) *QueryManagedSubAccountSnapshotService { + s.limit = &limit + return s +} + +func (s *QueryManagedSubAccountSnapshotService) Do(ctx context.Context) (res *QueryManagedSubAccountSnapshotResp, err error) { + r := &request{ + method: http.MethodGet, + endpoint: queryManagedSubAccountSnapshotEndpoint, + secType: secTypeSigned, + } + r.setParam("email", s.email) + r.setParam("type", s.subType) + if s.startTime != nil { + r.setParam("startTime", *s.startTime) + } + if s.endTime != nil { + r.setParam("endTime", *s.endTime) + } + if s.limit != nil { + r.setParam("limit", *s.limit) + } + data, err := s.c.callAPI(ctx, r) + if err != nil { + return nil, err + } + res = new(QueryManagedSubAccountSnapshotResp) + err = json.Unmarshal(data, res) + if err != nil { + return nil, err + } + return res, nil +} + +type QueryManagedSubAccountSnapshotResp struct { + Code int `json:"code"` + Msg string `json:"msg"` + SnapshotVos []struct { + Data []struct { + Balances []struct { + Asset string `json:"asset"` + Free string `json:"free"` + Locked string `json:"locked"` + } `json:"balances"` + TotalAssetOfBtc string `json:"totalAssetOfBtc"` + } `json:"data"` + Type string `json:"type"` + UpdateTime uint64 `json:"updateTime"` + } `json:"snapshotVos"` +} + +// Query Managed Sub Account Transfer Log (Investor) (USER_DATA) +const ( + queryManagedSubAccountTransferLogEndpoint = "/sapi/v1/managed-subaccount/queryTransLogForInvestor" +) + +type QueryManagedSubAccountTransferLogService struct { + c *Client + email string + startTime uint64 + endTime uint64 + page int + limit int + transfers *string + transferFunctionAccountType *string +} + +func (s *QueryManagedSubAccountTransferLogService) Email(email string) *QueryManagedSubAccountTransferLogService { + s.email = email + return s +} + +func (s *QueryManagedSubAccountTransferLogService) StartTime(startTime uint64) *QueryManagedSubAccountTransferLogService { + s.startTime = startTime + return s +} + +func (s *QueryManagedSubAccountTransferLogService) EndTime(endTime uint64) *QueryManagedSubAccountTransferLogService { + s.endTime = endTime + return s +} + +func (s *QueryManagedSubAccountTransferLogService) Page(page int) *QueryManagedSubAccountTransferLogService { + s.page = page + return s +} + +func (s *QueryManagedSubAccountTransferLogService) Limit(limit int) *QueryManagedSubAccountTransferLogService { + s.limit = limit + return s +} + +func (s *QueryManagedSubAccountTransferLogService) Transfers(transfers string) *QueryManagedSubAccountTransferLogService { + s.transfers = &transfers + return s +} + +func (s *QueryManagedSubAccountTransferLogService) TransferFunctionAccountType(transferFunctionAccountType string) *QueryManagedSubAccountTransferLogService { + s.transferFunctionAccountType = &transferFunctionAccountType + return s +} + +func (s *QueryManagedSubAccountTransferLogService) Do(ctx context.Context) (res *QueryManagedSubAccountTransferLogResp, err error) { + r := &request{ + method: http.MethodGet, + endpoint: queryManagedSubAccountTransferLogEndpoint, + secType: secTypeSigned, + } + r.setParam("email", s.email) + r.setParam("startTime", s.startTime) + r.setParam("endTime", s.endTime) + r.setParam("page", s.page) + r.setParam("limit", s.limit) + if s.transfers != nil { + r.setParam("transfers", *s.transfers) + } + if s.transferFunctionAccountType != nil { + r.setParam("transferFunctionAccountType", *s.transferFunctionAccountType) + } + data, err := s.c.callAPI(ctx, r) + if err != nil { + return nil, err + } + res = new(QueryManagedSubAccountTransferLogResp) + err = json.Unmarshal(data, res) + if err != nil { + return nil, err + } + return res, nil +} + +type QueryManagedSubAccountTransferLogResp struct { + ManagerSubTransferHistoryVos []struct { + FromEmail string `json:"fromEmail"` + FromAccountType string `json:"fromAccountType"` + ToEmail string `json:"toEmail"` + ToAccountType string `json:"toAccountType"` + Asset string `json:"asset"` + Amount int `json:"amount"` + ScheduledData int `json:"scheduledData"` + CreateTime uint64 `json:"createTime"` + Status string `json:"status"` + } `json:"managerSubTransferHistoryVos"` + Count int `json:"count"` +} + +// Query Managed Sub-account Futures Asset Details(For Investor Master Account)(USER_DATA) +const ( + queryManagedSubAccountFuturesAssetDetailsEndpoint = "/sapi/v1/managed-subaccount/fetch-future-asset" +) + +type QueryManagedSubAccountFuturesAssetDetailsService struct { + c *Client + email string +} + +func (s *QueryManagedSubAccountFuturesAssetDetailsService) Email(email string) *QueryManagedSubAccountFuturesAssetDetailsService { + s.email = email + return s +} + +func (s *QueryManagedSubAccountFuturesAssetDetailsService) Do(ctx context.Context) (res *QueryManagedSubAccountFuturesAssetDetailsResp, err error) { + r := &request{ + method: http.MethodGet, + endpoint: queryManagedSubAccountFuturesAssetDetailsEndpoint, + secType: secTypeSigned, + } + r.setParam("email", s.email) + data, err := s.c.callAPI(ctx, r) + if err != nil { + return nil, err + } + res = new(QueryManagedSubAccountFuturesAssetDetailsResp) + err = json.Unmarshal(data, res) + if err != nil { + return nil, err + } + return res, nil +} + +type QueryManagedSubAccountFuturesAssetDetailsResp struct { + Code int `json:"code"` + Message string `json:"message"` + SnapshotVos []struct { + Type string `json:"type"` + UpdateTime uint64 `json:"updateTime"` + Data struct { + Assets []struct { + Asset string `json:"asset"` + MarginBalance int64 `json:"marginBalance"` + WalletBalance int64 `json:"walletBalance"` + } `json:"assets"` + Position []struct { + Symbol string `json:"symbol"` + EntryPrice int64 `json:"entryPrice"` + MarkPrice int64 `json:"markPrice"` + PositionAmt int64 `json:"positionAmt"` + } `json:"position"` + } `json:"data"` + } `json:"snapshotVos"` +} + +// Query Managed Sub-account Margin Asset Details (For Investor Master Account) (USER_DATA) +const ( + queryManagedSubAccountMarginAssetDetailsEndpoint = "/sapi/v1/managed-subaccount/marginAsset" +) + +type QueryManagedSubAccountMarginAssetDetailsService struct { + c *Client + email string +} + +func (s *QueryManagedSubAccountMarginAssetDetailsService) Email(email string) *QueryManagedSubAccountMarginAssetDetailsService { + s.email = email + return s +} + +func (s *QueryManagedSubAccountMarginAssetDetailsService) Do(ctx context.Context) (res *QueryManagedSubAccountMarginAssetDetailsResp, err error) { + r := &request{ + method: http.MethodGet, + endpoint: queryManagedSubAccountMarginAssetDetailsEndpoint, + secType: secTypeSigned, + } + r.setParam("email", s.email) + data, err := s.c.callAPI(ctx, r) + if err != nil { + return nil, err + } + res = new(QueryManagedSubAccountMarginAssetDetailsResp) + err = json.Unmarshal(data, res) + if err != nil { + return nil, err + } + return res, nil +} + +type QueryManagedSubAccountMarginAssetDetailsResp struct { + MarginLevel string `json:"marginLevel"` + TotalAssetOfBtc string `json:"totalAssetOfBtc"` + TotalLiabilityOfBtc string `json:"totalLiabilityOfBtc"` + TotalNetAssetOfBtc string `json:"totalNetAssetOfBtc"` + UserAssets []struct { + Asset string `json:"asset"` + Borrowed string `json:"borrowed"` + Free string `json:"free"` + Interest string `json:"interest"` + Locked string `json:"locked"` + NetAsset string `json:"netAsset"` + } `json:"userAssets"` +} + +// Query Managed Sub Account Transfer Log (Trading Team) (USER_DATA) +const ( + queryManagedSubAccountTransferLogForTradingTeamEndpoint = "/sapi/v1/managed-subaccount/queryTransLogForTradeParent" +) + +type QueryManagedSubAccountTransferLogForTradingTeamService struct { + c *Client + email string + startTime uint64 + endTime uint64 + page int + limit int + transfers *string + transferFunctionAccountType *string +} + +func (s *QueryManagedSubAccountTransferLogForTradingTeamService) Email(email string) *QueryManagedSubAccountTransferLogForTradingTeamService { + s.email = email + return s +} + +func (s *QueryManagedSubAccountTransferLogForTradingTeamService) StartTime(startTime uint64) *QueryManagedSubAccountTransferLogForTradingTeamService { + s.startTime = startTime + return s +} + +func (s *QueryManagedSubAccountTransferLogForTradingTeamService) EndTime(endTime uint64) *QueryManagedSubAccountTransferLogForTradingTeamService { + s.endTime = endTime + return s +} + +func (s *QueryManagedSubAccountTransferLogForTradingTeamService) Page(page int) *QueryManagedSubAccountTransferLogForTradingTeamService { + s.page = page + return s +} + +func (s *QueryManagedSubAccountTransferLogForTradingTeamService) Limit(limit int) *QueryManagedSubAccountTransferLogForTradingTeamService { + s.limit = limit + return s +} + +func (s *QueryManagedSubAccountTransferLogForTradingTeamService) Transfers(transfers string) *QueryManagedSubAccountTransferLogForTradingTeamService { + s.transfers = &transfers + return s +} + +func (s *QueryManagedSubAccountTransferLogForTradingTeamService) TransferFunctionAccountType(transferFunctionAccountType string) *QueryManagedSubAccountTransferLogForTradingTeamService { + s.transferFunctionAccountType = &transferFunctionAccountType + return s +} + +func (s *QueryManagedSubAccountTransferLogForTradingTeamService) Do(ctx context.Context) (res *QueryManagedSubAccountTransferLogForTradingTeamResp, err error) { + r := &request{ + method: http.MethodGet, + endpoint: queryManagedSubAccountTransferLogForTradingTeamEndpoint, + secType: secTypeSigned, + } + r.setParam("email", s.email) + r.setParam("startTime", s.startTime) + r.setParam("endTime", s.endTime) + r.setParam("page", s.page) + r.setParam("limit", s.limit) + if s.transfers != nil { + r.setParam("transfers", *s.transfers) + } + if s.transferFunctionAccountType != nil { + r.setParam("transferFunctionAccountType", *s.transferFunctionAccountType) + } + data, err := s.c.callAPI(ctx, r) + if err != nil { + return nil, err + } + res = new(QueryManagedSubAccountTransferLogForTradingTeamResp) + err = json.Unmarshal(data, res) + if err != nil { + return nil, err + } + return res, nil +} + +type QueryManagedSubAccountTransferLogForTradingTeamResp struct { + ManagerSubTransferHistoryVos []struct { + FromEmail string `json:"fromEmail"` + FromAccountType string `json:"fromAccountType"` + ToEmail string `json:"toEmail"` + ToAccountType string `json:"toAccountType"` + Asset string `json:"asset"` + Amount string `json:"amount"` + ScheduledData int64 `json:"scheduledData"` + CreateTime uint64 `json:"createTime"` + Status string `json:"status"` + } `json:"managerSubTransferHistoryVos"` + Count int `json:"count"` +} + +// Query Sub-account Assets (For Master Account)(USER_DATA) +const ( + querySubAccountAssetsForMasterAccountEndpoint = "/sapi/v4/sub-account/assets" +) + +type QuerySubAccountAssetsForMasterAccountService struct { + c *Client + email string +} + +func (s *QuerySubAccountAssetsForMasterAccountService) Email(email string) *QuerySubAccountAssetsForMasterAccountService { + s.email = email + return s +} + +func (s *QuerySubAccountAssetsForMasterAccountService) Do(ctx context.Context) (res *QuerySubAccountAssetsForMasterAccountResp, err error) { + r := &request{ + method: http.MethodGet, + endpoint: querySubAccountAssetsForMasterAccountEndpoint, + secType: secTypeSigned, + } + r.setParam("email", s.email) + data, err := s.c.callAPI(ctx, r) + if err != nil { + return nil, err + } + res = new(QuerySubAccountAssetsForMasterAccountResp) + err = json.Unmarshal(data, res) + if err != nil { + return nil, err + } + return res, nil +} + +type QuerySubAccountAssetsForMasterAccountResp struct { + Balances []struct { + Asset string `json:"asset"` + Free string `json:"free"` + Locked string `json:"locked"` + } `json:"balances"` +} + +// Query Managed Sub-account List +const ( + queryManagedSubAccountListEndpoint = "/sapi/v1/managed-subaccount/info" +) + +type QueryManagedSubAccountList struct { + c *Client + email *string + page *int + limit *int +} + +func (s *QueryManagedSubAccountList) Email(email string) *QueryManagedSubAccountList { + s.email = &email + return s +} + +func (s *QueryManagedSubAccountList) Page(page int) *QueryManagedSubAccountList { + s.page = &page + return s +} + +func (s *QueryManagedSubAccountList) Limit(limit int) *QueryManagedSubAccountList { + s.limit = &limit + return s +} + +func (s *QueryManagedSubAccountList) Do(ctx context.Context) (res *QueryManagedSubAccountListResp, err error) { + r := &request{ + method: http.MethodGet, + endpoint: queryManagedSubAccountListEndpoint, + secType: secTypeSigned, + } + if s.email != nil { + r.setParam("email", *s.email) + } + if s.page != nil { + r.setParam("page", strconv.Itoa(*s.page)) + } + if s.limit != nil { + r.setParam("limit", strconv.Itoa(*s.limit)) + } + data, err := s.c.callAPI(ctx, r) + if err != nil { + return nil, err + } + res = new(QueryManagedSubAccountListResp) + err = json.Unmarshal(data, res) + if err != nil { + return nil, err + } + return res, nil +} + +type QueryManagedSubAccountListResp struct { + Total int `json:"total"` + ManagerSubUserInfoVoList []struct { + RootUserId int `json:"rootUserId"` + ManagersubUserId int `json:"managersubUserId"` + BindParentUserId int `json:"bindParentUserId"` + Email string `json:"email"` + InsertTimestamp uint64 `json:"insertTimestamp"` + BindParentEmail string `json:"bindParentEmail"` + IsSubUserEnabled bool `json:"isSubUserEnabled"` + IsUserActive bool `json:"isUserActive"` + IsMarginEnabled bool `json:"isMarginEnabled"` + IsFutureEnabled bool `json:"isFutureEnabled"` + IsSignedLVTRiskAgreement bool `json:"isSignedLVTRiskAgreement"` + } `json:"managerSubUserInfoVoList"` +} + +// Query Sub-account Transaction Tatistics (For Master Account) (USER_DATA) +const ( + QuerySubAccountTransactionTatisticsEndpoint = "/sapi/v1/sub-account/transaction-tatistics" +) + +type QuerySubAccountTransactionTatistics struct { + c *Client + email string +} + +func (s *QuerySubAccountTransactionTatistics) Email(email string) *QuerySubAccountTransactionTatistics { + s.email = email + return s +} + +func (s *QuerySubAccountTransactionTatistics) Do(ctx context.Context) (res *QuerySubAccountTransactionTatisticsResp, err error) { + r := &request{ + method: http.MethodGet, + endpoint: QuerySubAccountTransactionTatisticsEndpoint, + secType: secTypeSigned, + } + r.setParam("email", s.email) + data, err := s.c.callAPI(ctx, r) + if err != nil { + return nil, err + } + res = new(QuerySubAccountTransactionTatisticsResp) + err = json.Unmarshal(data, res) + if err != nil { + return nil, err + } + return res, nil +} + +type QuerySubAccountTransactionTatisticsResp struct { + Recent30BtcTotal string `json:"recent30BtcTotal"` + Recent30BtcFuturesTotal string `json:"recent30BtcFuturesTotal"` + Recent30BtcMarginTotal string `json:"recent30BtcMarginTotal"` + Recent30BusdTotal string `json:"recent30BusdTotal"` + Recent30BusdFuturesTotal string `json:"recent30BusdFuturesTotal"` + Recent30BusdMarginTotal string `json:"recent30BusdMarginTotal"` + TradeInfoVos []struct { + UserId int64 `json:"userId"` + Btc int `json:"btc"` + BtcFutures int `json:"btcFutures"` + BtcMargin int `json:"btcMargin"` + Busd int `json:"busd"` + BusdFutures int `json:"busdFutures"` + BusdMargin int `json:"busdMargin"` + Date int64 `json:"date"` + } `json:"tradeInfoVos"` +} diff --git a/subaccount_test.go b/subaccount_test.go new file mode 100644 index 0000000..8d4986d --- /dev/null +++ b/subaccount_test.go @@ -0,0 +1,1538 @@ +package binance_connector + +import ( + "context" + "encoding/json" + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/suite" +) + +type subAccountTestSuite struct { + baseTestSuite +} + +func TestSubAccount(t *testing.T) { + suite.Run(t, new(subAccountTestSuite)) +} + +func (s *subAccountTestSuite) TestSubaccountDepositAddressService() { + data := []byte(` + { + "address":"TDunhSa7jkTNuKrusUTU1MUHtqXoBPKETV", + "coin":"USDT", + "tag":"a_tag", + "url":"https://tronscan.org/#/address/TDunhSa7jkTNuKrusUTU1MUHtqXoBPKETV" + } + `) + s.mockDo(data, nil) + defer s.assertDo() + + email := "testsub@gmail.com" + coin := "a_coin" + network := "a_network" + + s.assertReq(func(r *request) { + e := newSignedRequest().setParams(params{ + "email": email, + "coin": coin, + "network": network, + }) + s.assertRequestEqual(e, r) + }) + + res, err := s.client.NewGetSubAccountDepositAddressService(). + Email(email). + Coin(coin). + Network(network). + Do(newContext()) + + r := s.r() + r.NoError(err) + r.Equal("TDunhSa7jkTNuKrusUTU1MUHtqXoBPKETV", res.Address, "Address") + r.Equal("USDT", res.Coin, "Coin") + r.Equal("a_tag", res.Tag, "Tag") + r.Equal("https://tronscan.org/#/address/TDunhSa7jkTNuKrusUTU1MUHtqXoBPKETV", res.Url, "URL") +} + +func (s *subAccountTestSuite) TestInternalUniversalTransferHistory() { + data := []byte(` + { + "result": [ + { + "tranId": 92275823339, + "fromEmail": "sub1@gmail.com", + "toEmail": "sub2@gmail.com", + "asset": "USDT", + "amount": "100.0", + "createTimeStamp": 1640317374000, + "fromAccountType": "USDT_FUTURE", + "toAccountType": "SPOT", + "status": "SUCCESS", + "clientTranId": "testID" + } + ], + "totalCount": 1 + } + `) + s.mockDo(data, nil) + defer s.assertDo() + + fromEmail := "sub1@gmail.com" + toEmail := "sub2@gmail.com" + clientTranId := "testID" + endTime := time.Now().UnixNano() / 1000 / 1000 + startTime := endTime - 3600*1000 + page := 1 + limit := 10 + s.assertReq(func(r *request) { + e := newSignedRequest().setParams(params{ + "fromEmail": fromEmail, + "toEmail": toEmail, + "startTime": startTime, + "endTime": endTime, + "clientTranId": clientTranId, + "page": 1, + "limit": 10, + }) + s.assertRequestEqual(e, r) + }) + + res, err := s.client.NewQueryUniversalTransferHistoryService(). + FromEmail(fromEmail). + ToEmail(toEmail). + StartTime(uint64(startTime)). + EndTime(uint64(endTime)). + Page(page). + Limit(limit). + ClientTranId(clientTranId). + Do(newContext()) + + r := s.r() + r.NoError(err) + + s.assertInternalUniversalTransferEqual(&InternalUniversalTransfer{ + FromEmail: fromEmail, + ToEmail: toEmail, + FromAccountType: "USDT_FUTURE", + ToAccountType: "SPOT", + TranId: 92275823339, + ClientTranId: clientTranId, + Asset: "USDT", + Amount: "100.0", + Status: "SUCCESS", + CreateTimeStamp: 1640317374000, + }, res.Result[0]) + r.Equal(1, res.TotalCount, "TotalCount") +} + +func (s *subAccountTestSuite) assertInternalUniversalTransferEqual(e, a *InternalUniversalTransfer) { + r := s.r() + r.Equal(e.FromEmail, a.FromEmail, "FromEmail") + r.Equal(e.ToEmail, a.ToEmail, "ToEmail") + r.Equal(e.FromAccountType, a.FromAccountType, "FromAccountType") + r.Equal(e.ToAccountType, a.ToAccountType, "ToAccountType") + r.Equal(e.TranId, a.TranId, "TranId") + r.Equal(e.ClientTranId, a.ClientTranId, "ClientTranId") + r.Equal(e.Asset, a.Asset, "Asset") + r.Equal(e.Amount, a.Amount, "Amount") + r.Equal(e.Status, a.Status, "Status") + r.Equal(e.CreateTimeStamp, a.CreateTimeStamp, "CreateTimeStamp") +} + +func (s *subAccountTestSuite) TestCreateSubAccount() { + expectedEmail := "test@example.com" + data := []byte(fmt.Sprintf(`{"email": "%s"}`, expectedEmail)) + + s.mockDo(data, nil) + defer s.assertDo() + + resp, err := s.client.NewCreateSubAccountService(). + SubAccountString("Test Subaccount"). + Do(context.Background()) + + s.r().NoError(err) + s.Equal(expectedEmail, resp.Email) +} + +func (s *subAccountTestSuite) TestDeleteIPListForSubAccountAPIKey() { + ipAddress := "192.168.0.1" + respData := []byte(` + { + "ipRestrict": "NONE", + "ipList": [ + { + "ip": "192.168.0.2" + }, + { + "ip": "192.168.0.3" + } + ], + "updateTime": 1617205250105, + "apiKey": "a1b2c3d4" + } + `) + s.mockDo(respData, nil) + defer s.assertDo() + + resp, err := s.client.NewDeleteIPListForSubAccountAPIKeyService(). + Email("subaccount@example.com"). + SubAccountApiKey("a1b2c3d4"). + IpAddress(ipAddress). + Do(context.Background()) + + s.r().NoError(err) + s.Equal("NONE", resp.IpRestrict) + s.Len(resp.IpList, 2) + s.Equal("192.168.0.2", resp.IpList[0].Ip) + s.Equal("192.168.0.3", resp.IpList[1].Ip) + s.Equal(uint64(1617205250105), resp.UpdateTime) + s.Equal("a1b2c3d4", resp.ApiKey) +} + +func (s *subAccountTestSuite) TestDepositAssetsIntoTheManagedSubAccount() { + data := []byte(`{"tranId":123}`) + s.mockDo(data, nil) + defer s.assertDo() + + toEmail := "test@example.com" + asset := "BTC" + amount := 1.0 + + resp, err := s.client.NewDepositAssetsIntoManagedSubAccountService(). + ToEmail(toEmail). + Asset(asset). + Amount(amount). + Do(context.Background()) + + s.r().NoError(err) + s.Equal(int64(123), resp.TranId) +} + +func (s *subAccountTestSuite) TestEnableFuturesForSubAccount() { + data := []byte(`{"email":"test@test.com", "isFuturesEnabled": true}`) + s.mockDo(data, nil) + defer s.assertDo() + + resp, err := s.client.NewEnableFuturesForSubAccountService(). + Email("test@test.com"). + Do(context.Background()) + + s.r().NoError(err) + s.Equal("test@test.com", resp.Email) + s.True(resp.IsFuturesEnabled) +} + +func (s *marginTestSuite) TestEnableLeverageTokenForSubAccount() { + data := []byte(`{ + "email": "example@example.com", + "enableBlvt": true + }`) + + s.mockDo(data, nil) + defer s.assertDo() + + resp, err := s.client.NewEnableLeverageTokenForSubAccountService(). + Email("example@example.com"). + EnableBlvt(true). + Do(context.Background()) + + s.r().NoError(err) + s.Equal("example@example.com", resp.Email) + s.True(resp.EnableBlvt) +} + +func (s *marginTestSuite) TestEnableMarginForSubAccount() { + email := "test@example.com" + expectedResp := &EnableMarginForSubAccountResp{ + Email: email, + IsMarginEnabled: true, + } + + data, _ := json.Marshal(expectedResp) + s.mockDo(data, nil) + defer s.assertDo() + + resp, err := s.client.NewEnableMarginForSubAccountService(). + Email(email). + Do(context.Background()) + + s.r().NoError(err) + s.Equal(expectedResp.Email, resp.Email) + s.Equal(expectedResp.IsMarginEnabled, resp.IsMarginEnabled) +} + +func (s *subAccountTestSuite) TestFuturesTransferForSubAccount() { + data := []byte(`{"txnId":12345}`) + s.mockDo(data, nil) + defer s.assertDo() + + email := "example@binance.com" + asset := "BTC" + amount := 1.0 + transferType := 2 + + resp, err := s.client.NewFuturesTransferForSubAccountService(). + Email(email). + Asset(asset). + Amount(amount). + TransferType(transferType). + Do(context.Background()) + + s.r().NoError(err) + s.NotNil(resp) + s.Equal(12345, resp.TxnId) +} + +func (s *subAccountTestSuite) TestGetDetailOnSubAccountFuturesAccount() { + data := []byte(`{ + "email": "user@example.com", + "asset": "BNB", + "assets": [ + { + "asset": "BTC", + "initialMargin": "0.001", + "maintenanceMargin": "0.001", + "marginBalance": "0.001", + "maxWithdrawAmount": "0.001", + "openOrderInitialMargin": "0.001", + "positionInitialMargin": "0.001", + "unrealizedProfit": "0.001", + "walletBalance": "0.001" + } + ], + "canDeposit": true, + "canTrade": true, + "canWithdraw": true, + "feeTier": 1, + "maxWithdrawAmount": "0.001", + "totalInitialMargin": "0.001", + "totalMaintenanceMargin": "0.001", + "totalMarginBalance": "0.001", + "totalOpenOrderInitialMargin": "0.001", + "totalPositionInitialMargin": "0.001", + "totalUnrealizedProfit": "0.001", + "totalWalletBalance": "0.001", + "updateTime": 1613450271000 + }`) + s.mockDo(data, nil) + defer s.assertDo() + + resp, err := s.client.NewGetDetailOnSubAccountFuturesAccountService(). + Email("user@example.com"). + Do(context.Background()) + + s.r().NoError(err) + s.Equal("user@example.com", resp.Email) + s.Equal("BNB", resp.Asset) + s.Len(resp.Assets, 1) + s.Equal("BTC", resp.Assets[0].Asset) + s.Equal("0.001", resp.Assets[0].InitialMargin) + s.Equal("0.001", resp.Assets[0].MaintenanceMargin) + s.Equal("0.001", resp.Assets[0].MarginBalance) + s.Equal("0.001", resp.Assets[0].MaxWithdrawAmount) + s.Equal("0.001", resp.Assets[0].OpenOrderInitialMargin) + s.Equal("0.001", resp.Assets[0].PositionInitialMargin) + s.Equal("0.001", resp.Assets[0].UnrealizedProfit) + s.Equal("0.001", resp.Assets[0].WalletBalance) + s.True(resp.CanDeposit) + s.True(resp.CanTrade) + s.True(resp.CanWithdraw) + s.Equal(1, resp.FeeTier) + s.Equal("0.001", resp.MaxWithdrawAmount) + s.Equal("0.001", resp.TotalInitialMargin) + s.Equal("0.001", resp.TotalMaintenanceMargin) + s.Equal("0.001", resp.TotalMarginBalance) + s.Equal("0.001", resp.TotalOpenOrderInitialMargin) + s.Equal("0.001", resp.TotalPositionInitialMargin) + s.Equal("0.001", resp.TotalUnrealizedProfit) + s.Equal("0.001", resp.TotalWalletBalance) + s.Equal(uint64(1613450271000), resp.UpdateTime) +} + +func (s *subAccountTestSuite) TestGetDetailOnSubAccountFuturesAccountV2() { + data := []byte(` + { + "success": true, + "futuresType": 1, + "transfers": [ + { + "from": "aaa", + "to": "bbb", + "asset": "BTC", + "qty": "1.00000000", + "tranId": 123, + "time": 1613450271000 + }, + { + "from": "bbb", + "to": "aaa", + "asset": "ETH", + "qty": "10.00000000", + "tranId": 456, + "time": 1613450272000 + } + ] + } + `) + + s.mockDo(data, nil) + defer s.assertDo() + + resp, err := s.client.NewGetDetailOnSubAccountFuturesAccountV2Service(). + Email("test@example.com"). + FuturesType(1). + Do(context.Background()) + + s.r().NoError(err) + s.True(resp.Success) + s.Equal(1, resp.FuturesType) + s.Len(resp.Transfers, 2) + s.Equal("aaa", resp.Transfers[0].From) + s.Equal("bbb", resp.Transfers[0].To) + s.Equal("BTC", resp.Transfers[0].Asset) + s.Equal("1.00000000", resp.Transfers[0].Qty) + s.Equal(int64(123), resp.Transfers[0].TranId) + s.Equal(uint64(1613450271000), resp.Transfers[0].Time) + s.Equal("bbb", resp.Transfers[1].From) + s.Equal("aaa", resp.Transfers[1].To) + s.Equal("ETH", resp.Transfers[1].Asset) + s.Equal("10.00000000", resp.Transfers[1].Qty) + s.Equal(int64(456), resp.Transfers[1].TranId) + s.Equal(uint64(1613450272000), resp.Transfers[1].Time) +} + +func (s *subAccountTestSuite) TestGetDetailOnSubAccountMarginAccount() { + data := []byte(` + { + "email": "test@example.com", + "marginLevel": "1.00000000", + "totalAssetOfBtc": "0.10000000", + "totalLiabilityOfBtc": "0.00000000", + "totalNetAssetOfBtc": "0.10000000", + "marginTradeCoeffVo": { + "forceLiquidationRate": "1.00000000", + "marginCallBar": "1.00000000", + "normalBar": "1.00000000" + }, + "marginUserAssetVoList": [ + { + "asset": "BTC", + "borrowed": "0.00000000", + "free": "0.10000000", + "interest": "0.00000000", + "locked": "0.00000000", + "netAsset": "0.10000000" + } + ] + } + `) + + s.mockDo(data, nil) + defer s.assertDo() + + resp, err := s.client.NewGetDetailOnSubAccountMarginAccountService(). + Email("test@example.com"). + Do(context.Background()) + + s.r().NoError(err) + s.Equal("test@example.com", resp.Email) + s.Equal("1.00000000", resp.MarginLevel) + s.Equal("0.10000000", resp.TotalAssetOfBtc) + s.Equal("0.00000000", resp.TotalLiabilityOfBtc) + s.Equal("0.10000000", resp.TotalNetAssetOfBtc) + s.Equal("1.00000000", resp.MarginTradeCoeffVo.ForceLiquidationRate) + s.Equal("1.00000000", resp.MarginTradeCoeffVo.MarginCallBar) + s.Equal("1.00000000", resp.MarginTradeCoeffVo.NormalBar) + s.Len(resp.MarginUserAssetVoList, 1) + s.Equal("BTC", resp.MarginUserAssetVoList[0].Asset) + s.Equal("0.00000000", resp.MarginUserAssetVoList[0].Borrowed) + s.Equal("0.10000000", resp.MarginUserAssetVoList[0].Free) + s.Equal("0.00000000", resp.MarginUserAssetVoList[0].Interest) + s.Equal("0.00000000", resp.MarginUserAssetVoList[0].Locked) + s.Equal("0.10000000", resp.MarginUserAssetVoList[0].NetAsset) +} + +func (s *subAccountTestSuite) TestGetFuturesPositionRiskOfSubAccount() { + data := []byte(`{ + "entryPrice": "36621.32911", + "leverage": "1", + "maxNotional": "2000000", + "liquidationPrice": "0", + "markPrice": "36772.64828", + "positionAmount": "1.00000000", + "symbol": "BTCUSDT", + "unrealizedProfit": "11.99924692" + }`) + + s.mockDo(data, nil) + defer s.assertDo() + + resp, err := s.client.NewGetFuturesPositionRiskOfSubAccountService(). + Email("example@example.com"). + Do(context.Background()) + + s.r().NoError(err) + s.Equal("36621.32911", resp.EntryPrice) + s.Equal("1", resp.Leverage) + s.Equal("2000000", resp.MaxNotional) + s.Equal("0", resp.LiquidationPrice) + s.Equal("36772.64828", resp.MarkPrice) + s.Equal("1.00000000", resp.PositionAmount) + s.Equal("BTCUSDT", resp.Symbol) + s.Equal("11.99924692", resp.UnrealizedProfit) +} + +func (s *subAccountTestSuite) TestGetFuturesPositionRiskOfSubAccountV2() { + data := []byte(` + { + "futurePositionRiskVos": [ + { + "entryPrice": "56789.01234567", + "leverage": "1", + "maxNotional": "1000000", + "liquidationPrice": "55555.55555555", + "markPrice": "56789.01234567", + "positionAmount": "10", + "symbol": "BTCUSDT", + "unrealizedProfit": "0.001" + } + ] + }`) + + s.mockDo(data, nil) + defer s.assertDo() + + resp, err := s.client.NewGetFuturesPositionRiskOfSubAccountV2Service(). + Email("test@example.com"). + FuturesType(1). + Do(context.Background()) + + s.r().NoError(err) + s.Len(resp.FuturePositionRiskVos, 1) + s.Equal("56789.01234567", resp.FuturePositionRiskVos[0].EntryPrice) + s.Equal("1", resp.FuturePositionRiskVos[0].Leverage) + s.Equal("1000000", resp.FuturePositionRiskVos[0].MaxNotional) + s.Equal("55555.55555555", resp.FuturePositionRiskVos[0].LiquidationPrice) + s.Equal("56789.01234567", resp.FuturePositionRiskVos[0].MarkPrice) + s.Equal("10", resp.FuturePositionRiskVos[0].PositionAmount) + s.Equal("BTCUSDT", resp.FuturePositionRiskVos[0].Symbol) + s.Equal("0.001", resp.FuturePositionRiskVos[0].UnrealizedProfit) +} + +func (s *subAccountTestSuite) TestGetIPRestrictionForSubAccountAPIKey() { + data := []byte(` + { + "ipRestrict": "NONE", + "ipList": [ + { + "ip": "0.0.0.0/0" + } + ], + "updateTime": 1617137789000, + "apiKey": "some-api-key" + } + `) + + s.mockDo(data, nil) + defer s.assertDo() + + resp, err := s.client.NewGetIPRestrictionForSubAccountAPIKeyService(). + Email("subaccount@example.com"). + SubAccountApiKey("some-api-key"). + Do(context.Background()) + + s.r().NoError(err) + s.NotNil(resp) + s.Equal("NONE", resp.IpRestrict) + s.Len(resp.IpList, 1) + s.Equal("0.0.0.0/0", resp.IpList[0].Ip) + s.Equal(uint64(1617137789000), resp.UpdateTime) + s.Equal("some-api-key", resp.ApiKey) +} + +func (s *subAccountTestSuite) TestGetSubAccountDepositHistory() { + data := []byte(` + { + "depositList": [ + { + "id": 123, + "amount": "1.00000000", + "coin": "BTC", + "network": "", + "status": 1, + "address": "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa", + "addressTag": "", + "txId": "tx123", + "insertTime": 1613450271000, + "transferType": 0, + "confirmTimes": "0/1", + "unlockConfirm": 2, + "walletType": 1 + } + ] + } + `) + + s.mockDo(data, nil) + defer s.assertDo() + + resp, err := s.client.NewGetSubAccountDepositHistoryService(). + Email("test@test.com"). + Coin("BTC"). + Status(1). + StartTime(1613450271000). + EndTime(1613536671000). + Limit(500). + Offset(0). + Do(context.Background()) + + s.r().NoError(err) + s.Len(resp.DepositList, 1) + s.Equal(int64(123), resp.DepositList[0].Id) + s.Equal("1.00000000", resp.DepositList[0].Amount) + s.Equal("BTC", resp.DepositList[0].Coin) + s.Equal("", resp.DepositList[0].Network) + s.Equal(int64(1), resp.DepositList[0].Status) + s.Equal("1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa", resp.DepositList[0].Address) + s.Equal("", resp.DepositList[0].AddressTag) + s.Equal("tx123", resp.DepositList[0].TxId) + s.Equal(uint64(1613450271000), resp.DepositList[0].InsertTime) + s.Equal(int64(0), resp.DepositList[0].TransferType) + s.Equal("0/1", resp.DepositList[0].ConfirmTimes) + s.Equal(int64(2), resp.DepositList[0].UnlockConfirm) + s.Equal(1, resp.DepositList[0].WalletType) +} + +func (s *subAccountTestSuite) TestGetSubAccountStatus() { + data := []byte(` + { + "email": "user@example.com", + "isSubUserEnabled": true, + "isUserActive": true, + "insertTime": 1621829948472, + "isMarginEnabled": true, + "isFuturesEnabled": false, + "mobile": 1234567890 + } + `) + + s.mockDo(data, nil) + defer s.assertDo() + + resp, err := s.client.NewGetSubAccountStatusService(). + Email("user@example.com"). + Do(context.Background()) + + s.r().NoError(err) + s.Equal("user@example.com", resp.Email) + s.True(resp.IsSubUserEnabled) + s.True(resp.IsUserActive) + s.Equal(uint64(1621829948472), resp.InsertTime) + s.True(resp.IsMarginEnabled) + s.False(resp.IsFuturesEnabled) + s.Equal(int64(1234567890), resp.Mobile) +} + +func (s *subAccountTestSuite) TestGetSummaryOfSubAccountFuturesAccount() { + data := []byte(` + { + "totalInitialMargin": "1.00000000", + "totalMaintenanceMargin": "1.00000000", + "totalMarginBalance": "1.00000000", + "totalOpenOrderInitialMargin": "1.00000000", + "totalPositionInitialMargin": "1.00000000", + "totalUnrealizedProfit": "1.00000000", + "totalWalletBalance": "1.00000000", + "asset": "BTC", + "subAccountList": [ + { + "email": "example@example.com", + "totalInitialMargin": "1.00000000", + "totalMaintenanceMargin": "1.00000000", + "totalMarginBalance": "1.00000000", + "totalOpenOrderInitialMargin": "1.00000000", + "totalPositionInitialMargin": "1.00000000", + "totalUnrealizedProfit": "1.00000000", + "totalWalletBalance": "1.00000000", + "asset": "BTC" + } + ] + } + `) + + s.mockDo(data, nil) + defer s.assertDo() + + resp, err := s.client.NewGetSummaryOfSubAccountFuturesAccountService().Do(context.Background()) + + s.r().NoError(err) + s.Equal("1.00000000", resp.TotalInitialMargin) + s.Equal("1.00000000", resp.TotalMaintenanceMargin) + s.Equal("1.00000000", resp.TotalMarginBalance) + s.Equal("1.00000000", resp.TotalOpenOrderInitialMargin) + s.Equal("1.00000000", resp.TotalPositionInitialMargin) + s.Equal("1.00000000", resp.TotalUnrealizedProfit) + s.Equal("1.00000000", resp.TotalWalletBalance) + s.Equal("BTC", resp.Asset) + s.Len(resp.SubAccountList, 1) + s.Equal("example@example.com", resp.SubAccountList[0].Email) + s.Equal("1.00000000", resp.SubAccountList[0].TotalInitialMargin) + s.Equal("1.00000000", resp.SubAccountList[0].TotalMaintenanceMargin) + s.Equal("1.00000000", resp.SubAccountList[0].TotalMarginBalance) + s.Equal("1.00000000", resp.SubAccountList[0].TotalOpenOrderInitialMargin) + s.Equal("1.00000000", resp.SubAccountList[0].TotalPositionInitialMargin) + s.Equal("1.00000000", resp.SubAccountList[0].TotalUnrealizedProfit) + s.Equal("1.00000000", resp.SubAccountList[0].TotalWalletBalance) + s.Equal("BTC", resp.SubAccountList[0].Asset) +} + +func (s *subAccountTestSuite) TestGetSummaryOfSubAccountFuturesAccountV2() { + data := []byte(` + { + "futureAccountSummaryResp": { + "totalInitialMargin": "100.00000000", + "totalMaintenanceMargin": "50.00000000", + "totalMarginBalance": "150.00000000", + "totalOpenOrderInitialMargin": "25.00000000", + "totalPositionInitialMargin": "75.00000000", + "totalUnrealizedProfit": "10.00000000", + "totalWalletBalance": "160.00000000", + "asset": "BTC", + "subAccountList": [ + { + "email": "test1@test.com", + "totalInitialMargin": "50.00000000", + "totalMaintenanceMargin": "25.00000000", + "totalMarginBalance": "75.00000000", + "totalOpenOrderInitialMargin": "15.00000000", + "totalPositionInitialMargin": "45.00000000", + "totalUnrealizedProfit": "5.00000000", + "totalWalletBalance": "80.00000000", + "asset": "BTC" + }, + { + "email": "test2@test.com", + "totalInitialMargin": "50.00000000", + "totalMaintenanceMargin": "25.00000000", + "totalMarginBalance": "75.00000000", + "totalOpenOrderInitialMargin": "10.00000000", + "totalPositionInitialMargin": "30.00000000", + "totalUnrealizedProfit": "5.00000000", + "totalWalletBalance": "80.00000000", + "asset": "BTC" + } + ] + } + } + `) + + s.mockDo(data, nil) + defer s.assertDo() + + resp, err := s.client.NewGetSummaryOfSubAccountFuturesAccountV2Service(). + FuturesType(1). + Page(1). + Limit(100). + Do(context.Background()) + + s.r().NoError(err) + s.Equal("100.00000000", resp.FutureAccountSummaryResp.TotalInitialMargin) + s.Equal("50.00000000", resp.FutureAccountSummaryResp.TotalMaintenanceMargin) + s.Equal("150.00000000", resp.FutureAccountSummaryResp.TotalMarginBalance) + s.Equal("25.00000000", resp.FutureAccountSummaryResp.TotalOpenOrderInitialMargin) + s.Equal("75.00000000", resp.FutureAccountSummaryResp.TotalPositionInitialMargin) + s.Equal("10.00000000", resp.FutureAccountSummaryResp.TotalUnrealizedProfit) + s.Equal("160.00000000", resp.FutureAccountSummaryResp.TotalWalletBalance) + s.Equal("BTC", resp.FutureAccountSummaryResp.Asset) + s.Len(resp.FutureAccountSummaryResp.SubAccountList, 2) + s.Equal("test1@test.com", resp.FutureAccountSummaryResp.SubAccountList[0].Email) + s.Equal("50.00000000", resp.FutureAccountSummaryResp.SubAccountList[0].TotalInitialMargin) + s.Equal("25.00000000", resp.FutureAccountSummaryResp.SubAccountList[0].TotalMaintenanceMargin) + s.Equal("75.00000000", resp.FutureAccountSummaryResp.SubAccountList[0].TotalMarginBalance) + s.Equal("15.00000000", resp.FutureAccountSummaryResp.SubAccountList[0].TotalOpenOrderInitialMargin) + s.Equal("45.00000000", resp.FutureAccountSummaryResp.SubAccountList[0].TotalPositionInitialMargin) + s.Equal("5.00000000", resp.FutureAccountSummaryResp.SubAccountList[0].TotalUnrealizedProfit) + s.Equal("80.00000000", resp.FutureAccountSummaryResp.SubAccountList[0].TotalWalletBalance) + s.Equal("BTC", resp.FutureAccountSummaryResp.SubAccountList[0].Asset) +} + +func (s *marginTestSuite) TestGetSummaryOfSubAccountMarginAccount() { + data := []byte(` + { + "totalAssetOfBtc": "0.10000000", + "totalLiabilityOfBtc": "0.05000000", + "totalNetAssetOfBtc": "0.05000000", + "subAccountList": [ + { + "email": "test@example.com", + "totalAssetOfBtc": "0.05000000", + "totalLiabilityOfBtc": "0.00000000", + "totalNetAssetOfBtc": "0.05000000" + } + ] + } + `) + + s.mockDo(data, nil) + defer s.assertDo() + + resp, err := s.client.NewGetSummaryOfSubAccountMarginAccountService(). + Do(context.Background()) + + s.r().NoError(err) + s.NotNil(resp) + s.Equal("0.10000000", resp.TotalAssetOfBtc) + s.Equal("0.05000000", resp.TotalLiabilityOfBtc) + s.Equal("0.05000000", resp.TotalNetAssetOfBtc) + s.Len(resp.SubAccountList, 1) + s.Equal("test@example.com", resp.SubAccountList[0].Email) + s.Equal("0.05000000", resp.SubAccountList[0].TotalAssetOfBtc) + s.Equal("0.00000000", resp.SubAccountList[0].TotalLiabilityOfBtc) + s.Equal("0.05000000", resp.SubAccountList[0].TotalNetAssetOfBtc) +} + +func (s *subAccountTestSuite) TestMarginTransferForSubAccount() { + data := []byte(` + { + "txnId": 12345 + } + `) + + s.mockDo(data, nil) + defer s.assertDo() + + resp, err := s.client.NewMarginTransferForSubAccountService(). + Email("test@example.com"). + Asset("BTC"). + Amount(1.23). + TransferType(1). + Do(context.Background()) + + s.r().NoError(err) + s.Equal(12345, resp.TxnId) +} + +func (s *subAccountTestSuite) TestQueryManagedSubAccountAssetDetails() { + data := []byte(` + { + "assetDetail": [ + { + "coin": "BTC", + "name": "Bitcoin", + "totalBalance": "1.00000000", + "availableBalance": "0.50000000", + "inOrder": "0.50000000", + "btcValue": "50000.00" + }, + { + "coin": "ETH", + "name": "Ethereum", + "totalBalance": "10.00000000", + "availableBalance": "5.00000000", + "inOrder": "5.00000000", + "btcValue": "3000.00" + } + ] + } + `) + + s.mockDo(data, nil) + defer s.assertDo() + + resp, err := s.client.NewQueryManagedSubAccountAssetDetailsService(). + Email("test@example.com"). + Do(context.Background()) + + s.r().NoError(err) + s.Len(resp.AssetDetail, 2) + s.Equal("BTC", resp.AssetDetail[0].Coin) + s.Equal("Bitcoin", resp.AssetDetail[0].Name) + s.Equal("1.00000000", resp.AssetDetail[0].TotalBalance) + s.Equal("0.50000000", resp.AssetDetail[0].AvailableBalance) + s.Equal("0.50000000", resp.AssetDetail[0].InOrder) + s.Equal("50000.00", resp.AssetDetail[0].BtcValue) + s.Equal("ETH", resp.AssetDetail[1].Coin) + s.Equal("Ethereum", resp.AssetDetail[1].Name) + s.Equal("10.00000000", resp.AssetDetail[1].TotalBalance) + s.Equal("5.00000000", resp.AssetDetail[1].AvailableBalance) + s.Equal("5.00000000", resp.AssetDetail[1].InOrder) + s.Equal("3000.00", resp.AssetDetail[1].BtcValue) +} + +func (s *subAccountTestSuite) TestQueryManagedSubAccountList() { + data := []byte(` + { + "total": 1, + "managerSubUserInfoVoList": [ + { + "rootUserId": 123456, + "managersubUserId": 789012, + "bindParentUserId": 345678, + "email": "test@example.com", + "insertTimestamp": 1613450271000, + "bindParentEmail": "parent@example.com", + "isSubUserEnabled": true, + "isUserActive": true, + "isMarginEnabled": true, + "isFutureEnabled": true, + "isSignedLVTRiskAgreement": true + } + ] + } + `) + + s.mockDo(data, nil) + defer s.assertDo() + + resp, err := s.client.NewQueryManagedSubAccountList(). + Email("test@example.com"). + Page(1). + Limit(500). + Do(context.Background()) + + s.r().NoError(err) + s.Equal(1, resp.Total) + s.Len(resp.ManagerSubUserInfoVoList, 1) + s.Equal(123456, resp.ManagerSubUserInfoVoList[0].RootUserId) + s.Equal(789012, resp.ManagerSubUserInfoVoList[0].ManagersubUserId) + s.Equal(345678, resp.ManagerSubUserInfoVoList[0].BindParentUserId) + s.Equal("test@example.com", resp.ManagerSubUserInfoVoList[0].Email) + s.Equal(uint64(1613450271000), resp.ManagerSubUserInfoVoList[0].InsertTimestamp) + s.Equal("parent@example.com", resp.ManagerSubUserInfoVoList[0].BindParentEmail) + s.True(resp.ManagerSubUserInfoVoList[0].IsSubUserEnabled) + s.True(resp.ManagerSubUserInfoVoList[0].IsUserActive) + s.True(resp.ManagerSubUserInfoVoList[0].IsMarginEnabled) + s.True(resp.ManagerSubUserInfoVoList[0].IsFutureEnabled) + s.True(resp.ManagerSubUserInfoVoList[0].IsSignedLVTRiskAgreement) +} + +func (s *accountTestSuite) TestQueryManagedSubAccountMarginAssetDetails() { + data := []byte(` + { + "marginLevel": "999.00000000", + "totalAssetOfBtc": "1.00000000", + "totalLiabilityOfBtc": "0.00000000", + "totalNetAssetOfBtc": "1.00000000", + "userAssets": [ + { + "asset": "BTC", + "borrowed": "0.00000000", + "free": "1.00000000", + "interest": "0.00000000", + "locked": "0.00000000", + "netAsset": "1.00000000" + }, + { + "asset": "ETH", + "borrowed": "0.00000000", + "free": "1.00000000", + "interest": "0.00000000", + "locked": "0.00000000", + "netAsset": "1.00000000" + } + ] + } + `) + + s.mockDo(data, nil) + defer s.assertDo() + + resp, err := s.client.NewQueryManagedSubAccountMarginAssetDetailsService(). + Email("test@example.com"). + Do(context.Background()) + + s.r().NoError(err) + s.Equal("999.00000000", resp.MarginLevel) + s.Equal("1.00000000", resp.TotalAssetOfBtc) + s.Equal("0.00000000", resp.TotalLiabilityOfBtc) + s.Equal("1.00000000", resp.TotalNetAssetOfBtc) + s.Len(resp.UserAssets, 2) + s.Equal("BTC", resp.UserAssets[0].Asset) + s.Equal("0.00000000", resp.UserAssets[0].Borrowed) + s.Equal("1.00000000", resp.UserAssets[0].Free) + s.Equal("0.00000000", resp.UserAssets[0].Interest) + s.Equal("0.00000000", resp.UserAssets[0].Locked) + s.Equal("1.00000000", resp.UserAssets[0].NetAsset) + s.Equal("ETH", resp.UserAssets[1].Asset) + s.Equal("0.00000000", resp.UserAssets[1].Borrowed) + s.Equal("1.00000000", resp.UserAssets[1].Free) + s.Equal("0.00000000", resp.UserAssets[1].Interest) + s.Equal("0.00000000", resp.UserAssets[1].Locked) + s.Equal("1.00000000", resp.UserAssets[1].NetAsset) +} + +func (s *subAccountTestSuite) TestQueryManagedSubAccountSnapshotService() { + data := []byte(` + { + "code": 200, + "msg": "success", + "snapshotVos": [ + { + "data": [ + { + "balances": [ + { + "asset": "BTC", + "free": "0.1", + "locked": "0.2" + }, + { + "asset": "ETH", + "free": "1.1", + "locked": "0.0" + } + ], + "totalAssetOfBtc": "0.025" + } + ], + "type": "SPOT", + "updateTime": 1619140921388 + } + ] + } + `) + + s.mockDo(data, nil) + defer s.assertDo() + + resp, err := s.client.NewQueryManagedSubAccountSnapshotService(). + Email("example@test.com"). + SubType("SPOT"). + StartTime(1619137321000). + EndTime(1619144521000). + Limit(10). + Do(context.Background()) + + s.r().NoError(err) + s.Equal(200, resp.Code) + s.Equal("success", resp.Msg) + s.Len(resp.SnapshotVos, 1) + s.Len(resp.SnapshotVos[0].Data, 1) + s.Len(resp.SnapshotVos[0].Data[0].Balances, 2) + s.Equal("BTC", resp.SnapshotVos[0].Data[0].Balances[0].Asset) + s.Equal("0.1", resp.SnapshotVos[0].Data[0].Balances[0].Free) + s.Equal("0.2", resp.SnapshotVos[0].Data[0].Balances[0].Locked) + s.Equal("ETH", resp.SnapshotVos[0].Data[0].Balances[1].Asset) + s.Equal("1.1", resp.SnapshotVos[0].Data[0].Balances[1].Free) + s.Equal("0.0", resp.SnapshotVos[0].Data[0].Balances[1].Locked) + s.Equal("0.025", resp.SnapshotVos[0].Data[0].TotalAssetOfBtc) + s.Equal("SPOT", resp.SnapshotVos[0].Type) + s.Equal(uint64(1619140921388), resp.SnapshotVos[0].UpdateTime) +} + +func (s *subAccountTestSuite) TestQueryManagedSubAccountTransferLogService() { + data := []byte(` + { + "managerSubTransferHistoryVos": [ + { + "fromEmail": "foo@bar.com", + "fromAccountType": "SPOT", + "toEmail": "baz@qux.com", + "toAccountType": "MARGIN", + "asset": "BTC", + "amount": 100000000, + "scheduledData": 0, + "createTime": 1613450271000, + "status": "SUCCESS" + } + ], + "count": 1 + } + `) + + s.mockDo(data, nil) + defer s.assertDo() + + resp, err := s.client.NewQueryManagedSubAccountTransferLogService(). + Email("foo@bar.com"). + StartTime(1613450271000). + EndTime(1613536671000). + Page(1). + Limit(500). + Transfers("IN"). + TransferFunctionAccountType("MARGIN"). + Do(context.Background()) + + s.r().NoError(err) + s.Len(resp.ManagerSubTransferHistoryVos, 1) + s.Equal("foo@bar.com", resp.ManagerSubTransferHistoryVos[0].FromEmail) + s.Equal("SPOT", resp.ManagerSubTransferHistoryVos[0].FromAccountType) + s.Equal("baz@qux.com", resp.ManagerSubTransferHistoryVos[0].ToEmail) + s.Equal("MARGIN", resp.ManagerSubTransferHistoryVos[0].ToAccountType) + s.Equal("BTC", resp.ManagerSubTransferHistoryVos[0].Asset) + s.Equal(100000000, resp.ManagerSubTransferHistoryVos[0].Amount) + s.Equal(0, resp.ManagerSubTransferHistoryVos[0].ScheduledData) + s.Equal(uint64(1613450271000), resp.ManagerSubTransferHistoryVos[0].CreateTime) + s.Equal("SUCCESS", resp.ManagerSubTransferHistoryVos[0].Status) + s.Equal(1, resp.Count) +} + +func (s *subAccountTestSuite) TestQueryManagedSubAccountTransferLogForTradingTeam() { + data := []byte(` + { + "managerSubTransferHistoryVos": [ + { + "fromEmail": "test1@test.com", + "fromAccountType": "SPOT", + "toEmail": "test2@test.com", + "toAccountType": "MARGIN", + "asset": "BTC", + "amount": "1.00000000", + "scheduledData": 1613450271000, + "createTime": 1613450271000, + "status": "CONFIRMED" + } + ] + } + `) + + s.mockDo(data, nil) + defer s.assertDo() + + resp, err := s.client.NewQueryManagedSubAccountTransferLogForTradingTeamService(). + Email("test@test.com"). + StartTime(1613450271000). + EndTime(1613536671000). + Page(1). + Limit(500). + Transfers("BETWEEN_PARENT_TRADING_ACCOUNTS"). + TransferFunctionAccountType("MARGIN"). + Do(context.Background()) + + s.r().NoError(err) + s.Len(resp.ManagerSubTransferHistoryVos, 1) + s.Equal("test1@test.com", resp.ManagerSubTransferHistoryVos[0].FromEmail) + s.Equal("SPOT", resp.ManagerSubTransferHistoryVos[0].FromAccountType) + s.Equal("test2@test.com", resp.ManagerSubTransferHistoryVos[0].ToEmail) + s.Equal("MARGIN", resp.ManagerSubTransferHistoryVos[0].ToAccountType) + s.Equal("BTC", resp.ManagerSubTransferHistoryVos[0].Asset) + s.Equal("1.00000000", resp.ManagerSubTransferHistoryVos[0].Amount) + s.Equal(int64(1613450271000), resp.ManagerSubTransferHistoryVos[0].ScheduledData) + s.Equal(uint64(1613450271000), resp.ManagerSubTransferHistoryVos[0].CreateTime) + s.Equal("CONFIRMED", resp.ManagerSubTransferHistoryVos[0].Status) +} + +func (s *subAccountTestSuite) TestQuerySubAccountAssets() { + data := []byte(` + { + "balances": [ + { + "asset": "BTC", + "free": "0.1", + "locked": "0.2" + }, + { + "asset": "ETH", + "free": "1.0", + "locked": "2.0" + } + ] + }`) + + expectedBalances := []struct { + Asset string + Free string + Locked string + }{ + { + Asset: "BTC", + Free: "0.1", + Locked: "0.2", + }, + { + Asset: "ETH", + Free: "1.0", + Locked: "2.0", + }, + } + + s.mockDo(data, nil) + defer s.assertDo() + + resp, err := s.client.NewQuerySubAccountAssetsService(). + Email("test@example.com"). + Do(context.Background()) + + s.r().NoError(err) + s.Len(resp.Balances, 2) + for i, balance := range resp.Balances { + s.Equal(expectedBalances[i].Asset, balance.Asset) + s.Equal(expectedBalances[i].Free, balance.Free) + s.Equal(expectedBalances[i].Locked, balance.Locked) + } +} + +func (s *subAccountTestSuite) TestQuerySubAccountAssetsForMasterAccount() { + data := []byte(` + { + "balances": [ + { + "asset": "BTC", + "free": "0.005", + "locked": "0.005" + }, + { + "asset": "ETH", + "free": "0.01", + "locked": "0.01" + } + ] + } + `) + + expectedResp := &QuerySubAccountAssetsForMasterAccountResp{ + Balances: []struct { + Asset string `json:"asset"` + Free string `json:"free"` + Locked string `json:"locked"` + }{ + { + Asset: "BTC", + Free: "0.005", + Locked: "0.005", + }, + { + Asset: "ETH", + Free: "0.01", + Locked: "0.01", + }, + }, + } + + s.mockDo(data, nil) + defer s.assertDo() + + resp, err := s.client.NewQuerySubAccountAssetsForMasterAccountService(). + Email("example@email.com"). + Do(context.Background()) + + s.r().NoError(err) + s.Equal(expectedResp, resp) +} + +func (s *subAccountTestSuite) TestQuerySubAccountSpotAssetsSummary() { + data := []byte(` + { + "totalCount": 2, + "masterAccountTotalAsset": "1.2345", + "spotSubUserAssetBtcVoList": [ + { + "email": "user1@example.com", + "toAsset": "BTC" + }, + { + "email": "user2@example.com", + "toAsset": "ETH" + } + ] + } + `) + s.mockDo(data, nil) + defer s.assertDo() + + resp, err := s.client.NewQuerySubAccountSpotAssetsSummaryService(). + Email("example@example.com"). + Page(1). + Size(50). + Do(context.Background()) + + s.r().NoError(err) + s.Equal(int64(2), resp.TotalCount) + s.Equal("1.2345", resp.MasterAccountTotalAsset) + s.Len(resp.SpotSubUserAssetBtcVoList, 2) + s.Equal("user1@example.com", resp.SpotSubUserAssetBtcVoList[0].Email) + s.Equal("BTC", resp.SpotSubUserAssetBtcVoList[0].ToAsset) + s.Equal("user2@example.com", resp.SpotSubUserAssetBtcVoList[1].Email) + s.Equal("ETH", resp.SpotSubUserAssetBtcVoList[1].ToAsset) +} + +func (s *subAccountTestSuite) TestQuerySubAccountTransactionTatistics() { + data := []byte(`{ + "recent30BtcTotal": "0.00000000", + "recent30BtcFuturesTotal": "0.00000000", + "recent30BtcMarginTotal": "0.00000000", + "recent30BusdTotal": "0.00000000", + "recent30BusdFuturesTotal": "0.00000000", + "recent30BusdMarginTotal": "0.00000000", + "tradeInfoVos": [ + { + "userId": 123, + "btc": 1, + "btcFutures": 2, + "btcMargin": 3, + "busd": 4, + "busdFutures": 5, + "busdMargin": 6, + "date": 1617235200000 + } + ] + }`) + + s.mockDo(data, nil) + defer s.assertDo() + + email := "test@test.com" + resp, err := s.client.NewQuerySubAccountTransactionTatistics(). + Email(email). + Do(context.Background()) + + s.r().NoError(err) + s.Equal("0.00000000", resp.Recent30BtcTotal) + s.Equal("0.00000000", resp.Recent30BtcFuturesTotal) + s.Equal("0.00000000", resp.Recent30BtcMarginTotal) + s.Equal("0.00000000", resp.Recent30BusdTotal) + s.Equal("0.00000000", resp.Recent30BusdFuturesTotal) + s.Equal("0.00000000", resp.Recent30BusdMarginTotal) + s.Len(resp.TradeInfoVos, 1) + s.Equal(int64(123), resp.TradeInfoVos[0].UserId) + s.Equal(1, resp.TradeInfoVos[0].Btc) + s.Equal(2, resp.TradeInfoVos[0].BtcFutures) + s.Equal(3, resp.TradeInfoVos[0].BtcMargin) + s.Equal(4, resp.TradeInfoVos[0].Busd) + s.Equal(5, resp.TradeInfoVos[0].BusdFutures) + s.Equal(6, resp.TradeInfoVos[0].BusdMargin) + s.Equal(int64(1617235200000), resp.TradeInfoVos[0].Date) +} + +func (s *subAccountTestSuite) TestSubAccountFuturesAssetTransfer() { + data := []byte(`{"success": true, "txnId": "123"}`) + + s.mockDo(data, nil) + defer s.assertDo() + + resp, err := s.client.NewSubAccountFuturesAssetTransferService(). + FromEmail("from@test.com"). + ToEmail("to@test.com"). + FuturesType(1). + Asset("BTC"). + Amount(1.23). + Do(context.Background()) + + s.r().NoError(err) + s.Equal(true, resp.Success) + s.Equal("123", resp.TxnId) +} + +func (s *subAccountTestSuite) TestQuerySubAccountFuturesAssetTransferHistory() { + data := []byte(` + { + "success": true, + "futuresType": 1, + "transfers": [ + { + "from": "xxx", + "to": "yyy", + "asset": "BTC", + "qty": "0.5", + "tranId": 123, + "time": 1613450271000 + } + ] + } + `) + + s.mockDo(data, nil) + defer s.assertDo() + + resp, err := s.client.NewQuerySubAccountFuturesAssetTransferHistoryService(). + Email("test@example.com"). + FuturesType(1). + StartTime(1613450271000). + EndTime(1613536671000). + Page(1). + Limit(500). + Do(context.Background()) + + s.r().NoError(err) + s.True(resp.Success) + s.Equal(int64(1), resp.FuturesType) + s.Len(resp.Transfers, 1) + s.Equal("xxx", resp.Transfers[0].From) + s.Equal("yyy", resp.Transfers[0].To) + s.Equal("BTC", resp.Transfers[0].Asset) + s.Equal("0.5", resp.Transfers[0].Qty) + s.Equal(int64(123), resp.Transfers[0].TranId) + s.Equal(uint64(1613450271000), resp.Transfers[0].Time) +} + +func (s *subAccountTestSuite) TestQuerySubAccountList() { + data := []byte(` + { + "subAccounts": [ + { + "email": "user@example.com", + "isFreeze": true, + "createTime": 1613450271000, + "isManagedSubAccount": true, + "isAssetManagementSubAccount": false + }, + { + "email": "user2@example.com", + "isFreeze": false, + "createTime": 1613450271000, + "isManagedSubAccount": false, + "isAssetManagementSubAccount": true + } + ] + } + `) + + s.mockDo(data, nil) + defer s.assertDo() + + resp, err := s.client.NewQuerySubAccountListService(). + Email("user@example.com"). + IsFreeze("true"). + Page(1). + Limit(500). + Do(context.Background()) + + s.r().NoError(err) + s.Len(resp.SubAccounts, 2) + s.Equal("user@example.com", resp.SubAccounts[0].Email) + s.Equal(true, resp.SubAccounts[0].IsFreeze) + s.Equal(uint64(1613450271000), resp.SubAccounts[0].CreateTime) + s.Equal(true, resp.SubAccounts[0].IsManagedSubAccount) + s.Equal(false, resp.SubAccounts[0].IsAssetManagementSubAccount) + s.Equal("user2@example.com", resp.SubAccounts[1].Email) + s.Equal(false, resp.SubAccounts[1].IsFreeze) + s.Equal(uint64(1613450271000), resp.SubAccounts[1].CreateTime) + s.Equal(false, resp.SubAccounts[1].IsManagedSubAccount) + s.Equal(true, resp.SubAccounts[1].IsAssetManagementSubAccount) +} + +func (s *subAccountTestSuite) TestQuerySubAccountSpotAssetTransferHistory() { + data := []byte(` + { + "rows": [ + { + "from": "email1@example.com", + "to": "email2@example.com", + "asset": "BTC", + "qty": "1.00000000", + "status": "CONFIRMED", + "tranId": 123456789, + "time": 1613450271000 + } + ] + } + `) + + s.mockDo(data, nil) + defer s.assertDo() + + resp, err := s.client.NewQuerySubAccountSpotAssetTransferHistoryService(). + FromEmail("email1@example.com"). + ToEmail("email2@example.com"). + StartTime(1613450271000). + EndTime(1613536671000). + Page(1). + Limit(500). + Do(context.Background()) + + s.r().NoError(err) + s.Len(resp.Rows, 1) + s.Equal("email1@example.com", resp.Rows[0].From) + s.Equal("email2@example.com", resp.Rows[0].To) + s.Equal("BTC", resp.Rows[0].Asset) + s.Equal("1.00000000", resp.Rows[0].Qty) + s.Equal("CONFIRMED", resp.Rows[0].Status) + s.Equal(int64(123456789), resp.Rows[0].TranId) + s.Equal(uint64(1613450271000), resp.Rows[0].Time) +} + +func (s *subAccountTestSuite) TestTransferToMaster() { + data := []byte(`{"txnId": 123}`) + + s.mockDo(data, nil) + defer s.assertDo() + + resp, err := s.client.NewTransferToMasterService(). + Asset("BTC"). + Amount(1.0). + Do(context.Background()) + + s.r().NoError(err) + s.Equal(123, resp.TxnId) +} + +func (s *subAccountTestSuite) TestDo() { + data := []byte(` + { + "tranId": 123456789, + "clientTranId": "123abc" + } + `) + + s.mockDo(data, nil) + defer s.assertDo() + + resp, err := s.client.NewUniversalTransferService(). + FromAccountType("SPOT"). + ToAccountType("MARGIN"). + FromEmail("example1@gmail.com"). + ToEmail("example2@gmail.com"). + ClientTranId("123abc"). + Symbol("BTCUSDT"). + Asset("BTC"). + Amount(1.0). + Do(context.Background()) + + s.r().NoError(err) + s.Equal(123456789, resp.TranId) + s.Equal("123abc", resp.ClientTranId) +} + +func (s *subAccountTestSuite) TestUpdateIPRestrictionForSubAccountAPIKey() { + data := []byte(`{ + "status": "SUCCESS", + "ipList": [ + { + "ip": "192.168.1.1" + }, + { + "ip": "192.168.1.2" + } + ], + "updateTime": 1617383620000, + "apiKey": "h-1234567890" + }`) + + s.mockDo(data, nil) + defer s.assertDo() + + resp, err := s.client.NewUpdateIPRestrictionForSubAccountAPIKeyService(). + Email("subaccount@test.com"). + SubAccountApiKey("h-1234567890"). + Status("ENABLED"). + IpAddress("192.168.1.1"). + Do(context.Background()) + + s.r().NoError(err) + s.Equal("SUCCESS", resp.Status) + s.Len(resp.IpList, 2) + s.Equal("192.168.1.1", resp.IpList[0].Ip) + s.Equal("192.168.1.2", resp.IpList[1].Ip) + s.Equal(uint64(1617383620000), resp.UpdateTime) + s.Equal("h-1234567890", resp.ApiKey) +} + +func (s *subAccountTestSuite) TestWithdrawAssetsFromTheManagedSubAccount() { + data := []byte(`{"tranId":123}`) + + s.mockDo(data, nil) + defer s.assertDo() + + resp, err := s.client.NewWithdrawAssetsFromTheManagedSubAccountService(). + FromEmail("user@example.com"). + Asset("BTC"). + Amount(1.0). + TransferDate(1617220000). + Do(context.Background()) + + s.r().NoError(err) + s.Equal(int64(123), resp.TranId) +} diff --git a/test_client.go b/test_client.go new file mode 100644 index 0000000..3bfd25d --- /dev/null +++ b/test_client.go @@ -0,0 +1,154 @@ +package binance_connector + +import ( + "bytes" + "context" + "io/ioutil" + "net/http" + "net/url" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" + "github.com/stretchr/testify/suite" +) + +type baseTestSuite struct { + suite.Suite + client *mockedClient + apiKey string + secretKey string + baseURL string +} + +func (s *baseTestSuite) r() *require.Assertions { + return s.Require() +} + +func (s *baseTestSuite) SetupTest() { + s.apiKey = "dummyAPIKey" + s.secretKey = "dummySecretKey" + s.baseURL = "https://dummyapi.com" + s.client = newMockedClient(s.apiKey, s.secretKey, s.baseURL) +} + +func (s *baseTestSuite) mockDo(data []byte, err error, statusCode ...int) { + s.client.Client.do = s.client.do + code := http.StatusOK + if len(statusCode) > 0 { + code = statusCode[0] + } + s.client.On("do", anyHTTPRequest()).Return(newHTTPResponse(data, code), err) +} + +func (s *baseTestSuite) assertDo() { + s.client.AssertCalled(s.T(), "do", anyHTTPRequest()) +} + +func (s *baseTestSuite) assertReq(f func(r *request)) { + s.client.assertReq = f +} + +func (s *baseTestSuite) assertRequestEqual(e, a *request) { + s.assertURLValuesEqual(e.query, a.query) + s.assertURLValuesEqual(e.form, a.form) +} + +func (s *baseTestSuite) assertURLValuesEqual(e, a url.Values) { + var eKeys, aKeys []string + for k := range e { + eKeys = append(eKeys, k) + } + for k := range a { + aKeys = append(aKeys, k) + } + r := s.r() + r.Len(aKeys, len(eKeys)) + for k := range a { + switch k { + case timestampKey, signatureKey: + r.NotEmpty(a.Get(k)) + continue + } + r.Equal(e[k], a[k], k) + } +} + +func anythingOfType(t string) mock.AnythingOfTypeArgument { + return mock.AnythingOfType(t) +} + +func newContext() context.Context { + return context.Background() +} + +func anyHTTPRequest() mock.AnythingOfTypeArgument { + return anythingOfType("*http.Request") +} + +func newHTTPResponse(data []byte, statusCode int) *http.Response { + return &http.Response{ + Body: ioutil.NopCloser(bytes.NewBuffer(data)), + StatusCode: statusCode, + } +} + +func newRequest() *request { + r := &request{ + query: url.Values{}, + form: url.Values{}, + } + return r +} + +func newSignedRequest() *request { + return newRequest().setParams(params{ + timestampKey: "", + signatureKey: "", + }) +} + +type assertReqFunc func(r *request) + +type mockedClient struct { + mock.Mock + *Client + assertReq assertReqFunc +} + +func newMockedClient(apiKey, secretKey, baseURL string) *mockedClient { + m := new(mockedClient) + m.Client = NewClient(apiKey, secretKey, baseURL) + return m +} + +func (m *mockedClient) do(req *http.Request) (*http.Response, error) { + if m.assertReq != nil { + r := newRequest() + r.query = req.URL.Query() + if req.Body != nil { + bs := make([]byte, req.ContentLength) + for { + n, _ := req.Body.Read(bs) + if n == 0 { + break + } + } + form, err := url.ParseQuery(string(bs)) + if err != nil { + panic(err) + } + r.form = form + } + m.assertReq(r) + } + args := m.Called(req) + return args.Get(0).(*http.Response), args.Error(1) +} + +func TestFormatTimestamp(t *testing.T) { + tm, _ := time.Parse("2006-01-02 15:04:05", "2018-06-01 01:01:01") + assert.Equal(t, int64(1527814861000), FormatTimestamp(tm)) +} diff --git a/user_stream.go b/user_stream.go new file mode 100644 index 0000000..cd8592f --- /dev/null +++ b/user_stream.go @@ -0,0 +1,78 @@ +package binance_connector + +import ( + "context" + "net/http" +) + +// Create Listen Key +type CreateListenKey struct { + c *Client +} + +// Do send request +func (s *CreateListenKey) Do(ctx context.Context, opts ...RequestOption) (listenKey string, err error) { + r := &request{ + method: http.MethodPost, + endpoint: "/api/v3/userDataStream", + secType: secTypeAPIKey, + } + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return "", err + } + j, err := newJSON(data) + if err != nil { + return "", err + } + listenKey = j.Get("listenKey").MustString() + return listenKey, nil +} + +// Keep Alive/Ping User Stream +type PingUserStream struct { + c *Client + listenKey string +} + +// ListenKey set listen key +func (s *PingUserStream) ListenKey(listenKey string) *PingUserStream { + s.listenKey = listenKey + return s +} + +// Do send request +func (s *PingUserStream) Do(ctx context.Context, opts ...RequestOption) (err error) { + r := &request{ + method: http.MethodPut, + endpoint: "/api/v3/userDataStream", + secType: secTypeAPIKey, + } + r.setParam("listenKey", s.listenKey) + _, err = s.c.callAPI(ctx, r, opts...) + return err +} + +// CloseUserStream delete listen key +type CloseUserStream struct { + c *Client + listenKey string +} + +// ListenKey set listen key +func (s *CloseUserStream) ListenKey(listenKey string) *CloseUserStream { + s.listenKey = listenKey + return s +} + +// Do send request +func (s *CloseUserStream) Do(ctx context.Context, opts ...RequestOption) (err error) { + r := &request{ + method: http.MethodDelete, + endpoint: "/api/v3/userDataStream", + secType: secTypeAPIKey, + } + r.setParam("listenKey", s.listenKey) + _, err = s.c.callAPI(ctx, r, opts...) + return err +} diff --git a/user_stream_test.go b/user_stream_test.go new file mode 100644 index 0000000..46c267d --- /dev/null +++ b/user_stream_test.go @@ -0,0 +1,59 @@ +package binance_connector + +import ( + "testing" + + "github.com/stretchr/testify/suite" +) + +type userStreamTestSuite struct { + baseTestSuite +} + +func TestUserStream(t *testing.T) { + suite.Run(t, new(userStreamTestSuite)) +} + +func (s *userStreamTestSuite) TestStartUserStream() { + data := []byte(`{ + "listenKey": "pqia91ma19a5s61cv6a81va65sdf19v8a65a1a5s61cv6a81va65sdf19v8a65a1" + }`) + s.mockDo(data, nil) + defer s.assertDo() + + s.assertReq(func(r *request) { + s.assertRequestEqual(newRequest(), r) + }) + + listenKey, err := s.client.NewCreateListenKeyService().Do(newContext()) + s.r().NoError(err) + s.r().Equal("pqia91ma19a5s61cv6a81va65sdf19v8a65a1a5s61cv6a81va65sdf19v8a65a1", listenKey) +} + +func (s *userStreamTestSuite) TestKeepaliveUserStream() { + data := []byte(`{}`) + s.mockDo(data, nil) + defer s.assertDo() + + listenKey := "dummykey" + s.assertReq(func(r *request) { + s.assertRequestEqual(newRequest().setParam("listenKey", listenKey), r) + }) + + err := s.client.NewPingUserStream().ListenKey(listenKey).Do(newContext()) + s.r().NoError(err) +} + +func (s *userStreamTestSuite) TestCloseUserStream() { + data := []byte(`{}`) + s.mockDo(data, nil) + defer s.assertDo() + + listenKey := "dummykey" + s.assertReq(func(r *request) { + s.assertRequestEqual(newRequest().setParam("listenKey", listenKey), r) + }) + + err := s.client.NewCloseUserStream().ListenKey(listenKey).Do(newContext()) + s.r().NoError(err) +} diff --git a/wallet.go b/wallet.go new file mode 100644 index 0000000..875b53a --- /dev/null +++ b/wallet.go @@ -0,0 +1,1766 @@ +package binance_connector + +import ( + "context" + "encoding/json" + "net/http" +) + +// System Status (System) +const ( + systemStatusEndpoint = "/sapi/v1/system/status" +) + +// GetSystemStatusService get account info +type GetSystemStatusService struct { + c *Client +} + +func (s *GetSystemStatusService) Do(ctx context.Context, opts ...RequestOption) (res []*SystemStatusResponse, err error) { + r := &request{ + method: http.MethodGet, + endpoint: systemStatusEndpoint, + secType: secTypeNone, + } + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return nil, err + } + res = make([]*SystemStatusResponse, 0) + err = json.Unmarshal(data, &res) + if err != nil { + return nil, err + } + return res, nil +} + +// SystemStatusResponse define response of GetSystemStatusService +type SystemStatusResponse struct { + Status bool `json:"status"` + Msg string `json:"msg"` +} + +// All Coins' Information (USER_DATA) +const ( + allCoinsInfoEndpoint = "/sapi/v1/capital/config/getall" +) + +// GetAllCoinsInfoService get all coins' information +type GetAllCoinsInfoService struct { + c *Client +} + +func (s *GetAllCoinsInfoService) Do(ctx context.Context) (res []*CoinInfo, err error) { + r := &request{ + method: http.MethodGet, + endpoint: allCoinsInfoEndpoint, + secType: secTypeSigned, + } + data, err := s.c.callAPI(ctx, r) + if err != nil { + return nil, err + } + res = make([]*CoinInfo, 0) + err = json.Unmarshal(data, &res) + if err != nil { + return nil, err + } + return res, nil +} + +// CoinInfo define response of GetAllCoinsInfoService +type CoinInfo struct { + Coin string `json:"coin"` + DepositAllEnable bool `json:"depositAllEnable"` + Free string `json:"free"` + Freeze string `json:"freeze"` + Ipoable string `json:"ipoable"` + Ipoing string `json:"ipoing"` + IsLegalMoney bool `json:"isLegalMoney"` + Locked string `json:"locked"` + Name string `json:"name"` + NetworkList []struct { + AddressRegex string `json:"addressRegex"` + Coin string `json:"coin"` + DepositDesc string `json:"depositDesc"` + DepositEnable bool `json:"depositEnable"` + IsDefault bool `json:"isDefault"` + MemoRegex string `json:"memoRegex"` + MinConfirm int `json:"minConfirm"` + Name string `json:"name"` + Network string `json:"network"` + ResetAddressStatus bool `json:"resetAddressStatus"` + SpecialTips string `json:"specialTips"` + UnLockConfirm int `json:"unLockConfirm"` + WithdrawDesc string `json:"withdrawDesc"` + WithdrawEnable bool `json:"withdrawEnable"` + WithdrawFee string `json:"withdrawFee"` + WithdrawIntegerMultiple string `json:"withdrawIntegerMultiple"` + WithdrawMax string `json:"withdrawMax"` + WithdrawMin string `json:"withdrawMin"` + SameAddress bool `json:"sameAddress"` + EstimatedArrivalTime uint64 `json:"estimatedArrivalTime"` + Busy bool `json:"busy"` + } `json:"networkList"` + Storage string `json:"storage"` + Trading bool `json:"trading"` + WithdrawAllEnable bool `json:"withdrawAllEnable"` + Withdrawing string `json:"withdrawing"` +} + +// Daily Account Snapshot (USER_DATA) +const ( + accountSnapshotEndpoint = "/sapi/v1/accountSnapshot" +) + +// GetAccountSnapshotService get all orders from account +type GetAccountSnapshotService struct { + c *Client + marketType string + startTime *uint64 + endTime *uint64 + limit *int +} + +// MarketType set market type +func (s *GetAccountSnapshotService) MarketType(marketType string) *GetAccountSnapshotService { + s.marketType = marketType + return s +} + +// StartTime set start time +func (s *GetAccountSnapshotService) StartTime(startTime uint64) *GetAccountSnapshotService { + s.startTime = &startTime + return s +} + +// EndTime set end time +func (s *GetAccountSnapshotService) EndTime(endTime uint64) *GetAccountSnapshotService { + s.endTime = &endTime + return s +} + +// Limit set limit +func (s *GetAccountSnapshotService) Limit(limit int) *GetAccountSnapshotService { + s.limit = &limit + return s +} + +func (s *GetAccountSnapshotService) Do(ctx context.Context) (res *AccountSnapshotResponse, err error) { + r := &request{ + method: http.MethodGet, + endpoint: accountSnapshotEndpoint, + secType: secTypeSigned, + } + r.setParam("type", s.marketType) + if s.startTime != nil { + r.setParam("startTime", *s.startTime) + } + if s.endTime != nil { + r.setParam("endTime", *s.endTime) + } + if s.limit != nil { + r.setParam("limit", *s.limit) + } + data, err := s.c.callAPI(ctx, r) + if err != nil { + return nil, err + } + res = new(AccountSnapshotResponse) + err = json.Unmarshal(data, res) + if err != nil { + return nil, err + } + return res, nil +} + +// AccountSnapshotResponse define response of GetAccountSnapshotService +type AccountSnapshotResponse struct { + Code int `json:"code"` + Msg string `json:"msg"` + SnapshotVos []struct { + Data struct { + Balances []struct { + Asset string `json:"asset"` + Free string `json:"free"` + Locked string `json:"locked"` + } `json:"balances"` + TotalAssetOfBtc string `json:"totalAssetOfBtc"` + } `json:"data"` + Type string `json:"type"` + UpdateTime uint64 `json:"updateTime"` + } `json:"snapshotVos"` +} + +// Disable Fast Withdraw Switch (USER_DATA) +const ( + disableFastWithdrawSwitchEndpoint = "/sapi/v1/account/disableFastWithdrawSwitch" +) + +// DisableFastWithdrawSwitchService disable fast withdraw switch +type DisableFastWithdrawSwitchService struct { + c *Client +} + +func (s *DisableFastWithdrawSwitchService) Do(ctx context.Context) (res *DisableFastWithdrawSwitchResponse, err error) { + r := &request{ + method: http.MethodPost, + endpoint: disableFastWithdrawSwitchEndpoint, + secType: secTypeSigned, + } + data, err := s.c.callAPI(ctx, r) + if err != nil { + return nil, err + } + res = new(DisableFastWithdrawSwitchResponse) + err = json.Unmarshal(data, res) + if err != nil { + return nil, err + } + return res, nil +} + +// DisableFastWithdrawSwitchResponse define response of DisableFastWithdrawSwitchService +// This endpoint has empty response +type DisableFastWithdrawSwitchResponse struct { +} + +// Enable Fast Withdraw Switch (USER_DATA) +const ( + enableFastWithdrawSwitchEndpoint = "/sapi/v1/account/enableFastWithdrawSwitch" +) + +// EnableFastWithdrawSwitchService enable fast withdraw switch +type EnableFastWithdrawSwitchService struct { + c *Client +} + +func (s *EnableFastWithdrawSwitchService) Do(ctx context.Context) (res *EnableFastWithdrawSwitchResponse, err error) { + r := &request{ + method: http.MethodPost, + endpoint: enableFastWithdrawSwitchEndpoint, + secType: secTypeSigned, + } + data, err := s.c.callAPI(ctx, r) + if err != nil { + return nil, err + } + res = new(EnableFastWithdrawSwitchResponse) + err = json.Unmarshal(data, res) + if err != nil { + return nil, err + } + return res, nil +} + +// EnableFastWithdrawSwitchResponse define response of EnableFastWithdrawSwitchService +// This endpoint has empty response +type EnableFastWithdrawSwitchResponse struct { +} + +// Withdraw(USER_DATA) +const ( + withdrawEndpoint = "/sapi/v1/capital/withdraw/apply" +) + +// WithdrawService withdraw +type WithdrawService struct { + c *Client + coin string + withdrawOrderId *string + network *string + address string + addressTag *string + amount float64 + transactionFeeFlag *bool + name *string + walletType *int +} + +// Coin set coin +func (s *WithdrawService) Coin(coin string) *WithdrawService { + s.coin = coin + return s +} + +// WithdrawOrderId set withdrawOrderId +func (s *WithdrawService) WithdrawOrderId(withdrawOrderId string) *WithdrawService { + s.withdrawOrderId = &withdrawOrderId + return s +} + +// Network set network +func (s *WithdrawService) Network(network string) *WithdrawService { + s.network = &network + return s +} + +// Address set address +func (s *WithdrawService) Address(address string) *WithdrawService { + s.address = address + return s +} + +// AddressTag set addressTag +func (s *WithdrawService) AddressTag(addressTag string) *WithdrawService { + s.addressTag = &addressTag + return s +} + +// Amount set amount +func (s *WithdrawService) Amount(amount float64) *WithdrawService { + s.amount = amount + return s +} + +// TransactionFeeFlag set transactionFeeFlag +func (s *WithdrawService) TransactionFeeFlag(transactionFeeFlag bool) *WithdrawService { + s.transactionFeeFlag = &transactionFeeFlag + return s +} + +// Name set name +func (s *WithdrawService) Name(name string) *WithdrawService { + s.name = &name + return s +} + +// WalletType set walletType +func (s *WithdrawService) WalletType(walletType int) *WithdrawService { + s.walletType = &walletType + return s +} + +func (s *WithdrawService) Do(ctx context.Context) (res *WithdrawResponse, err error) { + r := &request{ + method: http.MethodPost, + endpoint: withdrawEndpoint, + secType: secTypeSigned, + } + r.setParam("coin", s.coin) + r.setParam("address", s.address) + r.setParam("amount", s.amount) + if s.withdrawOrderId != nil { + r.setParam("withdrawOrderId", *s.withdrawOrderId) + } + if s.network != nil { + r.setParam("network", *s.network) + } + if s.addressTag != nil { + r.setParam("addressTag", *s.addressTag) + } + if s.transactionFeeFlag != nil { + r.setParam("transactionFeeFlag", *s.transactionFeeFlag) + } + if s.name != nil { + r.setParam("name", *s.name) + } + if s.walletType != nil { + r.setParam("walletType", *s.walletType) + } + data, err := s.c.callAPI(ctx, r) + if err != nil { + return nil, err + } + res = new(WithdrawResponse) + err = json.Unmarshal(data, res) + if err != nil { + return nil, err + } + return res, nil +} + +// WithdrawResponse define response of WithdrawService +type WithdrawResponse struct { + Id string `json:"id"` +} + +// Deposit History (supporting network) (USER_DATA) +const ( + depositHistoryEndpoint = "/sapi/v1/capital/deposit/hisrec" +) + +// DepositHistoryService deposit history +type DepositHistoryService struct { + c *Client + coin *string + status *int + startTime *uint64 + endTime *uint64 + offset *int + limit *int + txid *string +} + +// Coin set coin +func (s *DepositHistoryService) Coin(coin string) *DepositHistoryService { + s.coin = &coin + return s +} + +// Status set status +func (s *DepositHistoryService) Status(status int) *DepositHistoryService { + s.status = &status + return s +} + +// StartTime set startTime +func (s *DepositHistoryService) StartTime(startTime uint64) *DepositHistoryService { + s.startTime = &startTime + return s +} + +// EndTime set endTime +func (s *DepositHistoryService) EndTime(endTime uint64) *DepositHistoryService { + s.endTime = &endTime + return s +} + +// Offset set offset +func (s *DepositHistoryService) Offset(offset int) *DepositHistoryService { + s.offset = &offset + return s +} + +// Limit set limit +func (s *DepositHistoryService) Limit(limit int) *DepositHistoryService { + s.limit = &limit + return s +} + +// TxId set txid +func (s *DepositHistoryService) TxId(txid string) *DepositHistoryService { + s.txid = &txid + return s +} + +func (s *DepositHistoryService) Do(ctx context.Context) (res *DepositHistoryResponse, err error) { + r := &request{ + method: http.MethodGet, + endpoint: depositHistoryEndpoint, + secType: secTypeSigned, + } + if s.coin != nil { + r.setParam("coin", *s.coin) + } + if s.status != nil { + r.setParam("status", *s.status) + } + if s.startTime != nil { + r.setParam("startTime", *s.startTime) + } + if s.endTime != nil { + r.setParam("endTime", *s.endTime) + } + if s.offset != nil { + r.setParam("offset", *s.offset) + } + if s.limit != nil { + r.setParam("limit", *s.limit) + } + if s.txid != nil { + r.setParam("txId", *s.txid) + } + data, err := s.c.callAPI(ctx, r) + if err != nil { + return nil, err + } + res = new(DepositHistoryResponse) + err = json.Unmarshal(data, res) + if err != nil { + return nil, err + } + return res, nil +} + +// DepositHistoryResponse define response of DepositHistoryService +type DepositHistoryResponse struct { + Id string `json:"id"` + Amount string `json:"amount"` + Coin string `json:"coin"` + Network string `json:"network"` + Status int `json:"status"` + Address string `json:"address"` + AddressTag string `json:"addressTag"` + TxId string `json:"txId"` + InsertTime uint64 `json:"insertTime"` + TransferType int `json:"transferType"` + ConfirmTimes string `json:"confirmTimes"` + UnlockConfirm int `json:"unlockConfirm"` + WalletType int `json:"walletType"` +} + +// Withdraw History (supporting network) (USER_DATA) +const ( + withdrawHistoryEndpoint = "/sapi/v1/capital/withdraw/history" +) + +// WithdrawHistoryService withdraw history +type WithdrawHistoryService struct { + c *Client + coin *string + withdrawOrderId *string + status *int + offset *int + limit *int + startTime *uint64 + endTime *uint64 +} + +// Coin set coin +func (s *WithdrawHistoryService) Coin(coin string) *WithdrawHistoryService { + s.coin = &coin + return s +} + +// WithdrawOrderId set withdrawOrderId +func (s *WithdrawHistoryService) WithdrawOrderId(withdrawOrderId string) *WithdrawHistoryService { + s.withdrawOrderId = &withdrawOrderId + return s +} + +// Status set status +func (s *WithdrawHistoryService) Status(status int) *WithdrawHistoryService { + s.status = &status + return s +} + +// Offset set offset +func (s *WithdrawHistoryService) Offset(offset int) *WithdrawHistoryService { + s.offset = &offset + return s +} + +// Limit set limit +func (s *WithdrawHistoryService) Limit(limit int) *WithdrawHistoryService { + s.limit = &limit + return s +} + +// StartTime set startTime +func (s *WithdrawHistoryService) StartTime(startTime uint64) *WithdrawHistoryService { + s.startTime = &startTime + return s +} + +// EndTime set endTime +func (s *WithdrawHistoryService) EndTime(endTime uint64) *WithdrawHistoryService { + s.endTime = &endTime + return s +} + +func (s *WithdrawHistoryService) Do(ctx context.Context) (res *WithdrawHistoryResponse, err error) { + r := &request{ + method: http.MethodGet, + endpoint: withdrawHistoryEndpoint, + secType: secTypeSigned, + } + if s.coin != nil { + r.setParam("coin", *s.coin) + } + if s.withdrawOrderId != nil { + r.setParam("withdrawOrderId", *s.withdrawOrderId) + } + if s.status != nil { + r.setParam("status", *s.status) + } + if s.offset != nil { + r.setParam("offset", *s.offset) + } + if s.limit != nil { + r.setParam("limit", *s.limit) + } + if s.startTime != nil { + r.setParam("startTime", *s.startTime) + } + if s.endTime != nil { + r.setParam("endTime", *s.endTime) + } + data, err := s.c.callAPI(ctx, r) + if err != nil { + return nil, err + } + res = new(WithdrawHistoryResponse) + err = json.Unmarshal(data, res) + if err != nil { + return nil, err + } + return res, nil +} + +// WithdrawHistoryResponse define response of WithdrawHistoryService +type WithdrawHistoryResponse struct { + Id string `json:"id"` + Amount string `json:"amount"` + TransactionFee string `json:"transactionFee"` + Coin string `json:"coin"` + Status int `json:"status"` + Address string `json:"address"` + TxId string `json:"txId"` + ApplyTime uint64 `json:"applyTime"` + Network string `json:"network"` + TransferType int `json:"transferType"` + WithdrawOrderId string `json:"withdrawOrderId"` + Info string `json:"info"` + ConfirmNo int `json:"confirmNo"` + WalletType int `json:"walletType"` + TxKey string `json:"txKey"` +} + +// Deposit Address (supporting network) (USER_DATA) +const ( + depositAddressEndpoint = "/sapi/v1/capital/deposit/address" +) + +// DepositAddressService deposit address +type DepositAddressService struct { + c *Client + coin string + network *string +} + +// Coin set coin +func (s *DepositAddressService) Coin(coin string) *DepositAddressService { + s.coin = coin + return s +} + +// Network set network +func (s *DepositAddressService) Network(network string) *DepositAddressService { + s.network = &network + return s +} + +func (s *DepositAddressService) Do(ctx context.Context) (res *DepositAddressResponse, err error) { + r := &request{ + method: http.MethodGet, + endpoint: depositAddressEndpoint, + secType: secTypeSigned, + } + r.setParam("coin", s.coin) + if s.network != nil { + r.setParam("network", *s.network) + } + data, err := s.c.callAPI(ctx, r) + if err != nil { + return nil, err + } + res = new(DepositAddressResponse) + err = json.Unmarshal(data, res) + if err != nil { + return nil, err + } + return res, nil +} + +// DepositAddressResponse define response of DepositAddressService +type DepositAddressResponse struct { + Address string `json:"address"` + Coin string `json:"coin"` + Tag string `json:"tag"` + Url string `json:"url"` +} + +// Account Status (USER_DATA) +const ( + accountStatusEndpoint = "/sapi/v1/account/status" +) + +// AccountStatusService account status +type AccountStatusService struct { + c *Client +} + +func (s *AccountStatusService) Do(ctx context.Context) (res *AccountStatusResponse, err error) { + r := &request{ + method: http.MethodGet, + endpoint: accountStatusEndpoint, + secType: secTypeSigned, + } + data, err := s.c.callAPI(ctx, r) + if err != nil { + return nil, err + } + res = new(AccountStatusResponse) + err = json.Unmarshal(data, res) + if err != nil { + return nil, err + } + return res, nil +} + +// AccountStatusResponse define response of AccountStatusService +type AccountStatusResponse struct { + Data string `json:"data"` +} + +// Account API Trading Status (USER_DATA) +const ( + accountApiTradingStatusEndpoint = "/sapi/v1/account/apiTradingStatus" +) + +// AccountApiTradingStatusService account api trading status +type AccountApiTradingStatusService struct { + c *Client +} + +func (s *AccountApiTradingStatusService) Do(ctx context.Context) (res *AccountApiTradingStatusResponse, err error) { + r := &request{ + method: http.MethodGet, + endpoint: accountApiTradingStatusEndpoint, + secType: secTypeSigned, + } + data, err := s.c.callAPI(ctx, r) + if err != nil { + return nil, err + } + res = new(AccountApiTradingStatusResponse) + err = json.Unmarshal(data, res) + if err != nil { + return nil, err + } + return res, nil +} + +// AccountApiTradingStatusResponse define response of AccountApiTradingStatusService +type AccountApiTradingStatusResponse struct { + Data struct { + IsLocked bool `json:"isLocked"` + PlannedRecoverTime int64 `json:"plannedRecoverTime"` + TriggerCondition struct { + GCR int `json:"GCR"` + IFER int `json:"IFER"` + UFR int `json:"UFR"` + } `json:"triggerCondition"` + UpdateTime uint64 `json:"updateTime"` + } `json:"data"` +} + +// DustLog(USER_DATA) +const ( + dustLogEndpoint = "/sapi/v1/asset/dribblet" +) + +// DustLogService dust log +type DustLogService struct { + c *Client + startTime *uint64 + endTime *uint64 +} + +// StartTime set startTime +func (s *DustLogService) StartTime(startTime uint64) *DustLogService { + s.startTime = &startTime + return s +} + +// EndTime set endTime +func (s *DustLogService) EndTime(endTime uint64) *DustLogService { + s.endTime = &endTime + return s +} + +func (s *DustLogService) Do(ctx context.Context) (res *DustLogResponse, err error) { + r := &request{ + method: http.MethodGet, + endpoint: dustLogEndpoint, + secType: secTypeSigned, + } + if s.startTime != nil { + r.setParam("startTime", *s.startTime) + } + if s.endTime != nil { + r.setParam("endTime", *s.endTime) + } + data, err := s.c.callAPI(ctx, r) + if err != nil { + return nil, err + } + res = new(DustLogResponse) + err = json.Unmarshal(data, res) + if err != nil { + return nil, err + } + return res, nil +} + +// DustLogResponse define response of DustLogService +type DustLogResponse struct { + Total int `json:"total"` + UserAssetDribblets []struct { + OperateTime uint64 `json:"operateTime"` + TotalTransferedAmount string `json:"totalTransferedAmount"` + TotalServiceChargeAmount string `json:"totalServiceChargeAmount"` + TransId int64 `json:"transId"` + UserAssetDribbletDetails []struct { + TransId int64 `json:"transId"` + ServiceChargeAmount string `json:"serviceChargeAmount"` + Amount string `json:"amount"` + OperateTime uint64 `json:"operateTime"` + TransferedAmount string `json:"transferedAmount"` + FromAsset string `json:"fromAsset"` + } `json:"userAssetDribbletDetails"` + } `json:"userAssetDribblets"` +} + +// Get Assets That Can Be Converted Into BNB (USER_DATA) +const ( + assetDetailEndpoint = "/sapi/v1/asset/dust-btc" +) + +// AssetDetailService asset detail +type AssetDetailService struct { + c *Client +} + +func (s *AssetDetailService) Do(ctx context.Context) (res *AssetDetailResponse, err error) { + r := &request{ + method: http.MethodPost, + endpoint: assetDetailEndpoint, + secType: secTypeSigned, + } + data, err := s.c.callAPI(ctx, r) + if err != nil { + return nil, err + } + res = new(AssetDetailResponse) + err = json.Unmarshal(data, res) + if err != nil { + return nil, err + } + return res, nil +} + +// AssetDetailResponse define response of AssetDetailService +type AssetDetailResponse struct { + Details []struct { + Asset string `json:"asset"` + AssetFullName string `json:"assetFullName"` + AmountFree string `json:"amountFree"` + ToBTC string `json:"toBTC"` + ToBNB string `json:"toBNB"` + ToBNBOffExchange string `json:"toBNBOffExchange"` + Exchange string `json:"exchange"` + } `json:"details"` + TotalTransferBtc string `json:"totalTransferBtc"` + TotalTransferBnb string `json:"totalTransferBnb"` + DribbletPercentage string `json:"dribbletPercentage"` +} + +// Dust Transfer (USER_DATA) +const ( + dustTransferEndpoint = "/sapi/v1/asset/dust" +) + +// DustTransferService dust transfer +type DustTransferService struct { + c *Client + asset []string +} + +// Asset set asset +func (s *DustTransferService) Asset(asset []string) *DustTransferService { + s.asset = asset + return s +} + +func (s *DustTransferService) Do(ctx context.Context) (res *DustTransferResponse, err error) { + r := &request{ + method: http.MethodPost, + endpoint: dustTransferEndpoint, + secType: secTypeSigned, + } + for _, a := range s.asset { + r.addParam("asset", a) + } + data, err := s.c.callAPI(ctx, r) + if err != nil { + return nil, err + } + res = new(DustTransferResponse) + err = json.Unmarshal(data, res) + if err != nil { + return nil, err + } + return res, nil +} + +// DustTransferResponse define response of DustTransferService +type DustTransferResponse struct { + TotalServiceCharge string `json:"totalServiceCharge"` + TotalTransfered string `json:"totalTransfered"` + TransferResult []*DustTransferResult `json:"transferResult"` +} + +// DustTransferResult represents the result of a dust transfer. +type DustTransferResult struct { + Amount string `json:"amount"` + FromAsset string `json:"fromAsset"` + OperateTime int64 `json:"operateTime"` + ServiceChargeAmount string `json:"serviceChargeAmount"` + TranID int64 `json:"tranId"` + TransferedAmount string `json:"transferedAmount"` +} + +// Asset Dividend Record (USER_DATA) +const ( + assetDividendRecordEndpoint = "/sapi/v1/asset/assetDividend" +) + +// AssetDividendRecordService asset dividend record +type AssetDividendRecordService struct { + c *Client + asset *string + startTime *uint64 + endTime *uint64 + limit *int +} + +// Asset set asset +func (s *AssetDividendRecordService) Asset(asset string) *AssetDividendRecordService { + s.asset = &asset + return s +} + +// StartTime set startTime +func (s *AssetDividendRecordService) StartTime(startTime uint64) *AssetDividendRecordService { + s.startTime = &startTime + return s +} + +// EndTime set endTime +func (s *AssetDividendRecordService) EndTime(endTime uint64) *AssetDividendRecordService { + s.endTime = &endTime + return s +} + +// Limit set limit +func (s *AssetDividendRecordService) Limit(limit int) *AssetDividendRecordService { + s.limit = &limit + return s +} + +func (s *AssetDividendRecordService) Do(ctx context.Context) (res *AssetDividendRecordResponse, err error) { + r := &request{ + method: http.MethodGet, + endpoint: assetDividendRecordEndpoint, + secType: secTypeSigned, + } + if s.asset != nil { + r.setParam("asset", *s.asset) + } + if s.startTime != nil { + r.setParam("startTime", *s.startTime) + } + if s.endTime != nil { + r.setParam("endTime", *s.endTime) + } + if s.limit != nil { + r.setParam("limit", *s.limit) + } + data, err := s.c.callAPI(ctx, r) + if err != nil { + return nil, err + } + res = new(AssetDividendRecordResponse) + err = json.Unmarshal(data, res) + if err != nil { + return nil, err + } + return res, nil +} + +// AssetDividendRecordResponse define response of AssetDividendRecordService +type AssetDividendRecordResponse struct { + Rows []struct { + Id int64 `json:"id"` + Amount string `json:"amount"` + Asset string `json:"asset"` + DivTime uint64 `json:"divTime"` + EnInfo string `json:"enInfo"` + TranId int64 `json:"tranId"` + } `json:"rows"` + Total int64 `json:"total"` +} + +// Asset Detail (USER_DATA) +const ( + assetDetailV2Endpoint = "/sapi/v1/asset/assetDetail" +) + +// AssetDetailV2Service asset detail v2 +type AssetDetailV2Service struct { + c *Client + asset *string +} + +// Asset set asset +func (s *AssetDetailV2Service) Asset(asset string) *AssetDetailV2Service { + s.asset = &asset + return s +} + +func (s *AssetDetailV2Service) Do(ctx context.Context) (res *AssetDetailV2Response, err error) { + r := &request{ + method: http.MethodGet, + endpoint: assetDetailV2Endpoint, + secType: secTypeSigned, + } + if s.asset != nil { + r.setParam("asset", *s.asset) + } + data, err := s.c.callAPI(ctx, r) + if err != nil { + return nil, err + } + res = new(AssetDetailV2Response) + err = json.Unmarshal(data, res) + if err != nil { + return nil, err + } + return res, nil +} + +// AssetDetailV2Response define response of AssetDetailV2Service +type AssetDetailV2Response struct { + AssetDetail struct { + MinWithdrawAmount string `json:"minWithdrawAmount"` + DepositStatus bool `json:"depositStatus"` + WithdrawFee string `json:"withdrawFee"` + WithdrawStatus bool `json:"withdrawStatus"` + DepositTip string `json:"depositTip"` + } `json:"assetDetail"` +} + +// Trade Fee (USER_DATA) +const ( + tradeFeeEndpoint = "/sapi/v1/asset/tradeFee" +) + +// TradeFeeService trade fee +type TradeFeeService struct { + c *Client + symbol *string +} + +// Symbol set symbol +func (s *TradeFeeService) Symbol(symbol string) *TradeFeeService { + s.symbol = &symbol + return s +} + +func (s *TradeFeeService) Do(ctx context.Context) (res *TradeFeeResponse, err error) { + r := &request{ + method: http.MethodGet, + endpoint: tradeFeeEndpoint, + secType: secTypeSigned, + } + if s.symbol != nil { + r.setParam("symbol", *s.symbol) + } + data, err := s.c.callAPI(ctx, r) + if err != nil { + return nil, err + } + res = new(TradeFeeResponse) + err = json.Unmarshal(data, res) + if err != nil { + return nil, err + } + return res, nil +} + +// TradeFeeResponse define response of TradeFeeService +type TradeFeeResponse struct { + Symbol string `json:"symbol"` + MakerCommission string `json:"makerCommission"` + TakerCommission string `json:"takerCommission"` +} + +// User Universal Transfer (USER_DATA) +const ( + userUniversalTransferEndpoint = "/sapi/v1/asset/transfer" +) + +// UserUniversalTransferService user universal transfer +type UserUniversalTransferService struct { + c *Client + transferType string + asset string + amount float64 + fromSymbol *string + toSymbol *string +} + +// TransferType set transferType +func (s *UserUniversalTransferService) TransferType(transferType string) *UserUniversalTransferService { + s.transferType = transferType + return s +} + +// Asset set asset +func (s *UserUniversalTransferService) Asset(asset string) *UserUniversalTransferService { + s.asset = asset + return s +} + +// Amount set amount +func (s *UserUniversalTransferService) Amount(amount float64) *UserUniversalTransferService { + s.amount = amount + return s +} + +// FromSymbol set fromSymbol +func (s *UserUniversalTransferService) FromSymbol(fromSymbol string) *UserUniversalTransferService { + s.fromSymbol = &fromSymbol + return s +} + +// ToSymbol set toSymbol +func (s *UserUniversalTransferService) ToSymbol(toSymbol string) *UserUniversalTransferService { + s.toSymbol = &toSymbol + return s +} + +func (s *UserUniversalTransferService) Do(ctx context.Context) (res *UserUniversalTransferResponse, err error) { + r := &request{ + method: http.MethodPost, + endpoint: userUniversalTransferEndpoint, + secType: secTypeSigned, + } + r.setParam("type", s.transferType) + r.setParam("asset", s.asset) + r.setParam("amount", s.amount) + if s.fromSymbol != nil { + r.setParam("fromSymbol", *s.fromSymbol) + } + if s.toSymbol != nil { + r.setParam("toSymbol", *s.toSymbol) + } + data, err := s.c.callAPI(ctx, r) + if err != nil { + return nil, err + } + res = new(UserUniversalTransferResponse) + err = json.Unmarshal(data, res) + if err != nil { + return nil, err + } + return res, nil +} + +// UserUniversalTransferResponse define response of UserUniversalTransferService +type UserUniversalTransferResponse struct { + TranId int64 `json:"tranId"` +} + +// Query User Universal Transfer History (USER_DATA) +const ( + userUniversalTransferHistoryEndpoint = "/sapi/v1/asset/transfer" +) + +// UserUniversalTransferHistoryService user universal transfer history +type UserUniversalTransferHistoryService struct { + c *Client + transferType string + startTime *uint64 + endTime *uint64 + current *int + size *int + fromSymbol *string + toSymbol *string +} + +// TransferType set transferType +func (s *UserUniversalTransferHistoryService) TransferType(transferType string) *UserUniversalTransferHistoryService { + s.transferType = transferType + return s +} + +// StartTime set startTime +func (s *UserUniversalTransferHistoryService) StartTime(startTime uint64) *UserUniversalTransferHistoryService { + s.startTime = &startTime + return s +} + +// EndTime set endTime +func (s *UserUniversalTransferHistoryService) EndTime(endTime uint64) *UserUniversalTransferHistoryService { + s.endTime = &endTime + return s +} + +// Current set current +func (s *UserUniversalTransferHistoryService) Current(current int) *UserUniversalTransferHistoryService { + s.current = ¤t + return s +} + +// Size set size +func (s *UserUniversalTransferHistoryService) Size(size int) *UserUniversalTransferHistoryService { + s.size = &size + return s +} + +// FromSymbol set fromSymbol +func (s *UserUniversalTransferHistoryService) FromSymbol(fromSymbol string) *UserUniversalTransferHistoryService { + s.fromSymbol = &fromSymbol + return s +} + +// ToSymbol set toSymbol +func (s *UserUniversalTransferHistoryService) ToSymbol(toSymbol string) *UserUniversalTransferHistoryService { + s.toSymbol = &toSymbol + return s +} + +func (s *UserUniversalTransferHistoryService) Do(ctx context.Context) (res *UserUniversalTransferHistoryResponse, err error) { + r := &request{ + method: http.MethodGet, + endpoint: userUniversalTransferHistoryEndpoint, + secType: secTypeSigned, + } + r.setParam("type", s.transferType) + if s.startTime != nil { + r.setParam("startTime", *s.startTime) + } + if s.endTime != nil { + r.setParam("endTime", *s.endTime) + } + if s.current != nil { + r.setParam("current", *s.current) + } + if s.size != nil { + r.setParam("size", *s.size) + } + if s.fromSymbol != nil { + r.setParam("fromSymbol", *s.fromSymbol) + } + if s.toSymbol != nil { + r.setParam("toSymbol", *s.toSymbol) + } + data, err := s.c.callAPI(ctx, r) + if err != nil { + return nil, err + } + res = new(UserUniversalTransferHistoryResponse) + err = json.Unmarshal(data, res) + if err != nil { + return nil, err + } + return res, nil +} + +// UserUniversalTransferHistoryResponse define response of UserUniversalTransferHistoryService +type UserUniversalTransferHistoryResponse struct { + Total int64 `json:"total"` + Rows []struct { + Asset string `json:"asset"` + Amount string `json:"amount"` + Type string `json:"type"` + Status string `json:"status"` + TranId int64 `json:"tranId"` + Timestamp uint64 `json:"timestamp"` + } `json:"rows"` +} + +// Funding Wallet (USER_DATA) +const ( + fundingWalletEndpoint = "/sapi/v1/asset/get-funding-asset" +) + +// FundingWalletService funding wallet +type FundingWalletService struct { + c *Client + asset *string + needBtcValuation *string +} + +// Asset set asset +func (s *FundingWalletService) Asset(asset string) *FundingWalletService { + s.asset = &asset + return s +} + +// NeedBtcValuation set needBtcValuation +func (s *FundingWalletService) NeedBtcValuation(needBtcValuation string) *FundingWalletService { + s.needBtcValuation = &needBtcValuation + return s +} + +func (s *FundingWalletService) Do(ctx context.Context) (res *FundingWalletResponse, err error) { + r := &request{ + method: http.MethodGet, + endpoint: fundingWalletEndpoint, + secType: secTypeSigned, + } + if s.asset != nil { + r.setParam("asset", *s.asset) + } + if s.needBtcValuation != nil { + r.setParam("needBtcValuation", *s.needBtcValuation) + } + data, err := s.c.callAPI(ctx, r) + if err != nil { + return nil, err + } + res = new(FundingWalletResponse) + err = json.Unmarshal(data, res) + if err != nil { + return nil, err + } + return res, nil +} + +// FundingWalletResponse define response of FundingWalletService +type FundingWalletResponse struct { + Asset string `json:"asset"` + Free string `json:"free"` + Locked string `json:"locked"` + Freeze string `json:"freeze"` + Withdrawing string `json:"withdrawing"` + BtcValuation string `json:"btcValuation"` +} + +// User Asset (USER_DATA) +const ( + userAssetEndpoint = "/sapi/v3/asset/getUserAsset" +) + +// UserAssetService user asset +type UserAssetService struct { + c *Client + asset *string + needBtcValuation *bool +} + +// Asset set asset +func (s *UserAssetService) Asset(asset string) *UserAssetService { + s.asset = &asset + return s +} + +// NeedBtcValuation set needBtcValuation +func (s *UserAssetService) NeedBtcValuation(needBtcValuation bool) *UserAssetService { + s.needBtcValuation = &needBtcValuation + return s +} + +func (s *UserAssetService) Do(ctx context.Context) (res *UserAssetResponse, err error) { + r := &request{ + method: http.MethodGet, + endpoint: userAssetEndpoint, + secType: secTypeSigned, + } + if s.asset != nil { + r.setParam("asset", *s.asset) + } + if s.needBtcValuation != nil { + r.setParam("needBtcValuation", *s.needBtcValuation) + } + data, err := s.c.callAPI(ctx, r) + if err != nil { + return nil, err + } + res = new(UserAssetResponse) + err = json.Unmarshal(data, res) + if err != nil { + return nil, err + } + return res, nil +} + +// UserAssetResponse define response of UserAssetService +type UserAssetResponse struct { + Asset string `json:"asset"` + Free string `json:"free"` + Locked string `json:"locked"` + Freeze string `json:"freeze"` + Withdrawing string `json:"withdrawing"` + Ipoable string `json:"ipoable"` + BtcValuation string `json:"btcValuation"` +} + +// BUSD Convert (TRADE) +const ( + bUSDConvertEndpoint = "/sapi/v1/asset/convert-transfer" +) + +// BUSDConvertService BUSD convert +type BUSDConvertService struct { + c *Client + clientTranId string + asset string + amount float64 + targetAsset string + accountType *string +} + +// ClientTranId set clientTranId +func (s *BUSDConvertService) ClientTranId(clientTranId string) *BUSDConvertService { + s.clientTranId = clientTranId + return s +} + +// Asset set asset +func (s *BUSDConvertService) Asset(asset string) *BUSDConvertService { + s.asset = asset + return s +} + +// Amount set amount +func (s *BUSDConvertService) Amount(amount float64) *BUSDConvertService { + s.amount = amount + return s +} + +// TargetAsset set targetAsset +func (s *BUSDConvertService) TargetAsset(targetAsset string) *BUSDConvertService { + s.targetAsset = targetAsset + return s +} + +// AccountType set accountType +func (s *BUSDConvertService) AccountType(accountType string) *BUSDConvertService { + s.accountType = &accountType + return s +} + +func (s *BUSDConvertService) Do(ctx context.Context) (res *BUSDConvertResponse, err error) { + r := &request{ + method: http.MethodPost, + endpoint: bUSDConvertEndpoint, + secType: secTypeSigned, + } + r.setParam("clientTranId", s.clientTranId) + r.setParam("asset", s.asset) + r.setParam("amount", s.amount) + r.setParam("targetAsset", s.targetAsset) + if s.accountType != nil { + r.setParam("accountType", *s.accountType) + } + data, err := s.c.callAPI(ctx, r) + if err != nil { + return nil, err + } + res = new(BUSDConvertResponse) + err = json.Unmarshal(data, res) + if err != nil { + return nil, err + } + return res, nil +} + +// BUSDConvertResponse define response of BUSDConvertService +type BUSDConvertResponse struct { + TranId int64 `json:"tranId"` + Status string `json:"status"` +} + +// BUSD Convert History (USER_DATA) +const ( + bUSDConvertHistoryEndpoint = "/sapi/v1/asset/convert-transfer/queryByPage" +) + +// BUSDConvertHistoryService BUSD convert history +type BUSDConvertHistoryService struct { + c *Client + tranId *int64 + clientTranId *string + asset *string + startTime uint64 + endTime uint64 + accountType *string + current *int + size *int +} + +// TranId set tranId +func (s *BUSDConvertHistoryService) TranId(tranId int64) *BUSDConvertHistoryService { + s.tranId = &tranId + return s +} + +// ClientTranId set clientTranId +func (s *BUSDConvertHistoryService) ClientTranId(clientTranId string) *BUSDConvertHistoryService { + s.clientTranId = &clientTranId + return s +} + +// Asset set asset +func (s *BUSDConvertHistoryService) Asset(asset string) *BUSDConvertHistoryService { + s.asset = &asset + return s +} + +// StartTime set startTime +func (s *BUSDConvertHistoryService) StartTime(startTime uint64) *BUSDConvertHistoryService { + s.startTime = startTime + return s +} + +// EndTime set endTime +func (s *BUSDConvertHistoryService) EndTime(endTime uint64) *BUSDConvertHistoryService { + s.endTime = endTime + return s +} + +// AccountType set accountType +func (s *BUSDConvertHistoryService) AccountType(accountType string) *BUSDConvertHistoryService { + s.accountType = &accountType + return s +} + +// Current set current +func (s *BUSDConvertHistoryService) Current(current int) *BUSDConvertHistoryService { + s.current = ¤t + return s +} + +// Size set size +func (s *BUSDConvertHistoryService) Size(size int) *BUSDConvertHistoryService { + s.size = &size + return s +} + +func (s *BUSDConvertHistoryService) Do(ctx context.Context) (res *BUSDConvertHistoryResponse, err error) { + r := &request{ + method: http.MethodGet, + endpoint: bUSDConvertHistoryEndpoint, + secType: secTypeSigned, + } + r.setParam("startTime", s.startTime) + r.setParam("endTime", s.endTime) + if s.tranId != nil { + r.setParam("tranId", *s.tranId) + } + if s.clientTranId != nil { + r.setParam("clientTranId", *s.clientTranId) + } + if s.asset != nil { + r.setParam("asset", *s.asset) + } + if s.accountType != nil { + r.setParam("accountType", *s.accountType) + } + if s.current != nil { + r.setParam("current", *s.current) + } + if s.size != nil { + r.setParam("size", *s.size) + } + data, err := s.c.callAPI(ctx, r) + if err != nil { + return nil, err + } + res = new(BUSDConvertHistoryResponse) + err = json.Unmarshal(data, res) + if err != nil { + return nil, err + } + return res, nil +} + +// BUSDConvertHistoryResponse define response of BUSDConvertHistoryService +type BUSDConvertHistoryResponse struct { + Total int32 `json:"total"` + Rows []struct { + TranId int64 `json:"tranId"` + Type int32 `json:"type"` + Time uint64 `json:"time"` + DeductedAsset string `json:"deductedAsset"` + DeductedAmount string `json:"deductedAmount"` + TargetAsset string `json:"targetAsset"` + TargetAmount string `json:"targetAmount"` + Status string `json:"status"` + AccountType string `json:"accountType"` + } `json:"rows"` +} + +// Get Cloud-Mining payment and refund history (USER_DATA) +const ( + cloudMiningPaymentHistoryEndpoint = "/sapi/v1/asset/ledger-transfer/cloud-mining/queryByPage" +) + +// CloudMiningPaymentHistoryService cloud mining payment history +type CloudMiningPaymentHistoryService struct { + c *Client + tranid *int64 + clientTranId *string + asset *string + startTime uint64 + endTime uint64 + current *int + size *int +} + +// Tranid set tranid +func (s *CloudMiningPaymentHistoryService) Tranid(tranid int64) *CloudMiningPaymentHistoryService { + s.tranid = &tranid + return s +} + +// ClientTranId set clientTranId +func (s *CloudMiningPaymentHistoryService) ClientTranId(clientTranId string) *CloudMiningPaymentHistoryService { + s.clientTranId = &clientTranId + return s +} + +// Asset set asset +func (s *CloudMiningPaymentHistoryService) Asset(asset string) *CloudMiningPaymentHistoryService { + s.asset = &asset + return s +} + +// StartTime set startTime +func (s *CloudMiningPaymentHistoryService) StartTime(startTime uint64) *CloudMiningPaymentHistoryService { + s.startTime = startTime + return s +} + +// EndTime set endTime +func (s *CloudMiningPaymentHistoryService) EndTime(endTime uint64) *CloudMiningPaymentHistoryService { + s.endTime = endTime + return s +} + +// Current set current +func (s *CloudMiningPaymentHistoryService) Current(current int) *CloudMiningPaymentHistoryService { + s.current = ¤t + return s +} + +// Size set size +func (s *CloudMiningPaymentHistoryService) Size(size int) *CloudMiningPaymentHistoryService { + s.size = &size + return s +} + +func (s *CloudMiningPaymentHistoryService) Do(ctx context.Context) (res *CloudMiningPaymentHistoryResponse, err error) { + r := &request{ + method: http.MethodGet, + endpoint: cloudMiningPaymentHistoryEndpoint, + secType: secTypeSigned, + } + r.setParam("startTime", s.startTime) + r.setParam("endTime", s.endTime) + if s.tranid != nil { + r.setParam("tranId", *s.tranid) + } + if s.clientTranId != nil { + r.setParam("clientTranId", *s.clientTranId) + } + if s.asset != nil { + r.setParam("asset", *s.asset) + } + if s.current != nil { + r.setParam("current", *s.current) + } + if s.size != nil { + r.setParam("size", *s.size) + } + data, err := s.c.callAPI(ctx, r) + if err != nil { + return nil, err + } + res = new(CloudMiningPaymentHistoryResponse) + err = json.Unmarshal(data, res) + if err != nil { + return nil, err + } + return res, nil +} + +// CloudMiningPaymentHistoryResponse define response of CloudMiningPaymentHistoryService +type CloudMiningPaymentHistoryResponse struct { + Total int32 `json:"total"` + Rows []struct { + CreateTime uint64 `json:"createTime"` + TranId int64 `json:"tranId"` + Type int32 `json:"type"` + Asset string `json:"asset"` + Amount string `json:"amount"` + Status string `json:"status"` + } `json:"rows"` +} + +// Get API Key Permission (USER_DATA) +const ( + apiKeyPermissionEndpoint = "/sapi/v1/account/apiRestrictions" +) + +// APIKeyPermissionService get api key permission +type APIKeyPermissionService struct { + c *Client +} + +func (s *APIKeyPermissionService) Do(ctx context.Context) (res *APIKeyPermissionResponse, err error) { + r := &request{ + method: http.MethodGet, + endpoint: apiKeyPermissionEndpoint, + secType: secTypeSigned, + } + data, err := s.c.callAPI(ctx, r) + if err != nil { + return nil, err + } + res = new(APIKeyPermissionResponse) + err = json.Unmarshal(data, res) + if err != nil { + return nil, err + } + return res, nil +} + +// APIKeyPermissionResponse define response of APIKeyPermissionService +type APIKeyPermissionResponse struct { + IPRestrict bool `json:"ipRestrict"` + CreateTime uint64 `json:"createTime"` + EnableWithdrawals bool `json:"enableWithdrawals"` + EnableInternalTransfer bool `json:"enableInternalTransfer"` + PermitsUniversalTransfer bool `json:"permitsUniversalTransfer"` + EnableVanillaOptions bool `json:"enableVanillaOptions"` + EnableReading bool `json:"enableReading"` + EnableFutures bool `json:"enableFutures"` + EnableMargin bool `json:"enableMargin"` + EnableSpotAndMarginTrading bool `json:"enableSpotAndMarginTrading"` + TradingAuthorityExpirationTime uint64 `json:"tradingAuthorityExpirationTime"` +} + +// Query auto-converting stable coins (USER_DATA) +const ( + autoConvertStableCoinEndpoint = "/sapi/v1/capital/contract/convertible-coins" +) + +// AutoConvertStableCoinService auto convert stable coin +type AutoConvertStableCoinService struct { + c *Client +} + +func (s *AutoConvertStableCoinService) Do(ctx context.Context) (res *AutoConvertStableCoinResponse, err error) { + r := &request{ + method: http.MethodGet, + endpoint: autoConvertStableCoinEndpoint, + secType: secTypeSigned, + } + data, err := s.c.callAPI(ctx, r) + if err != nil { + return nil, err + } + res = new(AutoConvertStableCoinResponse) + err = json.Unmarshal(data, res) + if err != nil { + return nil, err + } + return res, nil +} + +// AutoConvertStableCoinResponse define response of AutoConvertStableCoinService +type AutoConvertStableCoinResponse struct { + ConvertEnabled bool `json:"convertEnabled"` + Coins []struct { + Asset string `json:"coin"` + } `json:"coins"` + ExchangeRates []struct { + Asset string `json:"coin"` + } `json:"exchangeRates"` +} diff --git a/wallet_test.go b/wallet_test.go new file mode 100644 index 0000000..258c6d9 --- /dev/null +++ b/wallet_test.go @@ -0,0 +1,1020 @@ +package binance_connector + +import ( + "context" + "testing" + + "github.com/stretchr/testify/suite" +) + +type walletTestSuite struct { + baseTestSuite +} + +func TestWallet(t *testing.T) { + suite.Run(t, new(walletTestSuite)) +} + +func (s *walletTestSuite) TestCreateWithdraw() { + data := []byte(` + { + "id":"7213fea8e94b4a5593d507237e5a555b" + } + `) + s.mockDo(data, nil) + defer s.assertDo() + + coin := "USDT" + withdrawOrderID := "testID" + network := "ETH" + address := "myaddress" + addressTag := "xyz" + amount := 0.01 + transactionFeeFlag := true + name := "eth" + s.assertReq(func(r *request) { + e := newSignedRequest().setParams(params{ + "coin": coin, + "withdrawOrderId": withdrawOrderID, + "network": network, + "address": address, + "addressTag": addressTag, + "amount": amount, + "transactionFeeFlag": transactionFeeFlag, + "name": name, + }) + s.assertRequestEqual(e, r) + }) + + res, err := s.client.NewWithdrawService(). + Coin(coin). + WithdrawOrderId(withdrawOrderID). + Network(network). + Address(address). + AddressTag(addressTag). + Amount(amount). + TransactionFeeFlag(transactionFeeFlag). + Name(name). + Do(newContext()) + + r := s.r() + r.NoError(err) + r.Equal("7213fea8e94b4a5593d507237e5a555b", res.Id) +} + +func (s *walletTestSuite) TestDustTransfer() { + data := []byte(`{ + "totalServiceCharge":"0.02102542", + "totalTransfered":"1.05127099", + "transferResult":[ + { + "amount":"0.03000000", + "fromAsset":"ETH", + "operateTime":1563368549307, + "serviceChargeAmount":"0.00500000", + "tranId":2970932918, + "transferedAmount":"0.25000000" + }, + { + "amount":"0.09000000", + "fromAsset":"LTC", + "operateTime":1563368549404, + "serviceChargeAmount":"0.01548000", + "tranId":2970932918, + "transferedAmount":"0.77400000" + }, + { + "amount":"248.61878453", + "fromAsset":"TRX", + "operateTime":1563368549489, + "serviceChargeAmount":"0.00054542", + "tranId":2970932918, + "transferedAmount":"0.02727099" + } + ] + }`) + s.mockDo(data, nil) + defer s.assertDo() + asset := []string{"ETH", "LTC", "TRX"} + s.assertReq(func(r *request) { + e := newSignedRequest() + for _, a := range asset { + e.addParam("asset", a) + } + s.assertRequestEqual(e, r) + }) + res, err := s.client.NewDustTransferService().Asset(asset).Do(newContext()) + s.r().NoError(err) + e := &DustTransferResponse{ + TotalServiceCharge: "0.02102542", + TotalTransfered: "1.05127099", + TransferResult: []*DustTransferResult{ + { + Amount: "0.03000000", + FromAsset: "ETH", + OperateTime: 1563368549307, + ServiceChargeAmount: "0.00500000", + TranID: 2970932918, + TransferedAmount: "0.25000000", + }, + { + Amount: "0.09000000", + FromAsset: "LTC", + OperateTime: 1563368549404, + ServiceChargeAmount: "0.01548000", + TranID: 2970932918, + TransferedAmount: "0.77400000", + }, + { + Amount: "248.61878453", + FromAsset: "TRX", + OperateTime: 1563368549489, + ServiceChargeAmount: "0.00054542", + TranID: 2970932918, + TransferedAmount: "0.02727099", + }, + }, + } + s.assertTransferResponse(e, res) +} + +func (s *walletTestSuite) assertTransferResponse(e, a *DustTransferResponse) { + r := s.r() + r.Equal(e.TotalServiceCharge, a.TotalServiceCharge, "TotalServiceCharge") + r.Equal(e.TotalTransfered, a.TotalTransfered, "TotalTransfered") + for i, etr := range e.TransferResult { + r.Equal(etr.Amount, a.TransferResult[i].Amount, "Amount") + r.Equal(etr.FromAsset, a.TransferResult[i].FromAsset, "FromAsset") + r.Equal(etr.OperateTime, a.TransferResult[i].OperateTime, "OperateTime") + r.Equal(etr.ServiceChargeAmount, a.TransferResult[i].ServiceChargeAmount, "ServiceChargeAmount") + r.Equal(etr.TranID, a.TransferResult[i].TranID, "TranID") + r.Equal(etr.TransferedAmount, a.TransferResult[i].TransferedAmount, "TransferedAmount") + } +} + +func (s *walletTestSuite) TestUserUniversalTransfer() { + data := []byte(` + { + "tranId":13526853623 + } + `) + s.mockDo(data, nil) + defer s.assertDo() + + types := "MAIN_C2C" + asset := "USDT" + amount := 0.1 + fromSymbol := "USDT" + toSymbol := "USDT" + + s.assertReq(func(r *request) { + e := newSignedRequest().setParams(params{ + "type": types, + "asset": asset, + "amount": amount, + "fromSymbol": fromSymbol, + "toSymbol": toSymbol, + }) + s.assertRequestEqual(e, r) + }) + + res, err := s.client.NewUserUniversalTransferService(). + TransferType(types). + Asset(asset). + Amount(amount). + FromSymbol(fromSymbol). + ToSymbol(toSymbol). + Do(newContext()) + + r := s.r() + r.NoError(err) + r.Equal(int64(13526853623), res.TranId) +} + +func (s *walletTestSuite) TestBusdConvert() { + data := []byte(` + { + "tranId": 13526853623, + "status": "S" + } + `) + s.mockDo(data, nil) + defer s.assertDo() + + clientTranId := "X7612JSNTO8274HXUQJ2" + asset := "USDT" + amount := float64(20) + targetAsset := "BUSD" + + s.assertReq(func(r *request) { + e := newSignedRequest().setParams(params{ + "clientTranId": clientTranId, + "asset": asset, + "amount": amount, + "targetAsset": targetAsset, + }) + s.assertRequestEqual(e, r) + }) + + res, err := s.client.NewBUSDConvertService(). + ClientTranId(clientTranId). + Asset(asset). + Amount(amount). + TargetAsset(targetAsset). + Do(newContext()) + + r := s.r() + r.NoError(err) + r.Equal(int64(13526853623), res.TranId) + r.Equal("S", res.Status) +} + +func (s *walletTestSuite) TestGetDepositAddress() { + data := []byte(` + { + "address": "1HPn8Rx2y6nNSfagQBKy27GB99Vbzg89wv", + "coin": "BTC", + "tag": "", + "url": "https://btc.com/1HPn8Rx2y6nNSfagQBKy27GB99Vbzg89wv" + } + `) + s.mockDo(data, nil) + defer s.assertDo() + + coin := "BTC" + network := "BTC" + s.assertReq(func(r *request) { + e := newSignedRequest().setParams(params{ + "coin": coin, + "network": network, + }) + s.assertRequestEqual(e, r) + }) + + res, err := s.client.NewDepositAddressService(). + Coin(coin). + Network(network). + Do(newContext()) + + r := s.r() + r.NoError(err) + r.Equal("1HPn8Rx2y6nNSfagQBKy27GB99Vbzg89wv", res.Address) + r.Equal("", res.Tag) + r.Equal("BTC", res.Coin) + r.Equal("https://btc.com/1HPn8Rx2y6nNSfagQBKy27GB99Vbzg89wv", res.Url) +} + +func (s *walletTestSuite) TestAccountApiTradingStatus() { + data := []byte(` + { + "data": { + "isLocked": false, + "plannedRecoverTime": 0, + "triggerCondition": { + "GCR": 90, + "IFER": 90, + "UFR": 90 + }, + "updateTime": 1613450271000 + } + } + `) + + s.mockDo(data, nil) + defer s.assertDo() + + resp, err := s.client.NewAccountApiTradingStatusService().Do(context.Background()) + + s.r().NoError(err) + s.False(resp.Data.IsLocked) + s.Equal(int64(0), resp.Data.PlannedRecoverTime) + s.Equal(90, resp.Data.TriggerCondition.GCR) + s.Equal(90, resp.Data.TriggerCondition.IFER) + s.Equal(90, resp.Data.TriggerCondition.UFR) + s.Equal(uint64(1613450271000), resp.Data.UpdateTime) +} + +func (s *walletTestSuite) TestAccountStatusService() { + data := []byte(` + { + "data": "active" + } + `) + + s.mockDo(data, nil) + defer s.assertDo() + + resp, err := s.client.NewAccountStatusService().Do(context.Background()) + + s.r().NoError(err) + s.Equal("active", resp.Data) +} + +func (s *walletTestSuite) TestAPIKeyPermission() { + data := []byte(` + { + "ipRestrict": false, + "createTime": 1638289749000, + "enableWithdrawals": true, + "enableInternalTransfer": true, + "permitsUniversalTransfer": true, + "enableVanillaOptions": true, + "enableReading": true, + "enableFutures": true, + "enableMargin": true, + "enableSpotAndMarginTrading": true, + "tradingAuthorityExpirationTime": 1640978149000 + } + `) + + s.mockDo(data, nil) + defer s.assertDo() + + resp, err := s.client.NewAPIKeyPermissionService().Do(context.Background()) + + s.r().NoError(err) + s.NotNil(resp) + s.False(resp.IPRestrict) + s.Equal(uint64(1638289749000), resp.CreateTime) + s.True(resp.EnableWithdrawals) + s.True(resp.EnableInternalTransfer) + s.True(resp.PermitsUniversalTransfer) + s.True(resp.EnableVanillaOptions) + s.True(resp.EnableReading) + s.True(resp.EnableFutures) + s.True(resp.EnableMargin) + s.True(resp.EnableSpotAndMarginTrading) + s.Equal(uint64(1640978149000), resp.TradingAuthorityExpirationTime) +} + +func (s *walletTestSuite) TestAssetDetail() { + data := []byte(` + { + "details": [ + { + "asset": "BTC", + "assetFullName": "Bitcoin", + "amountFree": "0.00001000", + "toBTC": "0.00000910", + "toBNB": "0.00000890", + "toBNBOffExchange": "0.00000800", + "exchange": "Binance" + } + ], + "totalTransferBtc": "0.00000910", + "totalTransferBnb": "0.00000890", + "dribbletPercentage": "0.10000000" + } + `) + + s.mockDo(data, nil) + defer s.assertDo() + + resp, err := s.client.NewAssetDetailService(). + Do(context.Background()) + + s.r().NoError(err) + s.Len(resp.Details, 1) + s.Equal("BTC", resp.Details[0].Asset) + s.Equal("Bitcoin", resp.Details[0].AssetFullName) + s.Equal("0.00001000", resp.Details[0].AmountFree) + s.Equal("0.00000910", resp.Details[0].ToBTC) + s.Equal("0.00000890", resp.Details[0].ToBNB) + s.Equal("0.00000800", resp.Details[0].ToBNBOffExchange) + s.Equal("Binance", resp.Details[0].Exchange) + s.Equal("0.00000910", resp.TotalTransferBtc) + s.Equal("0.00000890", resp.TotalTransferBnb) + s.Equal("0.10000000", resp.DribbletPercentage) +} + +func (s *walletTestSuite) TestAssetDetailV2() { + data := []byte(` + { + "assetDetail": { + "minWithdrawAmount": "0.001", + "depositStatus": true, + "withdrawFee": "0.0005", + "withdrawStatus": true, + "depositTip": "Please don't deposit any other assets except RUB" + } + }`) + + s.mockDo(data, nil) + defer s.assertDo() + + resp, err := s.client.NewAssetDetailV2Service(). + Asset("BTC"). + Do(context.Background()) + + s.r().NoError(err) + s.NotNil(resp.AssetDetail) + s.Equal("0.001", resp.AssetDetail.MinWithdrawAmount) + s.True(resp.AssetDetail.DepositStatus) + s.Equal("0.0005", resp.AssetDetail.WithdrawFee) + s.True(resp.AssetDetail.WithdrawStatus) + s.Equal("Please don't deposit any other assets except RUB", resp.AssetDetail.DepositTip) +} + +func (s *walletTestSuite) TestAssetDividendRecord() { + data := []byte(` + { + "rows": [ + { + "id": 123, + "amount": "1.00000000", + "asset": "BTC", + "divTime": 1613450271000, + "enInfo": "BTC distribution", + "tranId": 456 + } + ], + "total": 1 + } + `) + + s.mockDo(data, nil) + defer s.assertDo() + + resp, err := s.client.NewAssetDividendRecordService(). + Asset("BTC"). + StartTime(1613450271000). + EndTime(1613536671000). + Limit(500). + Do(context.Background()) + + s.r().NoError(err) + s.Len(resp.Rows, 1) + s.Equal(int64(123), resp.Rows[0].Id) + s.Equal("1.00000000", resp.Rows[0].Amount) + s.Equal("BTC", resp.Rows[0].Asset) + s.Equal(uint64(1613450271000), resp.Rows[0].DivTime) + s.Equal("BTC distribution", resp.Rows[0].EnInfo) + s.Equal(int64(456), resp.Rows[0].TranId) + s.Equal(int64(1), resp.Total) +} + +func (s *walletTestSuite) TestAutoConvertStableCoin() { + data := []byte(` + { + "convertEnabled": true, + "coins": [ + { + "coin": "BUSD" + }, + { + "coin": "USDT" + } + ], + "exchangeRates": [ + { + "coin": "BUSD" + }, + { + "coin": "USDT" + } + ] + } + `) + + s.mockDo(data, nil) + defer s.assertDo() + + resp, err := s.client.NewAutoConvertStableCoinService().Do(context.Background()) + + s.r().NoError(err) + s.True(resp.ConvertEnabled) + s.Len(resp.Coins, 2) + s.Equal("BUSD", resp.Coins[0].Asset) + s.Equal("USDT", resp.Coins[1].Asset) + s.Len(resp.ExchangeRates, 2) + s.Equal("BUSD", resp.ExchangeRates[0].Asset) + s.Equal("USDT", resp.ExchangeRates[1].Asset) +} + +func (s *walletTestSuite) TestBUSDConvertHistory() { + data := []byte(` + { + "total": 1, + "rows": [ + { + "tranId":118263615991, + "type":244, + "time":1664442078000, + "deductedAsset":"BUSD", + "deductedAmount":"1", + "targetAsset":"USDC", + "targetAmount":"1", + "status":"S", + "accountType":"MAIN" + } + ] + }`) + + s.mockDo(data, nil) + defer s.assertDo() + + resp, err := s.client.NewBUSDConvertHistoryService(). + Asset("BUSD"). + StartTime(1664442078000). + EndTime(1613536671000). + Current(1). + Size(500). + Do(context.Background()) + + s.r().NoError(err) + s.Len(resp.Rows, 1) + s.Equal(int64(118263615991), resp.Rows[0].TranId) + s.Equal(int32(244), resp.Rows[0].Type) + s.Equal(uint64(1664442078000), resp.Rows[0].Time) + s.Equal("BUSD", resp.Rows[0].DeductedAsset) + s.Equal("1", resp.Rows[0].DeductedAmount) + s.Equal("S", resp.Rows[0].Status) + s.Equal("MAIN", resp.Rows[0].AccountType) + s.Equal(int32(1), resp.Total) +} + +func (s *walletTestSuite) TestCloudMiningPaymentHistory() { + data := []byte(` + { + "rows": [ + { + "createTime": 1613450271000, + "tranId": 123, + "type": 0, + "asset": "BTC", + "amount": "1.00000000", + "status": "CONFIRMED" + } + ], + "total": 1 + } + `) + + s.mockDo(data, nil) + defer s.assertDo() + + resp, err := s.client.NewCloudMiningPaymentHistoryService(). + Asset("BTC"). + StartTime(1613450271000). + EndTime(1613536671000). + Current(1). + Size(500). + Do(context.Background()) + + s.r().NoError(err) + s.Len(resp.Rows, 1) + s.Equal(uint64(1613450271000), resp.Rows[0].CreateTime) + s.Equal(int64(123), resp.Rows[0].TranId) + s.Equal(int32(0), resp.Rows[0].Type) + s.Equal("BTC", resp.Rows[0].Asset) + s.Equal("1.00000000", resp.Rows[0].Amount) + s.Equal("CONFIRMED", resp.Rows[0].Status) + s.Equal(int32(1), resp.Total) +} + +func (s *walletTestSuite) TestDepositHistory() { + data := []byte(` + { + "id": "769800519366885376", + "amount": "0.001", + "coin": "BNB", + "network": "BNB", + "status": 0, + "address": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", + "addressTag": "101764890", + "txId": "98A3EA560C6B3336D348B6C83F0F95ECE4F1F5919E94BD006E5BF3BF264FACFC", + "insertTime": 1661493146000, + "transferType": 0, + "confirmTimes": "1/1", + "unlockConfirm": 0, + "walletType": 0 + }`) + + s.mockDo(data, nil) + defer s.assertDo() + + resp, err := s.client.NewDepositHistoryService(). + Coin("BTC"). + Status(1). + StartTime(1609459200000). + EndTime(1609545600000). + Offset(0). + Limit(500). + Do(context.Background()) + + s.r().NoError(err) + s.Equal("769800519366885376", resp.Id) + s.Equal("0.001", resp.Amount) + s.Equal("BNB", resp.Coin) + s.Equal("BNB", resp.Network) + s.Equal(0, resp.Status) + s.Equal("bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", resp.Address) + s.Equal("101764890", resp.AddressTag) + s.Equal("98A3EA560C6B3336D348B6C83F0F95ECE4F1F5919E94BD006E5BF3BF264FACFC", resp.TxId) + s.Equal(uint64(1661493146000), resp.InsertTime) + s.Equal(0, resp.TransferType) + s.Equal("1/1", resp.ConfirmTimes) + s.Equal(0, resp.UnlockConfirm) + s.Equal(0, resp.WalletType) +} + +func (s *walletTestSuite) TestDustLog() { + data := []byte(` + { + "total": 1, + "userAssetDribblets": [ + { + "operateTime": 1613450271000, + "totalTransferedAmount": "0.00100000", + "totalServiceChargeAmount": "0.00000020", + "transId": 123, + "userAssetDribbletDetails": [ + { + "transId": 123, + "serviceChargeAmount": "0.00000010", + "amount": "0.00050000", + "operateTime": 1613450271000, + "transferedAmount": "0.00049000", + "fromAsset": "BTC" + }, + { + "transId": 123, + "serviceChargeAmount": "0.00000010", + "amount": "0.00050000", + "operateTime": 1613450271000, + "transferedAmount": "0.00049000", + "fromAsset": "ETH" + } + ] + } + ] + } + `) + + s.mockDo(data, nil) + defer s.assertDo() + + resp, err := s.client.NewDustLogService(). + StartTime(1613450271000). + EndTime(1613536671000). + Do(context.Background()) + + s.r().NoError(err) + s.Len(resp.UserAssetDribblets, 1) + s.Equal(1613450271000, int(resp.UserAssetDribblets[0].OperateTime)) + s.Equal("0.00100000", resp.UserAssetDribblets[0].TotalTransferedAmount) + s.Equal("0.00000020", resp.UserAssetDribblets[0].TotalServiceChargeAmount) + s.Equal(int64(123), resp.UserAssetDribblets[0].TransId) + s.Len(resp.UserAssetDribblets[0].UserAssetDribbletDetails, 2) + s.Equal(int64(123), resp.UserAssetDribblets[0].UserAssetDribbletDetails[0].TransId) + s.Equal("0.00000010", resp.UserAssetDribblets[0].UserAssetDribbletDetails[0].ServiceChargeAmount) + s.Equal("0.00050000", resp.UserAssetDribblets[0].UserAssetDribbletDetails[0].Amount) + s.Equal(uint64(1613450271000), uint64(resp.UserAssetDribblets[0].UserAssetDribbletDetails[0].OperateTime)) + s.Equal("0.00049000", resp.UserAssetDribblets[0].UserAssetDribbletDetails[0].TransferedAmount) + s.Equal("BTC", resp.UserAssetDribblets[0].UserAssetDribbletDetails[0].FromAsset) + s.Equal(int64(123), resp.UserAssetDribblets[0].UserAssetDribbletDetails[1].TransId) + s.Equal("0.00000010", resp.UserAssetDribblets[0].UserAssetDribbletDetails[1].ServiceChargeAmount) + s.Equal("0.00050000", resp.UserAssetDribblets[0].UserAssetDribbletDetails[1].Amount) + s.Equal(1613450271000, int(resp.UserAssetDribblets[0].UserAssetDribbletDetails[1].OperateTime)) + s.Equal("0.00049000", resp.UserAssetDribblets[0].UserAssetDribbletDetails[1].TransferedAmount) + s.Equal("ETH", resp.UserAssetDribblets[0].UserAssetDribbletDetails[1].FromAsset) +} + +func (s *walletTestSuite) TestFundingWallet() { + data := []byte(`{ + "asset": "BTC", + "free": "0.1", + "locked": "0.2", + "freeze": "0.3", + "withdrawing": "0.4", + "btcValuation": "0.5" + }`) + + s.mockDo(data, nil) + defer s.assertDo() + + resp, err := s.client.NewFundingWalletService(). + Asset("BTC"). + NeedBtcValuation("true"). + Do(context.Background()) + + s.r().NoError(err) + s.Equal("BTC", resp.Asset) + s.Equal("0.1", resp.Free) + s.Equal("0.2", resp.Locked) + s.Equal("0.3", resp.Freeze) + s.Equal("0.4", resp.Withdrawing) + s.Equal("0.5", resp.BtcValuation) +} + +func (s *walletTestSuite) TestGetAccountSnapshot() { + data := []byte(` + { + "code":200, + "msg":"success", + "snapshotVos":[ + { + "type":"SPOT", + "updateTime":1557712656239, + "data":{ + "balances":[ + { + "asset":"BTC", + "free":"0.00219821", + "locked":"0.00000000" + }, + { + "asset":"LTC", + "free":"0.00000000", + "locked":"0.00000000" + } + ], + "totalAssetOfBtc":"0.00167717" + } + } + ] + } + `) + + s.mockDo(data, nil) + defer s.assertDo() + + resp, err := s.client.NewGetAccountSnapshotService(). + MarketType("SPOT"). + StartTime(1557712656239). + Limit(500). + Do(context.Background()) + + s.r().NoError(err) + s.Equal(200, resp.Code) + s.Equal("success", resp.Msg) + s.Len(resp.SnapshotVos, 1) + s.Equal("SPOT", resp.SnapshotVos[0].Type) + s.Equal(uint64(1557712656239), resp.SnapshotVos[0].UpdateTime) + s.Len(resp.SnapshotVos[0].Data.Balances, 2) + s.Equal("BTC", resp.SnapshotVos[0].Data.Balances[0].Asset) + s.Equal("0.00219821", resp.SnapshotVos[0].Data.Balances[0].Free) + s.Equal("0.00000000", resp.SnapshotVos[0].Data.Balances[0].Locked) + s.Equal("LTC", resp.SnapshotVos[0].Data.Balances[1].Asset) + s.Equal("0.00000000", resp.SnapshotVos[0].Data.Balances[1].Free) + s.Equal("0.00000000", resp.SnapshotVos[0].Data.Balances[1].Locked) + s.Equal("0.00167717", resp.SnapshotVos[0].Data.TotalAssetOfBtc) +} + +func (s *walletTestSuite) TestGetAllCoinsInfoService() { + data := []byte(` + [ + { + "coin": "BTC", + "depositAllEnable": true, + "free": "0.00000000", + "freeze": "0.00000000", + "ipoable": "0.00000000", + "ipoing": "0.00000000", + "isLegalMoney": false, + "locked": "0.00000000", + "name": "Bitcoin", + "networkList": [ + { + "addressRegex": "^(bnb1)[0-9a-z]{38}$", + "coin": "BTC", + "depositDesc": "Deposit to address", + "depositEnable": true, + "isDefault": false, + "memoRegex": "", + "minConfirm": 1, + "name": "BEP2", + "network": "BNB", + "resetAddressStatus": false, + "specialTips": "", + "unLockConfirm": 0, + "withdrawDesc": "Withdrawal to address", + "withdrawEnable": true, + "withdrawFee": "0.00000120", + "withdrawIntegerMultiple": "0.00000001", + "withdrawMax": "0.00000000", + "withdrawMin": "0.00200000", + "sameAddress": false, + "estimatedArrivalTime": 0, + "busy": false + } + ], + "storage": "0.00000000", + "trading": true, + "withdrawAllEnable": true, + "withdrawing": "0.00000000" + } + ] + `) + + s.mockDo(data, nil) + defer s.assertDo() + + resp, err := s.client.NewGetAllCoinsInfoService().Do(context.Background()) + + s.r().NoError(err) + s.Len(resp, 1) + s.Equal("BTC", resp[0].Coin) + s.True(resp[0].DepositAllEnable) + s.Equal("0.00000000", resp[0].Free) + s.Equal("0.00000000", resp[0].Freeze) + s.Equal("0.00000000", resp[0].Ipoable) + s.Equal("0.00000000", resp[0].Ipoing) + s.False(resp[0].IsLegalMoney) + s.Equal("0.00000000", resp[0].Locked) + s.Equal("Bitcoin", resp[0].Name) + s.Len(resp[0].NetworkList, 1) + s.Equal("^(bnb1)[0-9a-z]{38}$", resp[0].NetworkList[0].AddressRegex) + s.Equal("BTC", resp[0].NetworkList[0].Coin) + s.Equal("Deposit to address", resp[0].NetworkList[0].DepositDesc) + s.True(resp[0].NetworkList[0].DepositEnable) + s.False(resp[0].NetworkList[0].IsDefault) + s.Equal("", resp[0].NetworkList[0].MemoRegex) + s.Equal(1, resp[0].NetworkList[0].MinConfirm) + s.Equal("BEP2", resp[0].NetworkList[0].Name) + s.Equal("BNB", resp[0].NetworkList[0].Network) + s.False(resp[0].NetworkList[0].ResetAddressStatus) + s.Equal("", resp[0].NetworkList[0].SpecialTips) + s.Equal(0, resp[0].NetworkList[0].UnLockConfirm) + s.Equal("Withdrawal to address", resp[0].NetworkList[0].WithdrawDesc) + s.True(resp[0].NetworkList[0].WithdrawEnable) + s.Equal("0.00000120", resp[0].NetworkList[0].WithdrawFee) + s.Equal("0.00000001", resp[0].NetworkList[0].WithdrawIntegerMultiple) + s.Equal("0.00000000", resp[0].NetworkList[0].WithdrawMax) + s.Equal("0.00200000", resp[0].NetworkList[0].WithdrawMin) + s.False(resp[0].NetworkList[0].SameAddress) + s.Equal(uint64(0), resp[0].NetworkList[0].EstimatedArrivalTime) + s.False(resp[0].NetworkList[0].Busy) + s.Equal("0.00000000", resp[0].Storage) + s.True(resp[0].Trading) + s.True(resp[0].WithdrawAllEnable) + s.Equal("0.00000000", resp[0].Withdrawing) +} + +func (s *walletTestSuite) TestGetSystemStatus() { + data := []byte(` + [ + { + "status": true, + "msg": "normal" + } + ] + `) + + s.mockDo(data, nil) + defer s.assertDo() + + resp, err := s.client.NewGetSystemStatusService().Do(context.Background()) + + s.r().NoError(err) + s.Len(resp, 1) + s.Equal(true, resp[0].Status) + s.Equal("normal", resp[0].Msg) +} + +func (s *walletTestSuite) TestTradeFee() { + data := []byte(` + { + "symbol": "BTCUSDT", + "makerCommission": "0.00050000", + "takerCommission": "0.00050000" + } + `) + + s.mockDo(data, nil) + defer s.assertDo() + + resp, err := s.client.NewTradeFeeService(). + Symbol("BTCUSDT"). + Do(context.Background()) + + s.r().NoError(err) + s.NotNil(resp) + s.Equal("BTCUSDT", resp.Symbol) + s.Equal("0.00050000", resp.MakerCommission) + s.Equal("0.00050000", resp.TakerCommission) +} + +func (s *walletTestSuite) TestUserAsset() { + data := []byte(` + { + "asset": "BTC", + "free": "1.00000000", + "locked": "0.00000000", + "freeze": "0.00000000", + "withdrawing": "0.00000000", + "ipoable": "0.00000000", + "btcValuation": "1000000.00000000" + } + `) + + s.mockDo(data, nil) + defer s.assertDo() + + resp, err := s.client.NewUserAssetService(). + Asset("BTC"). + NeedBtcValuation(true). + Do(context.Background()) + + s.r().NoError(err) + s.Equal("BTC", resp.Asset) + s.Equal("1.00000000", resp.Free) + s.Equal("0.00000000", resp.Locked) + s.Equal("0.00000000", resp.Freeze) + s.Equal("0.00000000", resp.Withdrawing) + s.Equal("0.00000000", resp.Ipoable) + s.Equal("1000000.00000000", resp.BtcValuation) +} + +func (s *walletTestSuite) TestUserUniversalTransferHistory() { + data := []byte(` + { + "rows": [ + { + "asset": "BTC", + "amount": "1.00000000", + "type": "MAIN_UMFUTURE", + "status": "CONFIRMED", + "tranId": 123, + "timestamp": 1613450271000 + } + ], + "total": 1 + } + `) + + s.mockDo(data, nil) + defer s.assertDo() + + resp, err := s.client.NewUserUniversalTransferHistoryService(). + TransferType("MAIN_UMFUTURE"). + StartTime(1613450271000). + EndTime(1613536671000). + Current(1). + Size(500). + FromSymbol("BTC"). + ToSymbol("USDT"). + Do(context.Background()) + + s.r().NoError(err) + s.Len(resp.Rows, 1) + s.Equal("BTC", resp.Rows[0].Asset) + s.Equal("1.00000000", resp.Rows[0].Amount) + s.Equal("MAIN_UMFUTURE", resp.Rows[0].Type) + s.Equal("CONFIRMED", resp.Rows[0].Status) + s.Equal(int64(123), resp.Rows[0].TranId) + s.Equal(uint64(1613450271000), resp.Rows[0].Timestamp) + s.Equal(int64(1), resp.Total) +} + +func (s *walletTestSuite) TestWithdrawHistory() { + data := []byte(` + { + "id": "btc123", + "amount": "1.00000000", + "transactionFee": "0.00010000", + "coin": "BTC", + "status": 6, + "address": "abc123", + "txId": "def456", + "applyTime": 1617233588000, + "network": "btc", + "transferType": 0, + "withdrawOrderId": "ghi789", + "info": "", + "confirmNo": 2, + "walletType": 1, + "txKey": "jkl012" + } + `) + + s.mockDo(data, nil) + defer s.assertDo() + + resp, err := s.client.NewWithdrawHistoryService(). + Coin("BTC"). + WithdrawOrderId("ghi789"). + Status(6). + Offset(0). + Limit(10). + StartTime(1617233588000). + EndTime(1617320000000). + Do(context.Background()) + + s.r().NoError(err) + s.Equal("btc123", resp.Id) + s.Equal("1.00000000", resp.Amount) + s.Equal("0.00010000", resp.TransactionFee) + s.Equal("BTC", resp.Coin) + s.Equal(6, resp.Status) + s.Equal("abc123", resp.Address) + s.Equal("def456", resp.TxId) + s.Equal(uint64(1617233588000), resp.ApplyTime) + s.Equal("btc", resp.Network) + s.Equal(0, resp.TransferType) + s.Equal("ghi789", resp.WithdrawOrderId) + s.Equal("", resp.Info) + s.Equal(2, resp.ConfirmNo) + s.Equal(1, resp.WalletType) + s.Equal("jkl012", resp.TxKey) +} diff --git a/websocket.go b/websocket.go new file mode 100644 index 0000000..b7dd48f --- /dev/null +++ b/websocket.go @@ -0,0 +1,99 @@ +package binance_connector + +import ( + "net/http" + "time" + + "github.com/gorilla/websocket" +) + +// WsHandler handle raw websocket message +type WsHandler func(message []byte) + +// ErrHandler handles errors +type ErrHandler func(err error) + +// WsConfig webservice configuration +type WsConfig struct { + Endpoint string +} + +func newWsConfig(endpoint string) *WsConfig { + return &WsConfig{ + Endpoint: endpoint, + } +} + +var wsServe = func(cfg *WsConfig, handler WsHandler, errHandler ErrHandler) (doneCh, stopCh chan struct{}, err error) { + Dialer := websocket.Dialer{ + Proxy: http.ProxyFromEnvironment, + HandshakeTimeout: 45 * time.Second, + EnableCompression: false, + } + + c, _, err := Dialer.Dial(cfg.Endpoint, nil) + if err != nil { + return nil, nil, err + } + c.SetReadLimit(655350) + doneCh = make(chan struct{}) + stopCh = make(chan struct{}) + go func() { + // This function will exit either on error from + // websocket.Conn.ReadMessage or when the stopC channel is + // closed by the client. + defer close(doneCh) + if WebsocketKeepalive { + keepAlive(c, WebsocketTimeout) + } + // Wait for the stopC channel to be closed. We do that in a + // separate goroutine because ReadMessage is a blocking + // operation. + silent := false + go func() { + select { + case <-stopCh: + silent = true + case <-doneCh: + } + c.Close() + }() + for { + _, message, err := c.ReadMessage() + if err != nil { + if !silent { + errHandler(err) + } + return + } + handler(message) + } + }() + return +} + +func keepAlive(c *websocket.Conn, timeout time.Duration) { + ticker := time.NewTicker(timeout) + + lastResponse := time.Now() + c.SetPongHandler(func(msg string) error { + lastResponse = time.Now() + return nil + }) + + go func() { + defer ticker.Stop() + for { + deadline := time.Now().Add(10 * time.Second) + err := c.WriteControl(websocket.PingMessage, []byte{}, deadline) + if err != nil { + return + } + <-ticker.C + if time.Since(lastResponse) > timeout { + c.Close() + return + } + } + }() +} diff --git a/websocket_service.go b/websocket_service.go new file mode 100644 index 0000000..0e75c3c --- /dev/null +++ b/websocket_service.go @@ -0,0 +1,843 @@ +package binance_connector + +import ( + "fmt" + "strconv" + "strings" + "time" + + "encoding/json" + stdjson "encoding/json" +) + +// Endpoints +const ( + baseWsMainURL = "wss://stream.binance.com:9443/ws" + baseCombinedMainURL = "wss://stream.binance.com:9443/stream?streams=" +) + +type PriceLevel struct { + Price string + Quantity string +} + +// Parse parses this PriceLevel's Price and Quantity and +// returns them both. It also returns an error if either +// fails to parse. +func (p *PriceLevel) Parse() (float64, float64, error) { + price, err := strconv.ParseFloat(p.Price, 64) + if err != nil { + return 0, 0, err + } + quantity, err := strconv.ParseFloat(p.Quantity, 64) + if err != nil { + return price, 0, err + } + return price, quantity, nil +} + +// Ask is a type alias for PriceLevel. +type Ask = PriceLevel + +// Bid is a type alias for PriceLevel. +type Bid = PriceLevel + +const ( + UserDataEventTypeOutboundAccountPosition UserDataEventType = "outboundAccountPosition" + UserDataEventTypeBalanceUpdate UserDataEventType = "balanceUpdate" + UserDataEventTypeExecutionReport UserDataEventType = "executionReport" + UserDataEventTypeListStatus UserDataEventType = "ListStatus" +) + +var ( + // WebsocketTimeout is an interval for sending ping/pong messages if WebsocketKeepalive is enabled + WebsocketTimeout = time.Second * 60 + // WebsocketKeepalive enables sending ping/pong messages to check the connection stability + WebsocketKeepalive = false +) + +// getWsEndpoint return the base endpoint of the WS +func getWsEndpoint() string { + return baseWsMainURL +} + +// getCombinedEndpoint return the base endpoint of the combined stream +func getCombinedEndpoint() string { + return baseCombinedMainURL +} + +// WsPartialDepthEvent define websocket partial depth book event +type WsPartialDepthEvent struct { + Symbol string + LastUpdateID int64 `json:"lastUpdateId"` + Bids []Bid `json:"bids"` + Asks []Ask `json:"asks"` +} + +// WsPartialDepthHandler handle websocket partial depth event +type WsPartialDepthHandler func(event *WsPartialDepthEvent) + +// WsPartialDepthServe serve websocket partial depth handler with a symbol, using 1sec updates +func WsPartialDepthServe(symbol string, levels string, handler WsPartialDepthHandler, errHandler ErrHandler) (doneCh, stopCh chan struct{}, err error) { + endpoint := fmt.Sprintf("%s/%s@depth%s", getWsEndpoint(), strings.ToLower(symbol), levels) + return wsPartialDepthServe(endpoint, symbol, handler, errHandler) +} + +// WsPartialDepthServe100Ms serve websocket partial depth handler with a symbol, using 100msec updates +func WsPartialDepthServe100Ms(symbol string, levels string, handler WsPartialDepthHandler, errHandler ErrHandler) (doneCh, stopCh chan struct{}, err error) { + endpoint := fmt.Sprintf("%s/%s@depth%s@100ms", getWsEndpoint(), strings.ToLower(symbol), levels) + return wsPartialDepthServe(endpoint, symbol, handler, errHandler) +} + +// WsPartialDepthServe serve websocket partial depth handler with a symbol +func wsPartialDepthServe(endpoint string, symbol string, handler WsPartialDepthHandler, errHandler ErrHandler) (doneCh, stopCh chan struct{}, err error) { + cfg := newWsConfig(endpoint) + wsHandler := func(message []byte) { + j, err := newJSON(message) + if err != nil { + errHandler(err) + return + } + event := new(WsPartialDepthEvent) + event.Symbol = symbol + event.LastUpdateID = j.Get("lastUpdateId").MustInt64() + bidsLen := len(j.Get("bids").MustArray()) + event.Bids = make([]Bid, bidsLen) + for i := 0; i < bidsLen; i++ { + item := j.Get("bids").GetIndex(i) + event.Bids[i] = Bid{ + Price: item.GetIndex(0).MustString(), + Quantity: item.GetIndex(1).MustString(), + } + } + asksLen := len(j.Get("asks").MustArray()) + event.Asks = make([]Ask, asksLen) + for i := 0; i < asksLen; i++ { + item := j.Get("asks").GetIndex(i) + event.Asks[i] = Ask{ + Price: item.GetIndex(0).MustString(), + Quantity: item.GetIndex(1).MustString(), + } + } + handler(event) + } + return wsServe(cfg, wsHandler, errHandler) +} + +// WsCombinedPartialDepthServe is similar to WsPartialDepthServe, but it for multiple symbols +func WsCombinedPartialDepthServe(symbolLevels map[string]string, handler WsPartialDepthHandler, errHandler ErrHandler) (doneCh, stopCh chan struct{}, err error) { + endpoint := getCombinedEndpoint() + for s, l := range symbolLevels { + endpoint += fmt.Sprintf("%s@depth%s", strings.ToLower(s), l) + "/" + } + endpoint = endpoint[:len(endpoint)-1] + cfg := newWsConfig(endpoint) + wsHandler := func(message []byte) { + j, err := newJSON(message) + if err != nil { + errHandler(err) + return + } + event := new(WsPartialDepthEvent) + stream := j.Get("stream").MustString() + symbol := strings.Split(stream, "@")[0] + event.Symbol = strings.ToUpper(symbol) + data := j.Get("data").MustMap() + event.LastUpdateID, _ = data["lastUpdateId"].(stdjson.Number).Int64() + bidsLen := len(data["bids"].([]interface{})) + event.Bids = make([]Bid, bidsLen) + for i := 0; i < bidsLen; i++ { + item := data["bids"].([]interface{})[i].([]interface{}) + event.Bids[i] = Bid{ + Price: item[0].(string), + Quantity: item[1].(string), + } + } + asksLen := len(data["asks"].([]interface{})) + event.Asks = make([]Ask, asksLen) + for i := 0; i < asksLen; i++ { + + item := data["asks"].([]interface{})[i].([]interface{}) + event.Asks[i] = Ask{ + Price: item[0].(string), + Quantity: item[1].(string), + } + } + handler(event) + } + return wsServe(cfg, wsHandler, errHandler) +} + +// WsDepthHandler handle websocket depth event +type WsDepthHandler func(event *WsDepthEvent) + +// WsDepthServe serve websocket depth handler with a symbol, using 1sec updates +func WsDepthServe(symbol string, handler WsDepthHandler, errHandler ErrHandler) (doneCh, stopCh chan struct{}, err error) { + endpoint := fmt.Sprintf("%s/%s@depth", getWsEndpoint(), strings.ToLower(symbol)) + return wsDepthServe(endpoint, handler, errHandler) +} + +// WsDepthServe100Ms serve websocket depth handler with a symbol, using 100msec updates +func WsDepthServe100Ms(symbol string, handler WsDepthHandler, errHandler ErrHandler) (doneCh, stopCh chan struct{}, err error) { + endpoint := fmt.Sprintf("%s/%s@depth@100ms", getWsEndpoint(), strings.ToLower(symbol)) + return wsDepthServe(endpoint, handler, errHandler) +} + +// WsDepthServe serve websocket depth handler with an arbitrary endpoint address +func wsDepthServe(endpoint string, handler WsDepthHandler, errHandler ErrHandler) (doneCh, stopCh chan struct{}, err error) { + cfg := newWsConfig(endpoint) + wsHandler := func(message []byte) { + j, err := newJSON(message) + if err != nil { + errHandler(err) + return + } + event := new(WsDepthEvent) + event.Event = j.Get("e").MustString() + event.Time = j.Get("E").MustInt64() + event.Symbol = j.Get("s").MustString() + event.FirstUpdateID = j.Get("U").MustInt64() + event.LastUpdateID = j.Get("u").MustInt64() + bidsLen := len(j.Get("b").MustArray()) + event.Bids = make([]Bid, bidsLen) + for i := 0; i < bidsLen; i++ { + item := j.Get("b").GetIndex(i) + event.Bids[i] = Bid{ + Price: item.GetIndex(0).MustString(), + Quantity: item.GetIndex(1).MustString(), + } + } + asksLen := len(j.Get("a").MustArray()) + event.Asks = make([]Ask, asksLen) + for i := 0; i < asksLen; i++ { + item := j.Get("a").GetIndex(i) + event.Asks[i] = Ask{ + Price: item.GetIndex(0).MustString(), + Quantity: item.GetIndex(1).MustString(), + } + } + handler(event) + } + return wsServe(cfg, wsHandler, errHandler) +} + +// WsDepthEvent define websocket depth event +type WsDepthEvent struct { + Event string `json:"e"` + Time int64 `json:"E"` + Symbol string `json:"s"` + FirstUpdateID int64 `json:"U"` + LastUpdateID int64 `json:"u"` + Bids []Bid `json:"b"` + Asks []Ask `json:"a"` +} + +// WsCombinedDepthServe is similar to WsDepthServe, but it for multiple symbols +func WsCombinedDepthServe(symbols []string, handler WsDepthHandler, errHandler ErrHandler) (doneCh, stopCh chan struct{}, err error) { + endpoint := getCombinedEndpoint() + for _, s := range symbols { + endpoint += fmt.Sprintf("%s@depth", strings.ToLower(s)) + "/" + } + endpoint = endpoint[:len(endpoint)-1] + return wsCombinedDepthServe(endpoint, handler, errHandler) +} + +func WsCombinedDepthServe100Ms(symbols []string, handler WsDepthHandler, errHandler ErrHandler) (doneCh, stopCh chan struct{}, err error) { + endpoint := getCombinedEndpoint() + for _, s := range symbols { + endpoint += fmt.Sprintf("%s@depth@100ms", strings.ToLower(s)) + "/" + } + endpoint = endpoint[:len(endpoint)-1] + return wsCombinedDepthServe(endpoint, handler, errHandler) +} + +func wsCombinedDepthServe(endpoint string, handler WsDepthHandler, errHandler ErrHandler) (doneCh, stopCh chan struct{}, err error) { + cfg := newWsConfig(endpoint) + wsHandler := func(message []byte) { + j, err := newJSON(message) + if err != nil { + errHandler(err) + return + } + event := new(WsDepthEvent) + stream := j.Get("stream").MustString() + symbol := strings.Split(stream, "@")[0] + event.Symbol = strings.ToUpper(symbol) + data := j.Get("data").MustMap() + event.Time, _ = data["E"].(stdjson.Number).Int64() + event.LastUpdateID, _ = data["u"].(stdjson.Number).Int64() + event.FirstUpdateID, _ = data["U"].(stdjson.Number).Int64() + bidsLen := len(data["b"].([]interface{})) + event.Bids = make([]Bid, bidsLen) + for i := 0; i < bidsLen; i++ { + item := data["b"].([]interface{})[i].([]interface{}) + event.Bids[i] = Bid{ + Price: item[0].(string), + Quantity: item[1].(string), + } + } + asksLen := len(data["a"].([]interface{})) + event.Asks = make([]Ask, asksLen) + for i := 0; i < asksLen; i++ { + + item := data["a"].([]interface{})[i].([]interface{}) + event.Asks[i] = Ask{ + Price: item[0].(string), + Quantity: item[1].(string), + } + } + handler(event) + } + return wsServe(cfg, wsHandler, errHandler) +} + +// WsKlineHandler handle websocket kline event +type WsKlineHandler func(event *WsKlineEvent) + +// WsCombinedKlineServe is similar to WsKlineServe, but it handles multiple symbols with it interval +func WsCombinedKlineServe(symbolIntervalPair map[string]string, handler WsKlineHandler, errHandler ErrHandler) (doneCh, stopCh chan struct{}, err error) { + endpoint := getCombinedEndpoint() + for symbol, interval := range symbolIntervalPair { + endpoint += fmt.Sprintf("%s@kline_%s", strings.ToLower(symbol), interval) + "/" + } + endpoint = endpoint[:len(endpoint)-1] + cfg := newWsConfig(endpoint) + wsHandler := func(message []byte) { + j, err := newJSON(message) + if err != nil { + errHandler(err) + return + } + + stream := j.Get("stream").MustString() + data := j.Get("data").MustMap() + + symbol := strings.Split(stream, "@")[0] + + jsonData, _ := json.Marshal(data) + + event := new(WsKlineEvent) + err = json.Unmarshal(jsonData, event) + if err != nil { + errHandler(err) + return + } + event.Symbol = strings.ToUpper(symbol) + + handler(event) + } + return wsServe(cfg, wsHandler, errHandler) +} + +// WsKlineServe serve websocket kline handler with a symbol and interval like 15m, 30s +func WsKlineServe(symbol string, interval string, handler WsKlineHandler, errHandler ErrHandler) (doneCh, stopCh chan struct{}, err error) { + endpoint := fmt.Sprintf("%s/%s@kline_%s", getWsEndpoint(), strings.ToLower(symbol), interval) + cfg := newWsConfig(endpoint) + wsHandler := func(message []byte) { + event := new(WsKlineEvent) + err := json.Unmarshal(message, event) + if err != nil { + errHandler(err) + return + } + handler(event) + } + return wsServe(cfg, wsHandler, errHandler) +} + +// WsKlineEvent define websocket kline event +type WsKlineEvent struct { + Event string `json:"e"` + Time int64 `json:"E"` + Symbol string `json:"s"` + Kline WsKline `json:"k"` +} + +// WsKline define websocket kline +type WsKline struct { + StartTime int64 `json:"t"` + EndTime int64 `json:"T"` + Symbol string `json:"s"` + Interval string `json:"i"` + FirstTradeID int64 `json:"f"` + LastTradeID int64 `json:"L"` + Open string `json:"o"` + Close string `json:"c"` + High string `json:"h"` + Low string `json:"l"` + Volume string `json:"v"` + TradeNum int64 `json:"n"` + IsFinal bool `json:"x"` + QuoteVolume string `json:"q"` + ActiveBuyVolume string `json:"V"` + ActiveBuyQuoteVolume string `json:"Q"` +} + +// WsAggTradeHandler handle websocket aggregate trade event +type WsAggTradeHandler func(event *WsAggTradeEvent) + +// WsAggTradeServe serve websocket aggregate handler with a symbol +func WsAggTradeServe(symbol string, handler WsAggTradeHandler, errHandler ErrHandler) (doneCh, stopCh chan struct{}, err error) { + endpoint := fmt.Sprintf("%s/%s@aggTrade", getWsEndpoint(), strings.ToLower(symbol)) + cfg := newWsConfig(endpoint) + wsHandler := func(message []byte) { + event := new(WsAggTradeEvent) + err := json.Unmarshal(message, event) + if err != nil { + errHandler(err) + return + } + handler(event) + } + return wsServe(cfg, wsHandler, errHandler) +} + +// WsCombinedAggTradeServe is similar to WsAggTradeServe, but it handles multiple symbolx +func WsCombinedAggTradeServe(symbols []string, handler WsAggTradeHandler, errHandler ErrHandler) (doneCh, stopCh chan struct{}, err error) { + endpoint := getCombinedEndpoint() + for s := range symbols { + endpoint += fmt.Sprintf("%s@aggTrade", strings.ToLower(symbols[s])) + "/" + } + endpoint = endpoint[:len(endpoint)-1] + cfg := newWsConfig(endpoint) + wsHandler := func(message []byte) { + j, err := newJSON(message) + if err != nil { + errHandler(err) + return + } + + stream := j.Get("stream").MustString() + data := j.Get("data").MustMap() + + symbol := strings.Split(stream, "@")[0] + + jsonData, _ := json.Marshal(data) + + event := new(WsAggTradeEvent) + err = json.Unmarshal(jsonData, event) + if err != nil { + errHandler(err) + return + } + + event.Symbol = strings.ToUpper(symbol) + + handler(event) + } + return wsServe(cfg, wsHandler, errHandler) +} + +// WsAggTradeEvent define websocket aggregate trade event +type WsAggTradeEvent struct { + Event string `json:"e"` + Time int64 `json:"E"` + Symbol string `json:"s"` + AggTradeID int64 `json:"a"` + Price string `json:"p"` + Quantity string `json:"q"` + FirstBreakdownTradeID int64 `json:"f"` + LastBreakdownTradeID int64 `json:"l"` + TradeTime int64 `json:"T"` + IsBuyerMaker bool `json:"m"` + Placeholder bool `json:"M"` // add this field to avoid case insensitive unmarshaling +} + +// WsTradeHandler handle websocket trade event +type WsTradeHandler func(event *WsTradeEvent) +type WsCombinedTradeHandler func(event *WsCombinedTradeEvent) + +// WsTradeServe serve websocket handler with a symbol +func WsTradeServe(symbol string, handler WsTradeHandler, errHandler ErrHandler) (doneCh, stopCh chan struct{}, err error) { + endpoint := fmt.Sprintf("%s/%s@trade", getWsEndpoint(), strings.ToLower(symbol)) + cfg := newWsConfig(endpoint) + wsHandler := func(message []byte) { + event := new(WsTradeEvent) + err := json.Unmarshal(message, event) + if err != nil { + errHandler(err) + return + } + handler(event) + } + return wsServe(cfg, wsHandler, errHandler) +} + +func WsCombinedTradeServe(symbols []string, handler WsCombinedTradeHandler, errHandler ErrHandler) (doneCh, stopCh chan struct{}, err error) { + endpoint := getCombinedEndpoint() + for _, s := range symbols { + endpoint += fmt.Sprintf("%s@trade/", strings.ToLower(s)) + } + endpoint = endpoint[:len(endpoint)-1] + cfg := newWsConfig(endpoint) + wsHandler := func(message []byte) { + event := new(WsCombinedTradeEvent) + err := json.Unmarshal(message, event) + if err != nil { + errHandler(err) + return + } + handler(event) + } + return wsServe(cfg, wsHandler, errHandler) +} + +// WsTradeEvent define websocket trade event +type WsTradeEvent struct { + Event string `json:"e"` + Time int64 `json:"E"` + Symbol string `json:"s"` + TradeID int64 `json:"t"` + Price string `json:"p"` + Quantity string `json:"q"` + BuyerOrderId int64 `json:"b"` + SellerOrderId int64 `json:"a"` + TradeTime int64 `json:"T"` + IsBuyerMaker bool `json:"m"` + Placeholder bool `json:"M"` // add this field to avoid case insensitive unmarshaling +} + +type WsCombinedTradeEvent struct { + Stream string `json:"stream"` + Data WsTradeEvent `json:"data"` +} + +// WsUserDataEvent define user data event +type WsUserDataEvent struct { + Event UserDataEventType `json:"e"` + Time int64 `json:"E"` + TransactionTime int64 `json:"T"` + AccountUpdateTime int64 `json:"u"` + AccountUpdate WsAccountUpdateList + BalanceUpdate WsBalanceUpdate + OrderUpdate WsOrderUpdate + OCOUpdate WsOCOUpdate +} + +type WsAccountUpdateList struct { + WsAccountUpdates []WsAccountUpdate `json:"B"` +} + +// WsAccountUpdate define account update +type WsAccountUpdate struct { + Asset string `json:"a"` + Free string `json:"f"` + Locked string `json:"l"` +} + +type WsBalanceUpdate struct { + Asset string `json:"a"` + Change string `json:"d"` +} + +type WsOrderUpdate struct { + Symbol string `json:"s"` + ClientOrderId string `json:"c"` + Side string `json:"S"` + Type string `json:"o"` + TimeInForce TimeInForceType `json:"f"` + Volume string `json:"q"` + Price string `json:"p"` + StopPrice string `json:"P"` + TrailingDelta int64 `json:"d"` // Trailing Delta + IceBergVolume string `json:"F"` + OrderListId int64 `json:"g"` // for OCO + OrigCustomOrderId string `json:"C"` // customized order ID for the original order + ExecutionType string `json:"x"` // execution type for this event NEW/TRADE... + Status string `json:"X"` // order status + RejectReason string `json:"r"` + Id int64 `json:"i"` // order id + LatestVolume string `json:"l"` // quantity for the latest trade + FilledVolume string `json:"z"` + LatestPrice string `json:"L"` // price for the latest trade + FeeAsset string `json:"N"` + FeeCost string `json:"n"` + TransactionTime int64 `json:"T"` + TradeId int64 `json:"t"` + IsInOrderBook bool `json:"w"` // is the order in the order book? + IsMaker bool `json:"m"` // is this order maker? + CreateTime int64 `json:"O"` + FilledQuoteVolume string `json:"Z"` // the quote volume that already filled + LatestQuoteVolume string `json:"Y"` // the quote volume for the latest trade + QuoteVolume string `json:"Q"` + TrailingTime int64 `json:"D"` // Trailing Time + StrategyId int64 `json:"j"` // Strategy ID + StrategyType int64 `json:"J"` // Strategy Type + WorkingTime int64 `json:"W"` // Working Time + SelfTradePreventionMode string `json:"V"` +} + +type WsOCOUpdate struct { + Symbol string `json:"s"` + OrderListId int64 `json:"g"` + ContingencyType string `json:"c"` + ListStatusType string `json:"l"` + ListOrderStatus string `json:"L"` + RejectReason string `json:"r"` + ClientOrderId string `json:"C"` // List Client Order ID + Orders WsOCOOrderList +} + +type WsOCOOrderList struct { + WsOCOOrders []WsOCOOrder `json:"O"` +} + +type WsOCOOrder struct { + Symbol string `json:"s"` + OrderId int64 `json:"i"` + ClientOrderId string `json:"c"` +} + +// WsUserDataHandler handle WsUserDataEvent +type WsUserDataHandler func(event *WsUserDataEvent) + +// WsUserDataServe serve user data handler with listen key +func WsUserDataServe(listenKey string, handler WsUserDataHandler, errHandler ErrHandler) (doneCh, stopCh chan struct{}, err error) { + endpoint := fmt.Sprintf("%s/%s", getWsEndpoint(), listenKey) + cfg := newWsConfig(endpoint) + wsHandler := func(message []byte) { + j, err := newJSON(message) + if err != nil { + errHandler(err) + return + } + + event := new(WsUserDataEvent) + + err = json.Unmarshal(message, event) + if err != nil { + errHandler(err) + return + } + + switch UserDataEventType(j.Get("e").MustString()) { + case UserDataEventTypeOutboundAccountPosition: + err = json.Unmarshal(message, &event.AccountUpdate) + if err != nil { + errHandler(err) + return + } + case UserDataEventTypeBalanceUpdate: + err = json.Unmarshal(message, &event.BalanceUpdate) + if err != nil { + errHandler(err) + return + } + case UserDataEventTypeExecutionReport: + err = json.Unmarshal(message, &event.OrderUpdate) + if err != nil { + errHandler(err) + return + } + // Unmarshal has case sensitive problem + event.TransactionTime = j.Get("T").MustInt64() + event.OrderUpdate.TransactionTime = j.Get("T").MustInt64() + event.OrderUpdate.Id = j.Get("i").MustInt64() + event.OrderUpdate.TradeId = j.Get("t").MustInt64() + event.OrderUpdate.FeeAsset = j.Get("N").MustString() + case UserDataEventTypeListStatus: + err = json.Unmarshal(message, &event.OCOUpdate) + if err != nil { + errHandler(err) + return + } + } + + handler(event) + } + return wsServe(cfg, wsHandler, errHandler) +} + +// WsMarketStatHandler handle websocket that push single market statistics for 24hr +type WsMarketStatHandler func(event *WsMarketStatEvent) + +// WsCombinedMarketStatServe is similar to WsMarketStatServe, but it handles multiple symbolx +func WsCombinedMarketStatServe(symbols []string, handler WsMarketStatHandler, errHandler ErrHandler) (doneCh, stopCh chan struct{}, err error) { + endpoint := getCombinedEndpoint() + for s := range symbols { + endpoint += fmt.Sprintf("%s@ticker", strings.ToLower(symbols[s])) + "/" + } + endpoint = endpoint[:len(endpoint)-1] + cfg := newWsConfig(endpoint) + + wsHandler := func(message []byte) { + j, err := newJSON(message) + if err != nil { + errHandler(err) + return + } + + stream := j.Get("stream").MustString() + data := j.Get("data").MustMap() + + symbol := strings.Split(stream, "@")[0] + + jsonData, _ := json.Marshal(data) + + event := new(WsMarketStatEvent) + err = json.Unmarshal(jsonData, event) + if err != nil { + errHandler(err) + return + } + + event.Symbol = strings.ToUpper(symbol) + + handler(event) + } + return wsServe(cfg, wsHandler, errHandler) +} + +// WsMarketStatServe serve websocket that push 24hr statistics for single market every second +func WsMarketStatServe(symbol string, handler WsMarketStatHandler, errHandler ErrHandler) (doneCh, stopCh chan struct{}, err error) { + endpoint := fmt.Sprintf("%s/%s@ticker", getWsEndpoint(), strings.ToLower(symbol)) + cfg := newWsConfig(endpoint) + wsHandler := func(message []byte) { + var event WsMarketStatEvent + err := json.Unmarshal(message, &event) + if err != nil { + errHandler(err) + return + } + handler(&event) + } + return wsServe(cfg, wsHandler, errHandler) +} + +// WsAllMarketsStatHandler handle websocket that push all markets statistics for 24hr +type WsAllMarketsStatHandler func(event WsAllMarketsStatEvent) + +// WsAllMarketsStatServe serve websocket that push 24hr statistics for all market every second +func WsAllMarketsStatServe(handler WsAllMarketsStatHandler, errHandler ErrHandler) (doneCh, stopCh chan struct{}, err error) { + endpoint := fmt.Sprintf("%s/!ticker@arr", getWsEndpoint()) + cfg := newWsConfig(endpoint) + wsHandler := func(message []byte) { + var event WsAllMarketsStatEvent + err := json.Unmarshal(message, &event) + if err != nil { + errHandler(err) + return + } + handler(event) + } + return wsServe(cfg, wsHandler, errHandler) +} + +// WsAllMarketsStatEvent define array of websocket market statistics events +type WsAllMarketsStatEvent []*WsMarketStatEvent + +// WsMarketStatEvent define websocket market statistics event +type WsMarketStatEvent struct { + Event string `json:"e"` + Time int64 `json:"E"` + Symbol string `json:"s"` + PriceChange string `json:"p"` + PriceChangePercent string `json:"P"` + WeightedAvgPrice string `json:"w"` + PrevClosePrice string `json:"x"` + LastPrice string `json:"c"` + CloseQty string `json:"Q"` + BidPrice string `json:"b"` + BidQty string `json:"B"` + AskPrice string `json:"a"` + AskQty string `json:"A"` + OpenPrice string `json:"o"` + HighPrice string `json:"h"` + LowPrice string `json:"l"` + BaseVolume string `json:"v"` + QuoteVolume string `json:"q"` + OpenTime int64 `json:"O"` + CloseTime int64 `json:"C"` + FirstID int64 `json:"F"` + LastID int64 `json:"L"` + Count int64 `json:"n"` +} + +// WsAllMiniMarketsStatServeHandler handle websocket that push all mini-ticker market statistics for 24hr +type WsAllMiniMarketsStatServeHandler func(event WsAllMiniMarketsStatEvent) + +// WsAllMiniMarketsStatServe serve websocket that push mini version of 24hr statistics for all market every second +func WsAllMiniMarketsStatServe(handler WsAllMiniMarketsStatServeHandler, errHandler ErrHandler) (doneCh, stopCh chan struct{}, err error) { + endpoint := fmt.Sprintf("%s/!miniTicker@arr", getWsEndpoint()) + cfg := newWsConfig(endpoint) + wsHandler := func(message []byte) { + var event WsAllMiniMarketsStatEvent + err := json.Unmarshal(message, &event) + if err != nil { + errHandler(err) + return + } + handler(event) + } + return wsServe(cfg, wsHandler, errHandler) +} + +// WsAllMiniMarketsStatEvent define array of websocket market mini-ticker statistics events +type WsAllMiniMarketsStatEvent []*WsMiniMarketsStatEvent + +// WsMiniMarketsStatEvent define websocket market mini-ticker statistics event +type WsMiniMarketsStatEvent struct { + Event string `json:"e"` + Time int64 `json:"E"` + Symbol string `json:"s"` + LastPrice string `json:"c"` + OpenPrice string `json:"o"` + HighPrice string `json:"h"` + LowPrice string `json:"l"` + BaseVolume string `json:"v"` + QuoteVolume string `json:"q"` +} + +// WsBookTickerEvent define websocket best book ticker event. +type WsBookTickerEvent struct { + UpdateID int64 `json:"u"` + Symbol string `json:"s"` + BestBidPrice string `json:"b"` + BestBidQty string `json:"B"` + BestAskPrice string `json:"a"` + BestAskQty string `json:"A"` +} + +type WsCombinedBookTickerEvent struct { + Data *WsBookTickerEvent `json:"data"` + Stream string `json:"stream"` +} + +// WsBookTickerHandler handle websocket that pushes updates to the best bid or ask price or quantity in real-time for a specified symbol. +type WsBookTickerHandler func(event *WsBookTickerEvent) + +// WsBookTickerServe serve websocket that pushes updates to the best bid or ask price or quantity in real-time for a specified symbol. +func WsBookTickerServe(symbol string, handler WsBookTickerHandler, errHandler ErrHandler) (doneCh, stopCh chan struct{}, err error) { + endpoint := fmt.Sprintf("%s/%s@bookTicker", getWsEndpoint(), strings.ToLower(symbol)) + cfg := newWsConfig(endpoint) + wsHandler := func(message []byte) { + event := new(WsBookTickerEvent) + err := json.Unmarshal(message, &event) + if err != nil { + errHandler(err) + return + } + handler(event) + } + return wsServe(cfg, wsHandler, errHandler) +} + +// WsCombinedBookTickerServe is similar to WsBookTickerServe, but it is for multiple symbols +func WsCombinedBookTickerServe(symbols []string, handler WsBookTickerHandler, errHandler ErrHandler) (doneCh, stopCh chan struct{}, err error) { + endpoint := baseCombinedMainURL + for _, s := range symbols { + endpoint += fmt.Sprintf("%s@bookTicker", strings.ToLower(s)) + "/" + } + endpoint = endpoint[:len(endpoint)-1] + cfg := newWsConfig(endpoint) + wsHandler := func(message []byte) { + event := new(WsCombinedBookTickerEvent) + err := json.Unmarshal(message, event) + if err != nil { + errHandler(err) + return + } + handler(event.Data) + } + return wsServe(cfg, wsHandler, errHandler) +} diff --git a/websocket_service_test.go b/websocket_service_test.go new file mode 100644 index 0000000..611d1bb --- /dev/null +++ b/websocket_service_test.go @@ -0,0 +1,711 @@ +package binance_connector + +import ( + "errors" + "testing" + + "github.com/stretchr/testify/suite" +) + +type websocketTestSuite struct { + baseTestSuite + origWsServe func(*WsConfig, WsHandler, ErrHandler) (chan struct{}, chan struct{}, error) + serveCount int +} + +func TestWebsocketService(t *testing.T) { + suite.Run(t, new(websocketTestSuite)) +} + +func (s *websocketTestSuite) SetupTest() { + s.origWsServe = wsServe +} + +func (s *websocketTestSuite) TearDownTest() { + wsServe = s.origWsServe + s.serveCount = 0 +} + +func (s *websocketTestSuite) mockWsServe(data []byte, err error) { + wsServe = func(cfg *WsConfig, handler WsHandler, errHandler ErrHandler) (doneCh, stopCh chan struct{}, innerErr error) { + s.serveCount++ + doneCh = make(chan struct{}) + stopCh = make(chan struct{}) + go func() { + <-stopCh + close(doneCh) + }() + handler(data) + if err != nil { + errHandler(err) + } + return doneCh, stopCh, nil + } +} + +func (s *websocketTestSuite) assertWsServe(count ...int) { + e := 1 + if len(count) > 0 { + e = count[0] + } + s.r().Equal(e, s.serveCount) +} + +func (s *websocketTestSuite) assertUserDataEvent(e, a *WsUserDataEvent) { + r := s.r() + r.Equal(e.Event, a.Event, "Event") + r.Equal(e.Time, a.Time, "Time") + r.Equal(e.TransactionTime, a.TransactionTime, "TransactionTime") + r.Equal(e.AccountUpdateTime, a.AccountUpdateTime, "AccountUpdateTime") + for i, e := range e.AccountUpdate.WsAccountUpdates { + a := a.AccountUpdate.WsAccountUpdates[i] + s.assertAccountUpdate(&e, &a) + } + s.assertOrderUpdate(&e.OrderUpdate, &a.OrderUpdate) + s.assertBalanceUpdate(&e.BalanceUpdate, &a.BalanceUpdate) +} + +func (s *websocketTestSuite) testWsUserDataServe(data []byte, expectedEvent *WsUserDataEvent) { + fakeErrMsg := "fake error" + s.mockWsServe(data, errors.New(fakeErrMsg)) + defer s.assertWsServe() + + doneC, stopC, err := WsUserDataServe("fakeListenKey", func(event *WsUserDataEvent) { + s.assertUserDataEvent(expectedEvent, event) + }, func(err error) { + s.r().EqualError(err, fakeErrMsg) + }) + + s.r().NoError(err) + stopC <- struct{}{} + <-doneC +} + +func (s *websocketTestSuite) assertAccountUpdate(e, a *WsAccountUpdate) { + r := s.r() + r.Equal(e.Asset, a.Asset) + r.Equal(e.Free, a.Free) + r.Equal(e.Locked, a.Locked) +} + +func (s *websocketTestSuite) assertOrderUpdate(e, a *WsOrderUpdate) { + r := s.r() + r.Equal(e.TransactionTime, a.TransactionTime, "TransactionTime") + r.Equal(e.Symbol, a.Symbol, "Symbol") + r.Equal(e.Volume, a.Volume, "Volume") + r.Equal(e.QuoteVolume, a.QuoteVolume, "QuoteVolume") + r.Equal(e.Price, a.Price, "Price") + r.Equal(e.Side, a.Side, "Side") + r.Equal(e.IsMaker, a.IsMaker, "IsMaker") + r.Equal(e.Status, a.Status, "Status") + r.Equal(e.TimeInForce, a.TimeInForce, "TimeInForce") + r.Equal(e.Type, a.Type, "Type") + r.Equal(e.CreateTime, a.CreateTime, "CreateTime") + r.Equal(e.Id, a.Id, "Id") + r.Equal(e.StopPrice, a.StopPrice, "StopPrice") + r.Equal(e.TradeId, a.TradeId, "TradeId") + r.Equal(e.ExecutionType, a.ExecutionType, "ExecutionType") + r.Equal(e.FeeAsset, a.FeeAsset, "FeeAsset") + r.Equal(e.FeeCost, a.FeeCost, "FeeCost") + r.Equal(e.FilledQuoteVolume, a.FilledQuoteVolume, "FilledQuoteVolume") + r.Equal(e.FilledVolume, a.FilledVolume, "FilledVolume") + r.Equal(e.IceBergVolume, a.IceBergVolume, "IceBergVolume") + r.Equal(e.IsInOrderBook, a.IsInOrderBook, "IsInOrderBook") + r.Equal(e.LatestPrice, a.LatestPrice, "LatestPrice") + r.Equal(e.OrderListId, a.OrderListId, "LatestQuoteVolume") + r.Equal(e.LatestQuoteVolume, a.LatestQuoteVolume, "LatestQuoteVolume") + r.Equal(e.LatestVolume, a.LatestVolume, "OrigCustomOrderId") + r.Equal(e.OrigCustomOrderId, a.OrigCustomOrderId, "OrigCustomOrderId") + r.Equal(e.RejectReason, a.RejectReason, "RejectReason") +} + +func (s *websocketTestSuite) assertBalanceUpdate(e, a *WsBalanceUpdate) { + r := s.r() + r.Equal(e.Asset, a.Asset) + r.Equal(e.Change, a.Change) +} + +func (s *websocketTestSuite) TestWsUserDataServeAccountUpdate() { + data := []byte(`{ + "e":"outboundAccountPosition", + "E":1629771130464, + "u":1629771130463, + "B":[ + { + "a":"LTC", + "f":"503.70000000", + "l":"0.00000000" + } + ] + }`) + expectedEvent := &WsUserDataEvent{ + Event: "outboundAccountPosition", + Time: 1629771130464, + AccountUpdateTime: 1629771130463, + AccountUpdate: WsAccountUpdateList{ + []WsAccountUpdate{ + { + "LTC", + "503.70000000", + "0.00000000", + }, + }, + }, + } + s.testWsUserDataServe(data, expectedEvent) +} + +func (s *websocketTestSuite) TestWsTradeServe() { + data := []byte(`{ + "e": "trade", + "E": 123456789, + "s": "BNBBTC", + "t": 12345, + "p": "0.001", + "q": "100", + "b": 88, + "a": 50, + "T": 123456785, + "m": true, + "M": true + }`) + fakeErrMsg := "fake error" + s.mockWsServe(data, errors.New(fakeErrMsg)) + defer s.assertWsServe() + + doneC, stopC, err := WsTradeServe("BNBBTC", func(event *WsTradeEvent) { + e := &WsTradeEvent{ + Event: "trade", + Time: 123456789, + Symbol: "BNBBTC", + TradeID: 12345, + Price: "0.001", + Quantity: "100", + BuyerOrderId: 88, + SellerOrderId: 50, + TradeTime: 123456785, + IsBuyerMaker: true, + } + s.assertWsTradeEventEqual(e, event) + }, func(err error) { + s.r().EqualError(err, fakeErrMsg) + }) + s.r().NoError(err) + stopC <- struct{}{} + <-doneC +} + +func (s *websocketTestSuite) assertWsTradeEventEqual(e, a *WsTradeEvent) { + r := s.r() + r.Equal(e.Event, a.Event, "Event") + r.Equal(e.Time, a.Time, "Time") + r.Equal(e.Symbol, a.Symbol, "Symbol") + r.Equal(e.TradeID, a.TradeID, "TradeID") + r.Equal(e.Price, a.Price, "Price") + r.Equal(e.Quantity, a.Quantity, "Quantity") + r.Equal(e.BuyerOrderId, a.BuyerOrderId, "BuyerOrderID") + r.Equal(e.SellerOrderId, a.SellerOrderId, "SellerOrderID") + r.Equal(e.TradeTime, a.TradeTime, "TradeTime") + r.Equal(e.IsBuyerMaker, a.IsBuyerMaker, "IsBuyerMaker") +} + +func (s *websocketTestSuite) TestWsAllMiniMarketsStatServe() { + data := []byte(`[{ + "e": "24hrMiniTicker", + "E": 1523658017154, + "s": "BNBBTC", + "c": "0.00175640", + "o": "0.00161200", + "h": "0.00176000", + "l": "0.00159370", + "v": "3479863.89000000", + "q": "5725.90587704" + },{ + "e": "24hrMiniTicker", + "E": 1523658017133, + "s": "BNBETH", + "c": "0.02827000", + "o": "0.02628100", + "h": "0.02830300", + "l": "0.02469400", + "v": "456266.78000000", + "q": "11873.11095682" + }]`) + fakeErrMsg := "fake error" + s.mockWsServe(data, errors.New(fakeErrMsg)) + defer s.assertWsServe() + + doneC, stopC, err := WsAllMiniMarketsStatServe(func(event WsAllMiniMarketsStatEvent) { + e := WsAllMiniMarketsStatEvent{ + &WsMiniMarketsStatEvent{ + Event: "24hrMiniTicker", + Time: 1523658017154, + Symbol: "BNBBTC", + LastPrice: "0.00175640", + OpenPrice: "0.00161200", + HighPrice: "0.00176000", + LowPrice: "0.00159370", + BaseVolume: "3479863.89000000", + QuoteVolume: "5725.90587704", + }, + &WsMiniMarketsStatEvent{ + Event: "24hrMiniTicker", + Time: 1523658017133, + Symbol: "BNBETH", + LastPrice: "0.02827000", + OpenPrice: "0.02628100", + HighPrice: "0.02830300", + LowPrice: "0.02469400", + BaseVolume: "456266.78000000", + QuoteVolume: "11873.11095682", + }, + } + s.assertWsAllMiniMarketsStatEventEqual(e, event) + }, func(err error) { + s.r().EqualError(err, fakeErrMsg) + }) + s.r().NoError(err) + stopC <- struct{}{} + <-doneC +} + +func (s *websocketTestSuite) assertWsAllMiniMarketsStatEventEqual(e, a WsAllMiniMarketsStatEvent) { + for i := range e { + s.assertWsMiniMarketsStatEventEqual(e[i], a[i]) + } +} + +func (s *websocketTestSuite) assertWsMiniMarketsStatEventEqual(e, a *WsMiniMarketsStatEvent) { + r := s.r() + r.Equal(e.Event, a.Event, "Event") + r.Equal(e.Time, a.Time, "Time") + r.Equal(e.Symbol, a.Symbol, "Symbol") + r.Equal(e.LastPrice, a.LastPrice, "LastPrice") + r.Equal(e.OpenPrice, a.OpenPrice, "OpenPrice") + r.Equal(e.HighPrice, a.HighPrice, "HighPrice") + r.Equal(e.LowPrice, a.LowPrice, "LowPrice") + r.Equal(e.BaseVolume, a.BaseVolume, "BaseVolume") + r.Equal(e.QuoteVolume, a.QuoteVolume, "QuoteVolume") +} + +func (s *websocketTestSuite) TestBookTickerServe() { + data := []byte(`{ + "u":17242169, + "s":"BTCUSD_200626", + "b":"9548.1", + "B":"52", + "a":"9548.5", + "A":"11" + }`) + fakeErrMsg := "fake error" + s.mockWsServe(data, errors.New(fakeErrMsg)) + defer s.assertWsServe() + + doneC, stopC, err := WsBookTickerServe("BTCUSD_200626", func(event *WsBookTickerEvent) { + e := &WsBookTickerEvent{ + UpdateID: 17242169, + Symbol: "BTCUSD_200626", + BestBidPrice: "9548.1", + BestBidQty: "52", + BestAskPrice: "9548.5", + BestAskQty: "11", + } + s.assertWsBookTickerEvent(e, event) + }, + func(err error) { + s.r().EqualError(err, fakeErrMsg) + }) + + s.r().NoError(err) + stopC <- struct{}{} + <-doneC +} + +func (s *websocketTestSuite) assertWsBookTickerEvent(e, a *WsBookTickerEvent) { + r := s.r() + r.Equal(e.UpdateID, a.UpdateID, "UpdateID") + r.Equal(e.Symbol, a.Symbol, "Symbol") + r.Equal(e.BestBidPrice, a.BestBidPrice, "BestBidPrice") + r.Equal(e.BestBidQty, a.BestBidQty, "BestBidQty") + r.Equal(e.BestAskPrice, a.BestAskPrice, "BestAskPrice") + r.Equal(e.BestAskQty, a.BestAskQty, "BestAskQty") +} + +func (s *websocketTestSuite) TestDepthServe() { + data := []byte(`{ + "e": "depthUpdate", + "E": 1499404630606, + "s": "ETHBTC", + "u": 7913455, + "U": 7913452, + "b": [ + [ + "0.10376590", + "59.15767010", + [] + ] + ], + "a": [ + [ + "0.10376586", + "159.15767010", + [] + ], + [ + "0.10383109", + "345.86845230", + [] + ], + [ + "0.10490700", + "0.00000000", + [] + ] + ] + }`) + fakeErrMsg := "fake error" + s.mockWsServe(data, errors.New(fakeErrMsg)) + defer s.assertWsServe() + + doneC, stopC, err := WsDepthServe("ETHBTC", func(event *WsDepthEvent) { + e := &WsDepthEvent{ + Event: "depthUpdate", + Time: 1499404630606, + Symbol: "ETHBTC", + LastUpdateID: 7913455, + FirstUpdateID: 7913452, + Bids: []Bid{ + { + Price: "0.10376590", + Quantity: "59.15767010", + }, + }, + Asks: []Ask{ + { + Price: "0.10376586", + Quantity: "159.15767010", + }, + { + Price: "0.10383109", + Quantity: "345.86845230", + }, + { + Price: "0.10490700", + Quantity: "0.00000000", + }, + }, + } + s.assertWsDepthEventEqual(e, event) + }, func(err error) { + s.r().EqualError(err, fakeErrMsg) + }) + s.r().NoError(err) + stopC <- struct{}{} + <-doneC +} + +func (s *websocketTestSuite) assertWsDepthEventEqual(e, a *WsDepthEvent) { + r := s.r() + r.Equal(e.Event, a.Event, "Event") + r.Equal(e.Time, a.Time, "Time") + r.Equal(e.Symbol, a.Symbol, "Symbol") + r.Equal(e.LastUpdateID, a.LastUpdateID, "UpdateID") + r.Equal(e.FirstUpdateID, a.FirstUpdateID, "FirstUpdateID") + for i := 0; i < len(e.Bids); i++ { + r.Equal(e.Bids[i].Price, a.Bids[i].Price, "Price") + r.Equal(e.Bids[i].Quantity, a.Bids[i].Quantity, "Quantity") + } + for i := 0; i < len(e.Asks); i++ { + r.Equal(e.Asks[i].Price, a.Asks[i].Price, "Price") + r.Equal(e.Asks[i].Quantity, a.Asks[i].Quantity, "Quantity") + } +} + +func (s *websocketTestSuite) TestKlineServe() { + data := []byte(`{ + "e": "kline", + "E": 1499404907056, + "s": "ETHBTC", + "k": { + "t": 1499404860000, + "T": 1499404919999, + "s": "ETHBTC", + "i": "1m", + "f": 77462, + "L": 77465, + "o": "0.10278577", + "c": "0.10278645", + "h": "0.10278712", + "l": "0.10278518", + "v": "17.47929838", + "n": 4, + "x": false, + "q": "1.79662878", + "V": "2.34879839", + "Q": "0.24142166", + "B": "13279784.01349473" + } + }`) + fakeErrMsg := "fake error" + s.mockWsServe(data, errors.New(fakeErrMsg)) + defer s.assertWsServe() + + doneC, stopC, err := WsKlineServe("ETHBTC", "1m", func(event *WsKlineEvent) { + e := &WsKlineEvent{ + Event: "kline", + Time: 1499404907056, + Symbol: "ETHBTC", + Kline: WsKline{ + StartTime: 1499404860000, + EndTime: 1499404919999, + Symbol: "ETHBTC", + Interval: "1m", + FirstTradeID: 77462, + LastTradeID: 77465, + Open: "0.10278577", + Close: "0.10278645", + High: "0.10278712", + Low: "0.10278518", + Volume: "17.47929838", + TradeNum: 4, + IsFinal: false, + QuoteVolume: "1.79662878", + ActiveBuyVolume: "2.34879839", + ActiveBuyQuoteVolume: "0.24142166", + }, + } + s.assertWsKlineEventEqual(e, event) + }, func(err error) { + s.r().EqualError(err, fakeErrMsg) + }) + s.r().NoError(err) + stopC <- struct{}{} + <-doneC +} + +func (s *websocketTestSuite) assertWsKlineEventEqual(e, a *WsKlineEvent) { + r := s.r() + r.Equal(e.Event, a.Event, "Event") + r.Equal(e.Time, a.Time, "Time") + r.Equal(e.Symbol, a.Symbol, "Symbol") + ek, ak := e.Kline, a.Kline + r.Equal(ek.StartTime, ak.StartTime, "StartTime") + r.Equal(ek.EndTime, ak.EndTime, "EndTime") + r.Equal(ek.Symbol, ak.Symbol, "Symbol") + r.Equal(ek.Interval, ak.Interval, "Interval") + r.Equal(ek.FirstTradeID, ak.FirstTradeID, "FirstTradeID") + r.Equal(ek.LastTradeID, ak.LastTradeID, "LastTradeID") + r.Equal(ek.Open, ak.Open, "Open") + r.Equal(ek.Close, ak.Close, "Close") + r.Equal(ek.High, ak.High, "High") + r.Equal(ek.Low, ak.Low, "Low") + r.Equal(ek.Volume, ak.Volume, "Volume") + r.Equal(ek.TradeNum, ak.TradeNum, "TradeNum") + r.Equal(ek.IsFinal, ak.IsFinal, "IsFinal") + r.Equal(ek.QuoteVolume, ak.QuoteVolume, "QuoteVolume") + r.Equal(ek.ActiveBuyVolume, ak.ActiveBuyVolume, "ActiveBuyVolume") + r.Equal(ek.ActiveBuyQuoteVolume, ak.ActiveBuyQuoteVolume, "ActiveBuyQuoteVolume") +} + +func (s *websocketTestSuite) TestWsAggTradeServe() { + data := []byte(`{ + "e": "aggTrade", + "E": 1499405254326, + "s": "ETHBTC", + "a": 70232, + "p": "0.10281118", + "q": "8.15632997", + "f": 77489, + "l": 77489, + "T": 1499405254324, + "m": false, + "M": true + }`) + fakeErrMsg := "fake error" + s.mockWsServe(data, errors.New(fakeErrMsg)) + defer s.assertWsServe() + + doneC, stopC, err := WsAggTradeServe("ETHBTC", func(event *WsAggTradeEvent) { + e := &WsAggTradeEvent{ + Event: "aggTrade", + Time: 1499405254326, + Symbol: "ETHBTC", + AggTradeID: 70232, + Price: "0.10281118", + Quantity: "8.15632997", + FirstBreakdownTradeID: 77489, + LastBreakdownTradeID: 77489, + TradeTime: 1499405254324, + IsBuyerMaker: false, + } + s.assertWsAggTradeEventEqual(e, event) + }, func(err error) { + s.r().EqualError(err, fakeErrMsg) + }) + s.r().NoError(err) + stopC <- struct{}{} + <-doneC +} + +func (s *websocketTestSuite) assertWsAggTradeEventEqual(e, a *WsAggTradeEvent) { + r := s.r() + r.Equal(e.Event, a.Event, "Event") + r.Equal(e.Time, a.Time, "Time") + r.Equal(e.Symbol, a.Symbol, "Symbol") + r.Equal(e.AggTradeID, a.AggTradeID, "AggTradeID") + r.Equal(e.Price, a.Price, "Price") + r.Equal(e.Quantity, a.Quantity, "Quantity") + r.Equal(e.FirstBreakdownTradeID, a.FirstBreakdownTradeID, "FirstBreakdownTradeID") + r.Equal(e.LastBreakdownTradeID, a.LastBreakdownTradeID, "LastBreakdownTradeID") + r.Equal(e.TradeTime, a.TradeTime, "TradeTime") + r.Equal(e.IsBuyerMaker, a.IsBuyerMaker, "IsBuyerMaker") +} + +func (s *websocketTestSuite) TestWsAllMarketsStatServe() { + data := []byte(`[{ + "e": "24hrTicker", + "E": 123456789, + "s": "BNBBTC", + "p": "0.0015", + "P": "250.00", + "w": "0.0018", + "x": "0.0009", + "c": "0.0025", + "Q": "10", + "b": "0.0024", + "B": "10", + "a": "0.0026", + "A": "100", + "o": "0.0010", + "h": "0.0026", + "l": "0.0010", + "v": "10000", + "q": "18", + "O": 0, + "C": 86400000, + "F": 0, + "L": 18150, + "n": 18151 + },{ + "e": "24hrTicker", + "E": 123456789, + "s": "ETHBTC", + "p": "0.0015", + "P": "250.00", + "w": "0.0018", + "x": "0.0009", + "c": "0.0025", + "Q": "10", + "b": "0.0024", + "B": "10", + "a": "0.0026", + "A": "100", + "o": "0.0010", + "h": "0.0026", + "l": "0.0010", + "v": "10000", + "q": "18", + "O": 0, + "C": 86400000, + "F": 0, + "L": 18150, + "n": 18151 + }]`) + fakeErrMsg := "fake error" + s.mockWsServe(data, errors.New(fakeErrMsg)) + defer s.assertWsServe() + + doneC, stopC, err := WsAllMarketsStatServe(func(event WsAllMarketsStatEvent) { + e := WsAllMarketsStatEvent{ + &WsMarketStatEvent{ + Event: "24hrTicker", + Time: 123456789, + Symbol: "BNBBTC", + PriceChange: "0.0015", + PriceChangePercent: "250.00", + WeightedAvgPrice: "0.0018", + PrevClosePrice: "0.0009", + LastPrice: "0.0025", + CloseQty: "10", + BidPrice: "0.0024", + BidQty: "10", + AskPrice: "0.0026", + AskQty: "100", + OpenPrice: "0.0010", + HighPrice: "0.0026", + LowPrice: "0.0010", + BaseVolume: "10000", + QuoteVolume: "18", + OpenTime: 0, + CloseTime: 86400000, + FirstID: 0, + LastID: 18150, + Count: 18151, + }, + &WsMarketStatEvent{ + Event: "24hrTicker", + Time: 123456789, + Symbol: "ETHBTC", + PriceChange: "0.0015", + PriceChangePercent: "250.00", + WeightedAvgPrice: "0.0018", + PrevClosePrice: "0.0009", + LastPrice: "0.0025", + CloseQty: "10", + BidPrice: "0.0024", + BidQty: "10", + AskPrice: "0.0026", + AskQty: "100", + OpenPrice: "0.0010", + HighPrice: "0.0026", + LowPrice: "0.0010", + BaseVolume: "10000", + QuoteVolume: "18", + OpenTime: 0, + CloseTime: 86400000, + FirstID: 0, + LastID: 18150, + Count: 18151, + }, + } + s.assertWsAllMarketsStatEventEqual(e, event) + }, func(err error) { + s.r().EqualError(err, fakeErrMsg) + }) + s.r().NoError(err) + stopC <- struct{}{} + <-doneC +} + +func (s *websocketTestSuite) assertWsAllMarketsStatEventEqual(e, a WsAllMarketsStatEvent) { + for i := range e { + s.assertWsMarketStatEventEqual(e[i], a[i]) + } +} + +func (s *websocketTestSuite) assertWsMarketStatEventEqual(e, a *WsMarketStatEvent) { + r := s.r() + r.Equal(e.Event, a.Event, "Event") + r.Equal(e.Time, a.Time, "Time") + r.Equal(e.Symbol, a.Symbol, "Symbol") + r.Equal(e.PriceChange, a.PriceChange, "PriceChange") + r.Equal(e.PriceChangePercent, a.PriceChangePercent, "PriceChangePercent") + r.Equal(e.WeightedAvgPrice, a.WeightedAvgPrice, "WeightedAvgPrice") + r.Equal(e.PrevClosePrice, a.PrevClosePrice, "PrevClosePrice") + r.Equal(e.LastPrice, a.LastPrice, "LastPrice") + r.Equal(e.CloseQty, a.CloseQty, "CloseQty") + r.Equal(e.BidPrice, a.BidPrice, "BidPrice") + r.Equal(e.BidQty, a.BidQty, "BidQty") + r.Equal(e.AskPrice, a.AskPrice, "AskPrice") + r.Equal(e.AskQty, a.AskQty, "AskQty") + r.Equal(e.OpenPrice, a.OpenPrice, "OpenPrice") + r.Equal(e.HighPrice, a.HighPrice, "HighPrice") + r.Equal(e.LowPrice, a.LowPrice, "LowPrice") + r.Equal(e.BaseVolume, a.BaseVolume, "BaseVolume") + r.Equal(e.QuoteVolume, a.QuoteVolume, "QuoteVolume") + r.Equal(e.OpenTime, a.OpenTime, "OpenTime") + r.Equal(e.CloseTime, a.CloseTime, "CloseTime") + r.Equal(e.FirstID, a.FirstID, "FirstID") + r.Equal(e.LastID, a.LastID, "LastID") + r.Equal(e.Symbol, a.Symbol, "Symbol") +}