mirror of
https://github.com/d0zingcat/gocryptotrader.git
synced 2026-05-19 15:10:05 +00:00
* Fixes issue where getorders could not work due to unset asset type in rpcserver.go. Adds test. Also adds start and end date to the cli. * A few fixes * lint * fixes oopsie that affected doopsie * Ensures dates are set for all open order implementations. Adds new filter to ensure orders without dates are returned rather than filtered. Fixes up Binance OpenOrders implementation. Adds some extra typeconverts for binance * Add updated time to Binance GetActiveOrders. Update rpcserver.go to only set the time if its not empty. Also addressed bad expected value * Actually fixes things this time * Improves recvWindow to process openOrders * Adds asset type to getOrder as well * Fixes tests * Adds missing date fields * Fixes default time, updates default errors * Default start to last month, instead of last year
1398 lines
48 KiB
Go
1398 lines
48 KiB
Go
package binance
|
|
|
|
import (
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"net/http"
|
|
"net/url"
|
|
"strconv"
|
|
"time"
|
|
|
|
"github.com/thrasher-corp/gocryptotrader/common"
|
|
"github.com/thrasher-corp/gocryptotrader/currency"
|
|
exchange "github.com/thrasher-corp/gocryptotrader/exchanges"
|
|
"github.com/thrasher-corp/gocryptotrader/exchanges/asset"
|
|
)
|
|
|
|
const (
|
|
|
|
// Unauth
|
|
cfuturesExchangeInfo = "/dapi/v1/exchangeInfo?"
|
|
cfuturesOrderbook = "/dapi/v1/depth?"
|
|
cfuturesRecentTrades = "/dapi/v1/trades?"
|
|
cfuturesHistoricalTrades = "/dapi/v1/historicalTrades"
|
|
cfuturesCompressedTrades = "/dapi/v1/aggTrades?"
|
|
cfuturesKlineData = "/dapi/v1/klines?"
|
|
cfuturesContinuousKline = "/dapi/v1/continuousKlines?"
|
|
cfuturesIndexKline = "/dapi/v1/indexPriceKlines?"
|
|
cfuturesMarkPriceKline = "/dapi/v1/markPriceKlines?"
|
|
cfuturesMarkPrice = "/dapi/v1/premiumIndex?"
|
|
cfuturesFundingRateHistory = "/dapi/v1/fundingRate?"
|
|
cfuturesTickerPriceStats = "/dapi/v1/ticker/24hr?"
|
|
cfuturesSymbolPriceTicker = "/dapi/v1/ticker/price?"
|
|
cfuturesSymbolOrderbook = "/dapi/v1/ticker/bookTicker?"
|
|
cfuturesLiquidationOrders = "/dapi/v1/allForceOrders?"
|
|
cfuturesOpenInterest = "/dapi/v1/openInterest?"
|
|
cfuturesOpenInterestStats = "/futures/data/openInterestHist?"
|
|
cfuturesTopAccountsRatio = "/futures/data/topLongShortAccountRatio?"
|
|
cfuturesTopPositionsRatio = "/futures/data/topLongShortPositionRatio?"
|
|
cfuturesLongShortRatio = "/futures/data/globalLongShortAccountRatio?"
|
|
cfuturesBuySellVolume = "/futures/data/takerBuySellVol?"
|
|
cfuturesBasis = "/futures/data/basis?"
|
|
|
|
// Auth
|
|
cfuturesOrder = "/dapi/v1/order"
|
|
cfuturesBatchOrder = "/dapi/v1/batchOrders"
|
|
cfuturesCancelAllOrders = "/dapi/v1/allOpenOrders"
|
|
cfuturesCountdownCancel = "/dapi/v1/countdownCancelAll"
|
|
cfuturesOpenOrder = "/dapi/v1/openOrder"
|
|
cfuturesAllOpenOrders = "/dapi/v1/openOrders"
|
|
cfuturesAllOrders = "/dapi/v1/allOrders"
|
|
cfuturesAccountBalance = "/dapi/v1/balance"
|
|
cfuturesAccountInfo = "/dapi/v1/account"
|
|
cfuturesChangeInitialLeverage = "/dapi/v1/leverage"
|
|
cfuturesChangeMarginType = "/dapi/v1/marginType"
|
|
cfuturesModifyMargin = "/dapi/v1/positionMargin"
|
|
cfuturesMarginChangeHistory = "/dapi/v1/positionMargin/history"
|
|
cfuturesPositionInfo = "/dapi/v1/positionRisk"
|
|
cfuturesAccountTradeList = "/dapi/v1/userTrades"
|
|
cfuturesIncomeHistory = "/dapi/v1/income"
|
|
cfuturesNotionalBracket = "/dapi/v1/leverageBracket"
|
|
cfuturesUsersForceOrders = "/dapi/v1/forceOrders"
|
|
cfuturesADLQuantile = "/dapi/v1/adlQuantile"
|
|
)
|
|
|
|
// FuturesExchangeInfo stores CoinMarginedFutures, data
|
|
func (b *Binance) FuturesExchangeInfo() (CExchangeInfo, error) {
|
|
var resp CExchangeInfo
|
|
return resp, b.SendHTTPRequest(exchange.RestCoinMargined, cfuturesExchangeInfo, limitDefault, &resp)
|
|
}
|
|
|
|
// GetFuturesOrderbook gets orderbook data for CoinMarginedFutures,
|
|
func (b *Binance) GetFuturesOrderbook(symbol currency.Pair, limit int64) (OrderBook, error) {
|
|
var resp OrderBook
|
|
var data OrderbookData
|
|
params := url.Values{}
|
|
symbolValue, err := b.FormatSymbol(symbol, asset.CoinMarginedFutures)
|
|
if err != nil {
|
|
return resp, err
|
|
}
|
|
params.Set("symbol", symbolValue)
|
|
if limit > 0 && limit <= 1000 {
|
|
params.Set("limit", strconv.FormatInt(limit, 10))
|
|
}
|
|
err = b.SendHTTPRequest(exchange.RestCoinMargined, cfuturesOrderbook+params.Encode(), limitDefault, &data)
|
|
if err != nil {
|
|
return resp, err
|
|
}
|
|
var price, quantity float64
|
|
for x := range data.Asks {
|
|
price, err = strconv.ParseFloat(data.Asks[x][0], 64)
|
|
if err != nil {
|
|
return resp, err
|
|
}
|
|
quantity, err = strconv.ParseFloat(data.Asks[x][1], 64)
|
|
if err != nil {
|
|
return resp, err
|
|
}
|
|
resp.Asks = append(resp.Asks, OrderbookItem{
|
|
Price: price,
|
|
Quantity: quantity,
|
|
})
|
|
}
|
|
for y := range data.Bids {
|
|
price, err = strconv.ParseFloat(data.Bids[y][0], 64)
|
|
if err != nil {
|
|
return resp, err
|
|
}
|
|
quantity, err = strconv.ParseFloat(data.Bids[y][1], 64)
|
|
if err != nil {
|
|
return resp, err
|
|
}
|
|
resp.Bids = append(resp.Bids, OrderbookItem{
|
|
Price: price,
|
|
Quantity: quantity,
|
|
})
|
|
}
|
|
return resp, nil
|
|
}
|
|
|
|
// GetFuturesPublicTrades gets recent public trades for CoinMarginedFutures,
|
|
func (b *Binance) GetFuturesPublicTrades(symbol currency.Pair, limit int64) ([]FuturesPublicTradesData, error) {
|
|
var resp []FuturesPublicTradesData
|
|
params := url.Values{}
|
|
symbolValue, err := b.FormatSymbol(symbol, asset.CoinMarginedFutures)
|
|
if err != nil {
|
|
return resp, err
|
|
}
|
|
params.Set("symbol", symbolValue)
|
|
if limit > 0 && limit <= 1000 {
|
|
params.Set("limit", strconv.FormatInt(limit, 10))
|
|
}
|
|
return resp, b.SendHTTPRequest(exchange.RestCoinMargined, cfuturesRecentTrades+params.Encode(), limitDefault, &resp)
|
|
}
|
|
|
|
// GetFuturesHistoricalTrades gets historical public trades for CoinMarginedFutures,
|
|
func (b *Binance) GetFuturesHistoricalTrades(symbol currency.Pair, fromID string, limit int64) ([]UPublicTradesData, error) {
|
|
var resp []UPublicTradesData
|
|
params := url.Values{}
|
|
symbolValue, err := b.FormatSymbol(symbol, asset.CoinMarginedFutures)
|
|
if err != nil {
|
|
return resp, err
|
|
}
|
|
params.Set("symbol", symbolValue)
|
|
if fromID != "" {
|
|
params.Set("fromID", fromID)
|
|
}
|
|
if limit > 0 && limit < 1000 {
|
|
params.Set("limit", strconv.FormatInt(limit, 10))
|
|
}
|
|
return resp, b.SendAuthHTTPRequest(exchange.RestCoinMargined, http.MethodGet, cfuturesHistoricalTrades, params, limitDefault, &resp)
|
|
}
|
|
|
|
// GetPastPublicTrades gets past public trades for CoinMarginedFutures,
|
|
func (b *Binance) GetPastPublicTrades(symbol currency.Pair, limit, fromID int64) ([]FuturesPublicTradesData, error) {
|
|
var resp []FuturesPublicTradesData
|
|
params := url.Values{}
|
|
symbolValue, err := b.FormatSymbol(symbol, asset.CoinMarginedFutures)
|
|
if err != nil {
|
|
return resp, err
|
|
}
|
|
params.Set("symbol", symbolValue)
|
|
if limit > 0 && limit <= 1000 {
|
|
params.Set("limit", strconv.FormatInt(limit, 10))
|
|
}
|
|
if fromID != 0 {
|
|
params.Set("fromID", strconv.FormatInt(fromID, 10))
|
|
}
|
|
return resp, b.SendHTTPRequest(exchange.RestCoinMargined, cfuturesRecentTrades+params.Encode(), limitDefault, &resp)
|
|
}
|
|
|
|
// GetFuturesAggregatedTradesList gets aggregated trades list for CoinMarginedFutures,
|
|
func (b *Binance) GetFuturesAggregatedTradesList(symbol currency.Pair, fromID, limit int64, startTime, endTime time.Time) ([]AggregatedTrade, error) {
|
|
var resp []AggregatedTrade
|
|
params := url.Values{}
|
|
symbolValue, err := b.FormatSymbol(symbol, asset.CoinMarginedFutures)
|
|
if err != nil {
|
|
return resp, err
|
|
}
|
|
params.Set("symbol", symbolValue)
|
|
if limit > 0 && limit <= 1000 {
|
|
params.Set("limit", strconv.FormatInt(limit, 10))
|
|
}
|
|
if fromID != 0 {
|
|
params.Set("fromID", strconv.FormatInt(fromID, 10))
|
|
}
|
|
if !startTime.IsZero() && !endTime.IsZero() {
|
|
if startTime.After(endTime) {
|
|
return resp, errors.New("startTime cannot be after endTime")
|
|
}
|
|
params.Set("start_time", strconv.FormatInt(startTime.Unix(), 10))
|
|
params.Set("end_time", strconv.FormatInt(endTime.Unix(), 10))
|
|
}
|
|
return resp, b.SendHTTPRequest(exchange.RestCoinMargined, cfuturesCompressedTrades+params.Encode(), limitDefault, &resp)
|
|
}
|
|
|
|
// GetIndexAndMarkPrice gets index and mark prices for CoinMarginedFutures,
|
|
func (b *Binance) GetIndexAndMarkPrice(symbol, pair string) ([]IndexMarkPrice, error) {
|
|
var resp []IndexMarkPrice
|
|
params := url.Values{}
|
|
if symbol != "" {
|
|
params.Set("symbol", symbol)
|
|
}
|
|
if pair != "" {
|
|
params.Set("pair", pair)
|
|
}
|
|
return resp, b.SendHTTPRequest(exchange.RestCoinMargined, cfuturesMarkPrice+params.Encode(), limitDefault, &resp)
|
|
}
|
|
|
|
// GetFuturesKlineData gets futures kline data for CoinMarginedFutures,
|
|
func (b *Binance) GetFuturesKlineData(symbol currency.Pair, interval string, limit int64, startTime, endTime time.Time) ([]FuturesCandleStick, error) {
|
|
var data [][10]interface{}
|
|
var resp []FuturesCandleStick
|
|
params := url.Values{}
|
|
if symbol != (currency.Pair{}) {
|
|
symbolValue, err := b.FormatSymbol(symbol, asset.CoinMarginedFutures)
|
|
if err != nil {
|
|
return resp, err
|
|
}
|
|
params.Set("symbol", symbolValue)
|
|
}
|
|
if limit > 0 && limit <= 1000 {
|
|
params.Set("limit", strconv.FormatInt(limit, 10))
|
|
}
|
|
if !common.StringDataCompare(validFuturesIntervals, interval) {
|
|
return resp, errors.New("invalid interval parsed")
|
|
}
|
|
params.Set("interval", interval)
|
|
if !startTime.IsZero() && !endTime.IsZero() {
|
|
if startTime.After(endTime) {
|
|
return resp, errors.New("startTime cannot be after endTime")
|
|
}
|
|
params.Set("start_time", strconv.FormatInt(startTime.Unix(), 10))
|
|
params.Set("end_time", strconv.FormatInt(endTime.Unix(), 10))
|
|
}
|
|
err := b.SendHTTPRequest(exchange.RestCoinMargined, cfuturesKlineData+params.Encode(), limitDefault, &data)
|
|
if err != nil {
|
|
return resp, err
|
|
}
|
|
var floatData float64
|
|
var strData string
|
|
var ok bool
|
|
var tempData FuturesCandleStick
|
|
for x := range data {
|
|
floatData, ok = data[x][0].(float64)
|
|
if !ok {
|
|
return resp, errors.New("type assertion failed for open time")
|
|
}
|
|
tempData.OpenTime = time.Unix(int64(floatData), 0)
|
|
strData, ok = data[x][1].(string)
|
|
if !ok {
|
|
return resp, errors.New("type assertion failed for open")
|
|
}
|
|
floatData, err = strconv.ParseFloat(strData, 64)
|
|
if err != nil {
|
|
return resp, err
|
|
}
|
|
tempData.Open = floatData
|
|
strData, ok = data[x][2].(string)
|
|
if !ok {
|
|
return resp, errors.New("type assertion failed for high")
|
|
}
|
|
floatData, err = strconv.ParseFloat(strData, 64)
|
|
if err != nil {
|
|
return resp, err
|
|
}
|
|
tempData.High = floatData
|
|
strData, ok = data[x][3].(string)
|
|
if !ok {
|
|
return resp, errors.New("type assertion failed for low")
|
|
}
|
|
floatData, err = strconv.ParseFloat(strData, 64)
|
|
if err != nil {
|
|
return resp, err
|
|
}
|
|
tempData.Low = floatData
|
|
strData, ok = data[x][4].(string)
|
|
if !ok {
|
|
return resp, errors.New("type assertion failed for close")
|
|
}
|
|
floatData, err = strconv.ParseFloat(strData, 64)
|
|
if err != nil {
|
|
return resp, err
|
|
}
|
|
tempData.Close = floatData
|
|
strData, ok = data[x][5].(string)
|
|
if !ok {
|
|
return resp, errors.New("type assertion failed for volume")
|
|
}
|
|
floatData, err = strconv.ParseFloat(strData, 64)
|
|
if err != nil {
|
|
return resp, err
|
|
}
|
|
tempData.Volume = floatData
|
|
floatData, ok = data[x][6].(float64)
|
|
if !ok {
|
|
return resp, errors.New("type assertion failed for close time")
|
|
}
|
|
tempData.CloseTime = time.Unix(int64(floatData), 0)
|
|
strData, ok = data[x][7].(string)
|
|
if !ok {
|
|
return resp, errors.New("type assertion failed for base asset volume")
|
|
}
|
|
floatData, err = strconv.ParseFloat(strData, 64)
|
|
if err != nil {
|
|
return resp, err
|
|
}
|
|
tempData.BaseAssetVolume = floatData
|
|
floatData, ok = data[x][8].(float64)
|
|
if !ok {
|
|
return resp, errors.New("type assertion failed for taker buy volume")
|
|
}
|
|
tempData.TakerBuyVolume = floatData
|
|
strData, ok = data[x][9].(string)
|
|
if !ok {
|
|
return resp, errors.New("type assertion failed for taker buy base asset volume")
|
|
}
|
|
floatData, err = strconv.ParseFloat(strData, 64)
|
|
if err != nil {
|
|
return resp, err
|
|
}
|
|
tempData.TakerBuyBaseAssetVolume = floatData
|
|
resp = append(resp, tempData)
|
|
}
|
|
return resp, nil
|
|
}
|
|
|
|
// GetContinuousKlineData gets continuous kline data
|
|
func (b *Binance) GetContinuousKlineData(pair, contractType, interval string, limit int64, startTime, endTime time.Time) ([]FuturesCandleStick, error) {
|
|
var data [][10]interface{}
|
|
var resp []FuturesCandleStick
|
|
params := url.Values{}
|
|
params.Set("pair", pair)
|
|
if !common.StringDataCompare(validContractType, contractType) {
|
|
return resp, errors.New("invalid contractType")
|
|
}
|
|
params.Set("contractType", contractType)
|
|
if limit > 0 && limit <= 1000 {
|
|
params.Set("limit", strconv.FormatInt(limit, 10))
|
|
}
|
|
if !common.StringDataCompare(validFuturesIntervals, interval) {
|
|
return resp, errors.New("invalid interval parsed")
|
|
}
|
|
params.Set("interval", interval)
|
|
if !startTime.IsZero() && !endTime.IsZero() {
|
|
if startTime.After(endTime) {
|
|
return resp, errors.New("startTime cannot be after endTime")
|
|
}
|
|
params.Set("start_time", strconv.FormatInt(startTime.Unix(), 10))
|
|
params.Set("end_time", strconv.FormatInt(endTime.Unix(), 10))
|
|
}
|
|
err := b.SendHTTPRequest(exchange.RestCoinMargined, cfuturesContinuousKline+params.Encode(), limitDefault, &data)
|
|
if err != nil {
|
|
return resp, err
|
|
}
|
|
var floatData float64
|
|
var strData string
|
|
var ok bool
|
|
var tempData FuturesCandleStick
|
|
for x := range data {
|
|
floatData, ok = data[x][0].(float64)
|
|
if !ok {
|
|
return resp, errors.New("type assertion failed for open time")
|
|
}
|
|
tempData.OpenTime = time.Unix(int64(floatData), 0)
|
|
strData, ok = data[x][1].(string)
|
|
if !ok {
|
|
return resp, errors.New("type assertion failed for open")
|
|
}
|
|
floatData, err = strconv.ParseFloat(strData, 64)
|
|
if err != nil {
|
|
return resp, err
|
|
}
|
|
tempData.Open = floatData
|
|
strData, ok = data[x][2].(string)
|
|
if !ok {
|
|
return resp, errors.New("type assertion failed for high")
|
|
}
|
|
floatData, err = strconv.ParseFloat(strData, 64)
|
|
if err != nil {
|
|
return resp, err
|
|
}
|
|
tempData.High = floatData
|
|
strData, ok = data[x][3].(string)
|
|
if !ok {
|
|
return resp, errors.New("type assertion failed for low")
|
|
}
|
|
floatData, err = strconv.ParseFloat(strData, 64)
|
|
if err != nil {
|
|
return resp, err
|
|
}
|
|
tempData.Low = floatData
|
|
strData, ok = data[x][4].(string)
|
|
if !ok {
|
|
return resp, errors.New("type assertion failed for close")
|
|
}
|
|
floatData, err = strconv.ParseFloat(strData, 64)
|
|
if err != nil {
|
|
return resp, err
|
|
}
|
|
tempData.Close = floatData
|
|
strData, ok = data[x][5].(string)
|
|
if !ok {
|
|
return resp, errors.New("type assertion failed for volume")
|
|
}
|
|
floatData, err = strconv.ParseFloat(strData, 64)
|
|
if err != nil {
|
|
return resp, err
|
|
}
|
|
tempData.Volume = floatData
|
|
floatData, ok = data[x][6].(float64)
|
|
if !ok {
|
|
return resp, errors.New("type assertion failed for close time")
|
|
}
|
|
tempData.CloseTime = time.Unix(int64(floatData), 0)
|
|
strData, ok = data[x][7].(string)
|
|
if !ok {
|
|
return resp, errors.New("type assertion failed for base asset volume")
|
|
}
|
|
floatData, err = strconv.ParseFloat(strData, 64)
|
|
if err != nil {
|
|
return resp, err
|
|
}
|
|
tempData.BaseAssetVolume = floatData
|
|
floatData, ok = data[x][8].(float64)
|
|
if !ok {
|
|
return resp, errors.New("type assertion failed for taker buy volume")
|
|
}
|
|
tempData.TakerBuyVolume = floatData
|
|
strData, ok = data[x][9].(string)
|
|
if !ok {
|
|
return resp, errors.New("type assertion failed for taker buy base asset volume")
|
|
}
|
|
floatData, err = strconv.ParseFloat(strData, 64)
|
|
if err != nil {
|
|
return resp, err
|
|
}
|
|
tempData.TakerBuyBaseAssetVolume = floatData
|
|
resp = append(resp, tempData)
|
|
}
|
|
return resp, nil
|
|
}
|
|
|
|
// GetIndexPriceKlines gets continuous kline data
|
|
func (b *Binance) GetIndexPriceKlines(pair, interval string, limit int64, startTime, endTime time.Time) ([]FuturesCandleStick, error) {
|
|
var data [][10]interface{}
|
|
var resp []FuturesCandleStick
|
|
params := url.Values{}
|
|
params.Set("pair", pair)
|
|
if limit > 0 && limit <= 1000 {
|
|
params.Set("limit", strconv.FormatInt(limit, 10))
|
|
}
|
|
if !common.StringDataCompare(validFuturesIntervals, interval) {
|
|
return resp, errors.New("invalid interval parsed")
|
|
}
|
|
params.Set("interval", interval)
|
|
if !startTime.IsZero() && !endTime.IsZero() {
|
|
if startTime.After(endTime) {
|
|
return resp, errors.New("startTime cannot be after endTime")
|
|
}
|
|
params.Set("start_time", strconv.FormatInt(startTime.Unix(), 10))
|
|
params.Set("end_time", strconv.FormatInt(endTime.Unix(), 10))
|
|
}
|
|
err := b.SendHTTPRequest(exchange.RestCoinMargined, cfuturesIndexKline+params.Encode(), limitDefault, &data)
|
|
if err != nil {
|
|
return resp, err
|
|
}
|
|
var floatData float64
|
|
var strData string
|
|
var ok bool
|
|
var tempData FuturesCandleStick
|
|
for x := range data {
|
|
floatData, ok = data[x][0].(float64)
|
|
if !ok {
|
|
return resp, errors.New("type assertion failed for open time")
|
|
}
|
|
tempData.OpenTime = time.Unix(int64(floatData), 0)
|
|
strData, ok = data[x][1].(string)
|
|
if !ok {
|
|
return resp, errors.New("type assertion failed for open")
|
|
}
|
|
floatData, err = strconv.ParseFloat(strData, 64)
|
|
if err != nil {
|
|
return resp, err
|
|
}
|
|
tempData.Open = floatData
|
|
strData, ok = data[x][2].(string)
|
|
if !ok {
|
|
return resp, errors.New("type assertion failed for high")
|
|
}
|
|
floatData, err = strconv.ParseFloat(strData, 64)
|
|
if err != nil {
|
|
return resp, err
|
|
}
|
|
tempData.High = floatData
|
|
strData, ok = data[x][3].(string)
|
|
if !ok {
|
|
return resp, errors.New("type assertion failed for low")
|
|
}
|
|
floatData, err = strconv.ParseFloat(strData, 64)
|
|
if err != nil {
|
|
return resp, err
|
|
}
|
|
tempData.Low = floatData
|
|
strData, ok = data[x][4].(string)
|
|
if !ok {
|
|
return resp, errors.New("type assertion failed for close")
|
|
}
|
|
floatData, err = strconv.ParseFloat(strData, 64)
|
|
if err != nil {
|
|
return resp, err
|
|
}
|
|
tempData.Close = floatData
|
|
strData, ok = data[x][5].(string)
|
|
if !ok {
|
|
return resp, errors.New("type assertion failed for volume")
|
|
}
|
|
floatData, err = strconv.ParseFloat(strData, 64)
|
|
if err != nil {
|
|
return resp, err
|
|
}
|
|
tempData.Volume = floatData
|
|
floatData, ok = data[x][6].(float64)
|
|
if !ok {
|
|
return resp, errors.New("type assertion failed for close time")
|
|
}
|
|
tempData.CloseTime = time.Unix(int64(floatData), 0)
|
|
strData, ok = data[x][7].(string)
|
|
if !ok {
|
|
return resp, errors.New("type assertion failed for base asset volume")
|
|
}
|
|
floatData, err = strconv.ParseFloat(strData, 64)
|
|
if err != nil {
|
|
return resp, err
|
|
}
|
|
tempData.BaseAssetVolume = floatData
|
|
floatData, ok = data[x][8].(float64)
|
|
if !ok {
|
|
return resp, errors.New("type assertion failed for taker buy volume")
|
|
}
|
|
tempData.TakerBuyVolume = floatData
|
|
strData, ok = data[x][9].(string)
|
|
if !ok {
|
|
return resp, errors.New("type assertion failed for taker buy base asset volume")
|
|
}
|
|
floatData, err = strconv.ParseFloat(strData, 64)
|
|
if err != nil {
|
|
return resp, err
|
|
}
|
|
tempData.TakerBuyBaseAssetVolume = floatData
|
|
resp = append(resp, tempData)
|
|
}
|
|
return resp, nil
|
|
}
|
|
|
|
// GetMarkPriceKline gets mark price kline data
|
|
func (b *Binance) GetMarkPriceKline(symbol currency.Pair, interval string, limit int64, startTime, endTime time.Time) ([]FuturesCandleStick, error) {
|
|
var data [][10]interface{}
|
|
var resp []FuturesCandleStick
|
|
params := url.Values{}
|
|
symbolValue, err := b.FormatSymbol(symbol, asset.CoinMarginedFutures)
|
|
if err != nil {
|
|
return resp, err
|
|
}
|
|
params.Set("symbol", symbolValue)
|
|
if limit > 0 && limit <= 1000 {
|
|
params.Set("limit", strconv.FormatInt(limit, 10))
|
|
}
|
|
if !common.StringDataCompare(validFuturesIntervals, interval) {
|
|
return resp, errors.New("invalid interval parsed")
|
|
}
|
|
params.Set("interval", interval)
|
|
if !startTime.IsZero() && !endTime.IsZero() {
|
|
if startTime.After(endTime) {
|
|
return resp, errors.New("startTime cannot be after endTime")
|
|
}
|
|
params.Set("start_time", strconv.FormatInt(startTime.Unix(), 10))
|
|
params.Set("end_time", strconv.FormatInt(endTime.Unix(), 10))
|
|
}
|
|
err = b.SendHTTPRequest(exchange.RestCoinMargined, cfuturesMarkPriceKline+params.Encode(), limitDefault, &data)
|
|
if err != nil {
|
|
return resp, err
|
|
}
|
|
var floatData float64
|
|
var strData string
|
|
var ok bool
|
|
var tempData FuturesCandleStick
|
|
for x := range data {
|
|
floatData, ok = data[x][0].(float64)
|
|
if !ok {
|
|
return resp, errors.New("type assertion failed for open time")
|
|
}
|
|
tempData.OpenTime = time.Unix(int64(floatData), 0)
|
|
strData, ok = data[x][1].(string)
|
|
if !ok {
|
|
return resp, errors.New("type assertion failed for open")
|
|
}
|
|
floatData, err = strconv.ParseFloat(strData, 64)
|
|
if err != nil {
|
|
return resp, err
|
|
}
|
|
tempData.Open = floatData
|
|
strData, ok = data[x][2].(string)
|
|
if !ok {
|
|
return resp, errors.New("type assertion failed for high")
|
|
}
|
|
floatData, err = strconv.ParseFloat(strData, 64)
|
|
if err != nil {
|
|
return resp, err
|
|
}
|
|
tempData.High = floatData
|
|
strData, ok = data[x][3].(string)
|
|
if !ok {
|
|
return resp, errors.New("type assertion failed for low")
|
|
}
|
|
floatData, err = strconv.ParseFloat(strData, 64)
|
|
if err != nil {
|
|
return resp, err
|
|
}
|
|
tempData.Low = floatData
|
|
strData, ok = data[x][4].(string)
|
|
if !ok {
|
|
return resp, errors.New("type assertion failed for close")
|
|
}
|
|
floatData, err = strconv.ParseFloat(strData, 64)
|
|
if err != nil {
|
|
return resp, err
|
|
}
|
|
tempData.Close = floatData
|
|
strData, ok = data[x][5].(string)
|
|
if !ok {
|
|
return resp, errors.New("type assertion failed for volume")
|
|
}
|
|
floatData, err = strconv.ParseFloat(strData, 64)
|
|
if err != nil {
|
|
return resp, err
|
|
}
|
|
tempData.Volume = floatData
|
|
floatData, ok = data[x][6].(float64)
|
|
if !ok {
|
|
return resp, errors.New("type assertion failed for close time")
|
|
}
|
|
tempData.CloseTime = time.Unix(int64(floatData), 0)
|
|
strData, ok = data[x][7].(string)
|
|
if !ok {
|
|
return resp, errors.New("type assertion failed for base asset volume")
|
|
}
|
|
floatData, err = strconv.ParseFloat(strData, 64)
|
|
if err != nil {
|
|
return resp, err
|
|
}
|
|
tempData.BaseAssetVolume = floatData
|
|
floatData, ok = data[x][8].(float64)
|
|
if !ok {
|
|
return resp, errors.New("type assertion failed for taker buy volume")
|
|
}
|
|
tempData.TakerBuyVolume = floatData
|
|
strData, ok = data[x][9].(string)
|
|
if !ok {
|
|
return resp, errors.New("type assertion failed for taker buy base asset volume")
|
|
}
|
|
floatData, err = strconv.ParseFloat(strData, 64)
|
|
if err != nil {
|
|
return resp, err
|
|
}
|
|
tempData.TakerBuyBaseAssetVolume = floatData
|
|
resp = append(resp, tempData)
|
|
}
|
|
return resp, nil
|
|
}
|
|
|
|
// GetFuturesSwapTickerChangeStats gets 24hr ticker change stats for CoinMarginedFutures,
|
|
func (b *Binance) GetFuturesSwapTickerChangeStats(symbol currency.Pair, pair string) ([]PriceChangeStats, error) {
|
|
var resp []PriceChangeStats
|
|
params := url.Values{}
|
|
if symbol != (currency.Pair{}) {
|
|
symbolValue, err := b.FormatSymbol(symbol, asset.CoinMarginedFutures)
|
|
if err != nil {
|
|
return resp, err
|
|
}
|
|
params.Set("symbol", symbolValue)
|
|
}
|
|
if pair != "" {
|
|
params.Set("pair", pair)
|
|
}
|
|
return resp, b.SendHTTPRequest(exchange.RestCoinMargined, cfuturesTickerPriceStats+params.Encode(), limitDefault, &resp)
|
|
}
|
|
|
|
// FuturesGetFundingHistory gets funding history for CoinMarginedFutures,
|
|
func (b *Binance) FuturesGetFundingHistory(symbol currency.Pair, limit int64, startTime, endTime time.Time) ([]FundingRateHistory, error) {
|
|
var resp []FundingRateHistory
|
|
params := url.Values{}
|
|
if symbol != (currency.Pair{}) {
|
|
symbolValue, err := b.FormatSymbol(symbol, asset.CoinMarginedFutures)
|
|
if err != nil {
|
|
return resp, err
|
|
}
|
|
params.Set("symbol", symbolValue)
|
|
}
|
|
if limit > 0 && limit < 1000 {
|
|
params.Set("limit", strconv.FormatInt(limit, 10))
|
|
}
|
|
if !startTime.IsZero() && !endTime.IsZero() {
|
|
if startTime.After(endTime) {
|
|
return resp, errors.New("startTime cannot be after endTime")
|
|
}
|
|
params.Set("start_time", strconv.FormatInt(startTime.Unix(), 10))
|
|
params.Set("end_time", strconv.FormatInt(endTime.Unix(), 10))
|
|
}
|
|
return resp, b.SendHTTPRequest(exchange.RestCoinMargined, cfuturesFundingRateHistory+params.Encode(), limitDefault, &resp)
|
|
}
|
|
|
|
// GetFuturesSymbolPriceTicker gets price ticker for symbol
|
|
func (b *Binance) GetFuturesSymbolPriceTicker(symbol currency.Pair, pair string) ([]SymbolPriceTicker, error) {
|
|
var resp []SymbolPriceTicker
|
|
params := url.Values{}
|
|
if symbol != (currency.Pair{}) {
|
|
symbolValue, err := b.FormatSymbol(symbol, asset.CoinMarginedFutures)
|
|
if err != nil {
|
|
return resp, err
|
|
}
|
|
params.Set("symbol", symbolValue)
|
|
}
|
|
if pair != "" {
|
|
params.Set("pair", pair)
|
|
}
|
|
return resp, b.SendHTTPRequest(exchange.RestCoinMargined, cfuturesSymbolPriceTicker+params.Encode(), limitDefault, &resp)
|
|
}
|
|
|
|
// GetFuturesOrderbookTicker gets orderbook ticker for symbol
|
|
func (b *Binance) GetFuturesOrderbookTicker(symbol currency.Pair, pair string) ([]SymbolOrderBookTicker, error) {
|
|
var resp []SymbolOrderBookTicker
|
|
params := url.Values{}
|
|
if symbol != (currency.Pair{}) {
|
|
symbolValue, err := b.FormatSymbol(symbol, asset.CoinMarginedFutures)
|
|
if err != nil {
|
|
return resp, err
|
|
}
|
|
params.Set("symbol", symbolValue)
|
|
}
|
|
if pair != "" {
|
|
params.Set("pair", pair)
|
|
}
|
|
return resp, b.SendHTTPRequest(exchange.RestCoinMargined, cfuturesSymbolOrderbook+params.Encode(), limitDefault, &resp)
|
|
}
|
|
|
|
// GetFuturesLiquidationOrders gets orderbook ticker for symbol
|
|
func (b *Binance) GetFuturesLiquidationOrders(symbol currency.Pair, pair string, limit int64, startTime, endTime time.Time) ([]AllLiquidationOrders, error) {
|
|
var resp []AllLiquidationOrders
|
|
params := url.Values{}
|
|
if symbol != (currency.Pair{}) {
|
|
symbolValue, err := b.FormatSymbol(symbol, asset.CoinMarginedFutures)
|
|
if err != nil {
|
|
return resp, err
|
|
}
|
|
params.Set("symbol", symbolValue)
|
|
}
|
|
if pair != "" {
|
|
params.Set("pair", pair)
|
|
}
|
|
if limit > 0 && limit <= 1000 {
|
|
params.Set("limit", strconv.FormatInt(limit, 10))
|
|
}
|
|
if !startTime.IsZero() && !endTime.IsZero() {
|
|
if startTime.After(endTime) {
|
|
return resp, errors.New("startTime cannot be after endTime")
|
|
}
|
|
params.Set("start_time", strconv.FormatInt(startTime.Unix(), 10))
|
|
params.Set("end_time", strconv.FormatInt(endTime.Unix(), 10))
|
|
}
|
|
return resp, b.SendHTTPRequest(exchange.RestCoinMargined, cfuturesLiquidationOrders+params.Encode(), limitDefault, &resp)
|
|
}
|
|
|
|
// GetOpenInterest gets open interest data for a symbol
|
|
func (b *Binance) GetOpenInterest(symbol currency.Pair) (OpenInterestData, error) {
|
|
var resp OpenInterestData
|
|
params := url.Values{}
|
|
symbolValue, err := b.FormatSymbol(symbol, asset.CoinMarginedFutures)
|
|
if err != nil {
|
|
return resp, err
|
|
}
|
|
params.Set("symbol", symbolValue)
|
|
return resp, b.SendHTTPRequest(exchange.RestCoinMargined, cfuturesOpenInterest+params.Encode(), limitDefault, &resp)
|
|
}
|
|
|
|
// GetOpenInterestStats gets open interest stats for a symbol
|
|
func (b *Binance) GetOpenInterestStats(pair, contractType, period string, limit int64, startTime, endTime time.Time) ([]OpenInterestStats, error) {
|
|
var resp []OpenInterestStats
|
|
params := url.Values{}
|
|
if pair != "" {
|
|
params.Set("pair", pair)
|
|
}
|
|
if !common.StringDataCompare(validContractType, contractType) {
|
|
return resp, errors.New("invalid contractType")
|
|
}
|
|
params.Set("contractType", contractType)
|
|
if !common.StringDataCompare(validFuturesIntervals, period) {
|
|
return resp, errors.New("invalid period")
|
|
}
|
|
params.Set("period", period)
|
|
if limit > 0 && limit <= 1000 {
|
|
params.Set("limit", strconv.FormatInt(limit, 10))
|
|
}
|
|
if !startTime.IsZero() && !endTime.IsZero() {
|
|
if startTime.After(endTime) {
|
|
return resp, errors.New("startTime cannot be after endTime")
|
|
}
|
|
params.Set("start_time", strconv.FormatInt(startTime.Unix(), 10))
|
|
params.Set("end_time", strconv.FormatInt(endTime.Unix(), 10))
|
|
}
|
|
return resp, b.SendHTTPRequest(exchange.RestCoinMargined, cfuturesOpenInterestStats+params.Encode(), limitDefault, &resp)
|
|
}
|
|
|
|
// GetTraderFuturesAccountRatio gets a traders futures account long/short ratio
|
|
func (b *Binance) GetTraderFuturesAccountRatio(pair, period string, limit int64, startTime, endTime time.Time) ([]TopTraderAccountRatio, error) {
|
|
var resp []TopTraderAccountRatio
|
|
params := url.Values{}
|
|
params.Set("pair", pair)
|
|
if !common.StringDataCompare(validFuturesIntervals, period) {
|
|
return resp, errors.New("invalid period")
|
|
}
|
|
params.Set("period", period)
|
|
if limit > 0 && limit <= 1000 {
|
|
params.Set("limit", strconv.FormatInt(limit, 10))
|
|
}
|
|
if !startTime.IsZero() && !endTime.IsZero() {
|
|
if startTime.After(endTime) {
|
|
return resp, errors.New("startTime cannot be after endTime")
|
|
}
|
|
params.Set("start_time", strconv.FormatInt(startTime.Unix(), 10))
|
|
params.Set("end_time", strconv.FormatInt(endTime.Unix(), 10))
|
|
}
|
|
return resp, b.SendHTTPRequest(exchange.RestCoinMargined, cfuturesTopAccountsRatio+params.Encode(), limitDefault, &resp)
|
|
}
|
|
|
|
// GetTraderFuturesPositionsRatio gets a traders futures positions' long/short ratio
|
|
func (b *Binance) GetTraderFuturesPositionsRatio(pair, period string, limit int64, startTime, endTime time.Time) ([]TopTraderPositionRatio, error) {
|
|
var resp []TopTraderPositionRatio
|
|
params := url.Values{}
|
|
params.Set("pair", pair)
|
|
if !common.StringDataCompare(validFuturesIntervals, period) {
|
|
return resp, errors.New("invalid period")
|
|
}
|
|
params.Set("period", period)
|
|
if limit > 0 && limit <= 1000 {
|
|
params.Set("limit", strconv.FormatInt(limit, 10))
|
|
}
|
|
if !startTime.IsZero() && !endTime.IsZero() {
|
|
if startTime.After(endTime) {
|
|
return resp, errors.New("startTime cannot be after endTime")
|
|
}
|
|
params.Set("start_time", strconv.FormatInt(startTime.Unix(), 10))
|
|
params.Set("end_time", strconv.FormatInt(endTime.Unix(), 10))
|
|
}
|
|
return resp, b.SendHTTPRequest(exchange.RestCoinMargined, cfuturesTopPositionsRatio+params.Encode(), limitDefault, &resp)
|
|
}
|
|
|
|
// GetMarketRatio gets global long/short ratio
|
|
func (b *Binance) GetMarketRatio(pair, period string, limit int64, startTime, endTime time.Time) ([]TopTraderPositionRatio, error) {
|
|
var resp []TopTraderPositionRatio
|
|
params := url.Values{}
|
|
params.Set("pair", pair)
|
|
if !common.StringDataCompare(validFuturesIntervals, period) {
|
|
return resp, errors.New("invalid period")
|
|
}
|
|
params.Set("period", period)
|
|
if limit > 0 && limit <= 1000 {
|
|
params.Set("limit", strconv.FormatInt(limit, 10))
|
|
}
|
|
if !startTime.IsZero() && !endTime.IsZero() {
|
|
if startTime.After(endTime) {
|
|
return resp, errors.New("startTime cannot be after endTime")
|
|
}
|
|
params.Set("start_time", strconv.FormatInt(startTime.Unix(), 10))
|
|
params.Set("end_time", strconv.FormatInt(endTime.Unix(), 10))
|
|
}
|
|
return resp, b.SendHTTPRequest(exchange.RestCoinMargined, cfuturesLongShortRatio+params.Encode(), limitDefault, &resp)
|
|
}
|
|
|
|
// GetFuturesTakerVolume gets futures taker buy/sell volumes
|
|
func (b *Binance) GetFuturesTakerVolume(pair, contractType, period string, limit int64, startTime, endTime time.Time) ([]TakerBuySellVolume, error) {
|
|
var resp []TakerBuySellVolume
|
|
params := url.Values{}
|
|
params.Set("pair", pair)
|
|
if !common.StringDataCompare(validContractType, contractType) {
|
|
return resp, errors.New("invalid contractType")
|
|
}
|
|
params.Set("contractType", contractType)
|
|
if limit > 0 && limit <= 1000 {
|
|
params.Set("limit", strconv.FormatInt(limit, 10))
|
|
}
|
|
if !common.StringDataCompare(validFuturesIntervals, period) {
|
|
return resp, errors.New("invalid period parsed")
|
|
}
|
|
params.Set("period", period)
|
|
if !startTime.IsZero() && !endTime.IsZero() {
|
|
if startTime.After(endTime) {
|
|
return resp, errors.New("startTime cannot be after endTime")
|
|
}
|
|
params.Set("start_time", strconv.FormatInt(startTime.Unix(), 10))
|
|
params.Set("end_time", strconv.FormatInt(endTime.Unix(), 10))
|
|
}
|
|
return resp, b.SendHTTPRequest(exchange.RestCoinMargined, cfuturesBuySellVolume+params.Encode(), limitDefault, &resp)
|
|
}
|
|
|
|
// GetFuturesBasisData gets futures basis data
|
|
func (b *Binance) GetFuturesBasisData(pair, contractType, period string, limit int64, startTime, endTime time.Time) ([]FuturesBasisData, error) {
|
|
var resp []FuturesBasisData
|
|
params := url.Values{}
|
|
params.Set("pair", pair)
|
|
if !common.StringDataCompare(validContractType, contractType) {
|
|
return resp, errors.New("invalid contractType")
|
|
}
|
|
params.Set("contractType", contractType)
|
|
if limit > 0 && limit <= 1000 {
|
|
params.Set("limit", strconv.FormatInt(limit, 10))
|
|
}
|
|
if !common.StringDataCompare(validFuturesIntervals, period) {
|
|
return resp, errors.New("invalid period parsed")
|
|
}
|
|
params.Set("period", period)
|
|
if !startTime.IsZero() && !endTime.IsZero() {
|
|
if startTime.After(endTime) {
|
|
return resp, errors.New("startTime cannot be after endTime")
|
|
}
|
|
params.Set("start_time", strconv.FormatInt(startTime.Unix(), 10))
|
|
params.Set("end_time", strconv.FormatInt(endTime.Unix(), 10))
|
|
}
|
|
return resp, b.SendHTTPRequest(exchange.RestCoinMargined, cfuturesBasis+params.Encode(), limitDefault, &resp)
|
|
}
|
|
|
|
// FuturesNewOrder sends a new futures order to the exchange
|
|
func (b *Binance) FuturesNewOrder(symbol currency.Pair, side, positionSide, orderType, timeInForce,
|
|
newClientOrderID, closePosition, workingType, newOrderRespType string,
|
|
quantity, price, stopPrice, activationPrice, callbackRate float64, reduceOnly bool) (FuturesOrderPlaceData, error) {
|
|
var resp FuturesOrderPlaceData
|
|
params := url.Values{}
|
|
symbolValue, err := b.FormatSymbol(symbol, asset.CoinMarginedFutures)
|
|
if err != nil {
|
|
return resp, err
|
|
}
|
|
params.Set("symbol", symbolValue)
|
|
params.Set("side", side)
|
|
if positionSide != "" {
|
|
if !common.StringDataCompare(validPositionSide, positionSide) {
|
|
return resp, errors.New("invalid positionSide")
|
|
}
|
|
params.Set("positionSide", positionSide)
|
|
}
|
|
params.Set("type", orderType)
|
|
params.Set("timeInForce", timeInForce)
|
|
if reduceOnly {
|
|
params.Set("reduceOnly", "true")
|
|
}
|
|
if newClientOrderID != "" {
|
|
params.Set("newClientOrderID", newClientOrderID)
|
|
}
|
|
if closePosition != "" {
|
|
params.Set("closePosition", closePosition)
|
|
}
|
|
if workingType != "" {
|
|
if !common.StringDataCompare(validWorkingType, workingType) {
|
|
return resp, errors.New("invalid workingType")
|
|
}
|
|
params.Set("workingType", workingType)
|
|
}
|
|
if newOrderRespType != "" {
|
|
if !common.StringDataCompare(validNewOrderRespType, newOrderRespType) {
|
|
return resp, errors.New("invalid newOrderRespType")
|
|
}
|
|
params.Set("newOrderRespType", newOrderRespType)
|
|
}
|
|
if quantity != 0 {
|
|
params.Set("quantity", strconv.FormatFloat(quantity, 'f', -1, 64))
|
|
}
|
|
if price != 0 {
|
|
params.Set("price", strconv.FormatFloat(price, 'f', -1, 64))
|
|
}
|
|
if stopPrice != 0 {
|
|
params.Set("stopPrice", strconv.FormatFloat(stopPrice, 'f', -1, 64))
|
|
}
|
|
if activationPrice != 0 {
|
|
params.Set("activationPrice", strconv.FormatFloat(activationPrice, 'f', -1, 64))
|
|
}
|
|
if callbackRate != 0 {
|
|
params.Set("callbackRate", strconv.FormatFloat(callbackRate, 'f', -1, 64))
|
|
}
|
|
return resp, b.SendAuthHTTPRequest(exchange.RestCoinMargined, http.MethodPost, cfuturesOrder, params, limitDefault, &resp)
|
|
}
|
|
|
|
// FuturesBatchOrder sends a batch order request
|
|
func (b *Binance) FuturesBatchOrder(data []PlaceBatchOrderData) ([]FuturesOrderPlaceData, error) {
|
|
var resp []FuturesOrderPlaceData
|
|
params := url.Values{}
|
|
for x := range data {
|
|
unformattedPair, err := currency.NewPairFromString(data[x].Symbol)
|
|
if err != nil {
|
|
return resp, err
|
|
}
|
|
formattedPair, err := b.FormatExchangeCurrency(unformattedPair, asset.CoinMarginedFutures)
|
|
if err != nil {
|
|
return resp, err
|
|
}
|
|
data[x].Symbol = formattedPair.String()
|
|
if data[x].PositionSide != "" {
|
|
if !common.StringDataCompare(validPositionSide, data[x].PositionSide) {
|
|
return resp, errors.New("invalid positionSide")
|
|
}
|
|
}
|
|
if data[x].WorkingType != "" {
|
|
if !common.StringDataCompare(validWorkingType, data[x].WorkingType) {
|
|
return resp, errors.New("invalid workingType")
|
|
}
|
|
}
|
|
if data[x].NewOrderRespType != "" {
|
|
if !common.StringDataCompare(validNewOrderRespType, data[x].NewOrderRespType) {
|
|
return resp, errors.New("invalid newOrderRespType")
|
|
}
|
|
}
|
|
}
|
|
jsonData, err := json.Marshal(data)
|
|
if err != nil {
|
|
return resp, err
|
|
}
|
|
params.Set("batchOrders", string(jsonData))
|
|
return resp, b.SendAuthHTTPRequest(exchange.RestCoinMargined, http.MethodPost, cfuturesBatchOrder, params, limitDefault, &resp)
|
|
}
|
|
|
|
// FuturesBatchCancelOrders sends a batch request to cancel orders
|
|
func (b *Binance) FuturesBatchCancelOrders(symbol currency.Pair, orderList, origClientOrderIDList []string) ([]BatchCancelOrderData, error) {
|
|
var resp []BatchCancelOrderData
|
|
params := url.Values{}
|
|
symbolValue, err := b.FormatSymbol(symbol, asset.CoinMarginedFutures)
|
|
if err != nil {
|
|
return resp, err
|
|
}
|
|
params.Set("symbol", symbolValue)
|
|
if len(orderList) != 0 {
|
|
jsonOrderList, err := json.Marshal(orderList)
|
|
if err != nil {
|
|
return resp, err
|
|
}
|
|
params.Set("orderIdList", string(jsonOrderList))
|
|
}
|
|
if len(origClientOrderIDList) != 0 {
|
|
jsonCliOrdIDList, err := json.Marshal(origClientOrderIDList)
|
|
if err != nil {
|
|
return resp, err
|
|
}
|
|
params.Set("origClientOrderIdList", string(jsonCliOrdIDList))
|
|
}
|
|
return resp, b.SendAuthHTTPRequest(exchange.RestCoinMargined, http.MethodDelete, cfuturesBatchOrder, params, limitDefault, &resp)
|
|
}
|
|
|
|
// FuturesGetOrderData gets futures order data
|
|
func (b *Binance) FuturesGetOrderData(symbol currency.Pair, orderID, origClientOrderID string) (FuturesOrderGetData, error) {
|
|
var resp FuturesOrderGetData
|
|
params := url.Values{}
|
|
symbolValue, err := b.FormatSymbol(symbol, asset.CoinMarginedFutures)
|
|
if err != nil {
|
|
return resp, err
|
|
}
|
|
params.Set("symbol", symbolValue)
|
|
if orderID != "" {
|
|
params.Set("orderId", orderID)
|
|
}
|
|
if origClientOrderID != "" {
|
|
params.Set("origClientOrderId", origClientOrderID)
|
|
}
|
|
return resp, b.SendAuthHTTPRequest(exchange.RestCoinMargined, http.MethodGet, cfuturesOrder, params, limitDefault, &resp)
|
|
}
|
|
|
|
// FuturesCancelOrder cancels a futures order
|
|
func (b *Binance) FuturesCancelOrder(symbol currency.Pair, orderID, origClientOrderID string) (FuturesOrderGetData, error) {
|
|
var resp FuturesOrderGetData
|
|
params := url.Values{}
|
|
symbolValue, err := b.FormatSymbol(symbol, asset.CoinMarginedFutures)
|
|
if err != nil {
|
|
return resp, err
|
|
}
|
|
params.Set("symbol", symbolValue)
|
|
if orderID != "" {
|
|
params.Set("orderId", orderID)
|
|
}
|
|
if origClientOrderID != "" {
|
|
params.Set("origClientOrderId", origClientOrderID)
|
|
}
|
|
return resp, b.SendAuthHTTPRequest(exchange.RestCoinMargined, http.MethodDelete, cfuturesOrder, params, limitDefault, &resp)
|
|
}
|
|
|
|
// FuturesCancelAllOpenOrders cancels a futures order
|
|
func (b *Binance) FuturesCancelAllOpenOrders(symbol currency.Pair) (GenericAuthResponse, error) {
|
|
var resp GenericAuthResponse
|
|
params := url.Values{}
|
|
symbolValue, err := b.FormatSymbol(symbol, asset.CoinMarginedFutures)
|
|
if err != nil {
|
|
return resp, err
|
|
}
|
|
params.Set("symbol", symbolValue)
|
|
return resp, b.SendAuthHTTPRequest(exchange.RestCoinMargined, http.MethodDelete, cfuturesCancelAllOrders, params, limitDefault, &resp)
|
|
}
|
|
|
|
// AutoCancelAllOpenOrders cancels all open futures orders
|
|
// countdownTime 1000 = 1s, example - to cancel all orders after 30s (countdownTime: 30000)
|
|
func (b *Binance) AutoCancelAllOpenOrders(symbol currency.Pair, countdownTime int64) (AutoCancelAllOrdersData, error) {
|
|
var resp AutoCancelAllOrdersData
|
|
params := url.Values{}
|
|
symbolValue, err := b.FormatSymbol(symbol, asset.CoinMarginedFutures)
|
|
if err != nil {
|
|
return resp, err
|
|
}
|
|
params.Set("symbol", symbolValue)
|
|
params.Set("countdownTime", strconv.FormatInt(countdownTime, 10))
|
|
return resp, b.SendAuthHTTPRequest(exchange.RestCoinMargined, http.MethodPost, cfuturesCountdownCancel, params, limitDefault, &resp)
|
|
}
|
|
|
|
// FuturesOpenOrderData gets open order data for CoinMarginedFutures,
|
|
func (b *Binance) FuturesOpenOrderData(symbol currency.Pair, orderID, origClientOrderID string) (FuturesOrderGetData, error) {
|
|
var resp FuturesOrderGetData
|
|
params := url.Values{}
|
|
symbolValue, err := b.FormatSymbol(symbol, asset.CoinMarginedFutures)
|
|
if err != nil {
|
|
return resp, err
|
|
}
|
|
params.Set("symbol", symbolValue)
|
|
if orderID != "" {
|
|
params.Set("orderId", orderID)
|
|
}
|
|
if origClientOrderID != "" {
|
|
params.Set("origClientOrderId", origClientOrderID)
|
|
}
|
|
return resp, b.SendAuthHTTPRequest(exchange.RestCoinMargined, http.MethodGet, cfuturesOpenOrder, params, limitDefault, &resp)
|
|
}
|
|
|
|
// GetFuturesAllOpenOrders gets all open orders data for CoinMarginedFutures,
|
|
func (b *Binance) GetFuturesAllOpenOrders(symbol currency.Pair, pair string) ([]FuturesOrderData, error) {
|
|
var resp []FuturesOrderData
|
|
params := url.Values{}
|
|
if !symbol.IsEmpty() {
|
|
symbolValue, err := b.FormatSymbol(symbol, asset.CoinMarginedFutures)
|
|
if err != nil {
|
|
return resp, err
|
|
}
|
|
params.Set("symbol", symbolValue)
|
|
}
|
|
if pair != "" {
|
|
params.Set("pair", pair)
|
|
}
|
|
return resp, b.SendAuthHTTPRequest(exchange.RestCoinMargined, http.MethodGet, cfuturesAllOpenOrders, params, limitDefault, &resp)
|
|
}
|
|
|
|
// GetAllFuturesOrders gets all orders active cancelled or filled
|
|
func (b *Binance) GetAllFuturesOrders(symbol currency.Pair, pair string, startTime, endTime time.Time, orderID, limit int64) ([]FuturesOrderData, error) {
|
|
var resp []FuturesOrderData
|
|
params := url.Values{}
|
|
if !symbol.IsEmpty() {
|
|
symbolValue, err := b.FormatSymbol(symbol, asset.CoinMarginedFutures)
|
|
if err != nil {
|
|
return resp, err
|
|
}
|
|
params.Set("symbol", symbolValue)
|
|
}
|
|
if pair != "" {
|
|
params.Set("pair", pair)
|
|
}
|
|
if orderID != 0 {
|
|
params.Set("orderID", strconv.FormatInt(orderID, 10))
|
|
}
|
|
if limit > 0 && limit <= 100 {
|
|
params.Set("limit", strconv.FormatInt(limit, 10))
|
|
}
|
|
if !startTime.IsZero() && !endTime.IsZero() {
|
|
if startTime.After(endTime) {
|
|
return resp, errors.New("startTime cannot be after endTime")
|
|
}
|
|
params.Set("start_time", strconv.FormatInt(startTime.Unix(), 10))
|
|
params.Set("end_time", strconv.FormatInt(endTime.Unix(), 10))
|
|
}
|
|
return resp, b.SendAuthHTTPRequest(exchange.RestCoinMargined, http.MethodGet, cfuturesAllOrders, params, limitDefault, &resp)
|
|
}
|
|
|
|
// GetFuturesAccountBalance gets account balance data for CoinMarginedFutures, account
|
|
func (b *Binance) GetFuturesAccountBalance() ([]FuturesAccountBalanceData, error) {
|
|
var resp []FuturesAccountBalanceData
|
|
return resp, b.SendAuthHTTPRequest(exchange.RestCoinMargined, http.MethodGet, cfuturesAccountBalance, nil, limitDefault, &resp)
|
|
}
|
|
|
|
// GetFuturesAccountInfo gets account info data for CoinMarginedFutures, account
|
|
func (b *Binance) GetFuturesAccountInfo() (FuturesAccountInformation, error) {
|
|
var resp FuturesAccountInformation
|
|
return resp, b.SendAuthHTTPRequest(exchange.RestCoinMargined, http.MethodGet, cfuturesAccountInfo, nil, limitDefault, &resp)
|
|
}
|
|
|
|
// FuturesChangeInitialLeverage changes initial leverage for the account
|
|
func (b *Binance) FuturesChangeInitialLeverage(symbol currency.Pair, leverage int64) (FuturesLeverageData, error) {
|
|
var resp FuturesLeverageData
|
|
params := url.Values{}
|
|
symbolValue, err := b.FormatSymbol(symbol, asset.CoinMarginedFutures)
|
|
if err != nil {
|
|
return resp, err
|
|
}
|
|
params.Set("symbol", symbolValue)
|
|
if leverage < 1 || leverage > 125 {
|
|
return resp, errors.New("invalid leverage")
|
|
}
|
|
params.Set("leverage", strconv.FormatInt(leverage, 10))
|
|
return resp, b.SendAuthHTTPRequest(exchange.RestCoinMargined, http.MethodPost, cfuturesChangeInitialLeverage, params, limitDefault, &resp)
|
|
}
|
|
|
|
// FuturesChangeMarginType changes margin type
|
|
func (b *Binance) FuturesChangeMarginType(symbol currency.Pair, marginType string) (GenericAuthResponse, error) {
|
|
var resp GenericAuthResponse
|
|
params := url.Values{}
|
|
symbolValue, err := b.FormatSymbol(symbol, asset.CoinMarginedFutures)
|
|
if err != nil {
|
|
return resp, err
|
|
}
|
|
params.Set("symbol", symbolValue)
|
|
if !common.StringDataCompare(validMarginType, marginType) {
|
|
return resp, errors.New("invalid marginType")
|
|
}
|
|
params.Set("marginType", marginType)
|
|
return resp, b.SendAuthHTTPRequest(exchange.RestCoinMargined, http.MethodPost, cfuturesChangeMarginType, params, limitDefault, &resp)
|
|
}
|
|
|
|
// ModifyIsolatedPositionMargin changes margin for an isolated position
|
|
func (b *Binance) ModifyIsolatedPositionMargin(symbol currency.Pair, positionSide, changeType string, amount float64) (GenericAuthResponse, error) {
|
|
var resp GenericAuthResponse
|
|
params := url.Values{}
|
|
symbolValue, err := b.FormatSymbol(symbol, asset.CoinMarginedFutures)
|
|
if err != nil {
|
|
return resp, err
|
|
}
|
|
params.Set("symbol", symbolValue)
|
|
if !common.StringDataCompare(validPositionSide, positionSide) {
|
|
return resp, errors.New("invalid positionSide")
|
|
}
|
|
params.Set("positionSide", positionSide)
|
|
cType, ok := validMarginChange[changeType]
|
|
if !ok {
|
|
return resp, errors.New("invalid changeType")
|
|
}
|
|
params.Set("type", strconv.FormatInt(cType, 10))
|
|
params.Set("amount", strconv.FormatFloat(amount, 'f', -1, 64))
|
|
return resp, b.SendAuthHTTPRequest(exchange.RestCoinMargined, http.MethodPost, cfuturesModifyMargin, params, limitDefault, &resp)
|
|
}
|
|
|
|
// FuturesMarginChangeHistory gets past margin changes for positions
|
|
func (b *Binance) FuturesMarginChangeHistory(symbol currency.Pair, changeType string, startTime, endTime time.Time, limit int64) ([]GetPositionMarginChangeHistoryData, error) {
|
|
var resp []GetPositionMarginChangeHistoryData
|
|
params := url.Values{}
|
|
symbolValue, err := b.FormatSymbol(symbol, asset.CoinMarginedFutures)
|
|
if err != nil {
|
|
return resp, err
|
|
}
|
|
params.Set("symbol", symbolValue)
|
|
cType, ok := validMarginChange[changeType]
|
|
if !ok {
|
|
return resp, errors.New("invalid changeType")
|
|
}
|
|
params.Set("type", strconv.FormatInt(cType, 10))
|
|
if !startTime.IsZero() && !endTime.IsZero() {
|
|
if startTime.After(endTime) {
|
|
return resp, errors.New("startTime cannot be after endTime")
|
|
}
|
|
params.Set("start_time", strconv.FormatInt(startTime.Unix(), 10))
|
|
params.Set("end_time", strconv.FormatInt(endTime.Unix(), 10))
|
|
}
|
|
if limit != 0 {
|
|
params.Set("limit", strconv.FormatInt(limit, 10))
|
|
}
|
|
return resp, b.SendAuthHTTPRequest(exchange.RestCoinMargined, http.MethodGet, cfuturesMarginChangeHistory, params, limitDefault, &resp)
|
|
}
|
|
|
|
// FuturesPositionsInfo gets futures positions info
|
|
func (b *Binance) FuturesPositionsInfo(marginAsset, pair string) ([]FuturesPositionInformation, error) {
|
|
var resp []FuturesPositionInformation
|
|
params := url.Values{}
|
|
if marginAsset != "" {
|
|
params.Set("marginAsset", marginAsset)
|
|
}
|
|
if pair != "" {
|
|
params.Set("pair", pair)
|
|
}
|
|
return resp, b.SendAuthHTTPRequest(exchange.RestCoinMargined, http.MethodGet, cfuturesPositionInfo, params, limitDefault, &resp)
|
|
}
|
|
|
|
// FuturesTradeHistory gets trade history for CoinMarginedFutures, account
|
|
func (b *Binance) FuturesTradeHistory(symbol currency.Pair, pair string, startTime, endTime time.Time, limit, fromID int64) ([]FuturesAccountTradeList, error) {
|
|
var resp []FuturesAccountTradeList
|
|
params := url.Values{}
|
|
if symbol != (currency.Pair{}) {
|
|
symbolValue, err := b.FormatSymbol(symbol, asset.CoinMarginedFutures)
|
|
if err != nil {
|
|
return resp, err
|
|
}
|
|
params.Set("symbol", symbolValue)
|
|
}
|
|
if pair != "" {
|
|
params.Set("pair", pair)
|
|
}
|
|
if !startTime.IsZero() && !endTime.IsZero() {
|
|
if startTime.After(endTime) {
|
|
return resp, errors.New("startTime cannot be after endTime")
|
|
}
|
|
params.Set("start_time", strconv.FormatInt(startTime.Unix(), 10))
|
|
params.Set("end_time", strconv.FormatInt(endTime.Unix(), 10))
|
|
}
|
|
if limit != 0 {
|
|
params.Set("limit", strconv.FormatInt(limit, 10))
|
|
}
|
|
if fromID != 0 {
|
|
params.Set("fromId", strconv.FormatInt(fromID, 10))
|
|
}
|
|
return resp, b.SendAuthHTTPRequest(exchange.RestCoinMargined, http.MethodGet, cfuturesAccountTradeList, params, limitDefault, &resp)
|
|
}
|
|
|
|
// FuturesIncomeHistory gets income history for CoinMarginedFutures,
|
|
func (b *Binance) FuturesIncomeHistory(symbol currency.Pair, incomeType string, startTime, endTime time.Time, limit int64) ([]FuturesIncomeHistoryData, error) {
|
|
var resp []FuturesIncomeHistoryData
|
|
params := url.Values{}
|
|
if symbol != (currency.Pair{}) {
|
|
symbolValue, err := b.FormatSymbol(symbol, asset.CoinMarginedFutures)
|
|
if err != nil {
|
|
return resp, err
|
|
}
|
|
params.Set("symbol", symbolValue)
|
|
}
|
|
if incomeType != "" {
|
|
if !common.StringDataCompare(validIncomeType, incomeType) {
|
|
return resp, fmt.Errorf("invalid incomeType: %v", incomeType)
|
|
}
|
|
params.Set("incomeType", incomeType)
|
|
}
|
|
if !startTime.IsZero() && !endTime.IsZero() {
|
|
if startTime.After(endTime) {
|
|
return resp, errors.New("startTime cannot be after endTime")
|
|
}
|
|
params.Set("start_time", strconv.FormatInt(startTime.Unix(), 10))
|
|
params.Set("end_time", strconv.FormatInt(endTime.Unix(), 10))
|
|
}
|
|
if limit != 0 {
|
|
params.Set("limit", strconv.FormatInt(limit, 10))
|
|
}
|
|
return resp, b.SendAuthHTTPRequest(exchange.RestCoinMargined, http.MethodGet, cfuturesIncomeHistory, params, limitDefault, &resp)
|
|
}
|
|
|
|
// FuturesNotionalBracket gets futures notional bracket
|
|
func (b *Binance) FuturesNotionalBracket(pair string) ([]NotionalBracketData, error) {
|
|
var resp []NotionalBracketData
|
|
params := url.Values{}
|
|
if pair != "" {
|
|
params.Set("pair", pair)
|
|
}
|
|
return resp, b.SendAuthHTTPRequest(exchange.RestCoinMargined, http.MethodGet, cfuturesNotionalBracket, params, limitDefault, &resp)
|
|
}
|
|
|
|
// FuturesForceOrders gets futures forced orders
|
|
func (b *Binance) FuturesForceOrders(symbol currency.Pair, autoCloseType string, startTime, endTime time.Time) ([]ForcedOrdersData, error) {
|
|
var resp []ForcedOrdersData
|
|
params := url.Values{}
|
|
if symbol != (currency.Pair{}) {
|
|
symbolValue, err := b.FormatSymbol(symbol, asset.CoinMarginedFutures)
|
|
if err != nil {
|
|
return resp, err
|
|
}
|
|
params.Set("symbol", symbolValue)
|
|
}
|
|
if autoCloseType != "" {
|
|
if !common.StringDataCompare(validAutoCloseTypes, autoCloseType) {
|
|
return resp, errors.New("invalid autoCloseType")
|
|
}
|
|
params.Set("autoCloseType", autoCloseType)
|
|
}
|
|
if !startTime.IsZero() && !endTime.IsZero() {
|
|
if startTime.After(endTime) {
|
|
return resp, errors.New("startTime cannot be after endTime")
|
|
}
|
|
params.Set("start_time", strconv.FormatInt(startTime.Unix(), 10))
|
|
params.Set("end_time", strconv.FormatInt(endTime.Unix(), 10))
|
|
}
|
|
return resp, b.SendAuthHTTPRequest(exchange.RestCoinMargined, http.MethodGet, cfuturesUsersForceOrders, params, limitDefault, &resp)
|
|
}
|
|
|
|
// FuturesPositionsADLEstimate estimates ADL on positions
|
|
func (b *Binance) FuturesPositionsADLEstimate(symbol currency.Pair) ([]ADLEstimateData, error) {
|
|
var resp []ADLEstimateData
|
|
params := url.Values{}
|
|
if symbol != (currency.Pair{}) {
|
|
symbolValue, err := b.FormatSymbol(symbol, asset.CoinMarginedFutures)
|
|
if err != nil {
|
|
return resp, err
|
|
}
|
|
params.Set("symbol", symbolValue)
|
|
}
|
|
return resp, b.SendAuthHTTPRequest(exchange.RestCoinMargined, http.MethodGet, cfuturesADLQuantile, params, limitDefault, &resp)
|
|
}
|