mirror of
https://github.com/c9s/bbgo.git
synced 2024-11-10 09:11:55 +00:00
binance: move futures methods
This commit is contained in:
parent
9c0787e6ce
commit
071825e982
|
@ -367,31 +367,6 @@ func (e *Exchange) QueryMarginBorrowHistory(ctx context.Context, asset string) e
|
|||
return nil
|
||||
}
|
||||
|
||||
func (e *Exchange) TransferFuturesAccountAsset(ctx context.Context, asset string, amount fixedpoint.Value, io types.TransferDirection) error {
|
||||
req := e.client2.NewFuturesTransferRequest()
|
||||
req.Asset(asset)
|
||||
req.Amount(amount.String())
|
||||
|
||||
if io == types.TransferIn {
|
||||
req.TransferType(binanceapi.FuturesTransferSpotToUsdtFutures)
|
||||
} else if io == types.TransferOut {
|
||||
req.TransferType(binanceapi.FuturesTransferUsdtFuturesToSpot)
|
||||
} else {
|
||||
return fmt.Errorf("unexpected transfer direction: %d given", io)
|
||||
}
|
||||
|
||||
resp, err := req.Do(ctx)
|
||||
|
||||
switch io {
|
||||
case types.TransferIn:
|
||||
log.Infof("internal transfer (spot) => (futures) %s %s, transaction = %+v, err = %+v", amount.String(), asset, resp, err)
|
||||
case types.TransferOut:
|
||||
log.Infof("internal transfer (futures) => (spot) %s %s, transaction = %+v, err = %+v", amount.String(), asset, resp, err)
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// transferCrossMarginAccountAsset transfer asset to the cross margin account or to the main account
|
||||
func (e *Exchange) transferCrossMarginAccountAsset(ctx context.Context, asset string, amount fixedpoint.Value, io types.TransferDirection) error {
|
||||
req := e.client.NewMarginTransferService()
|
||||
|
@ -676,42 +651,6 @@ func (e *Exchange) QuerySpotAccount(ctx context.Context) (*types.Account, error)
|
|||
return a, nil
|
||||
}
|
||||
|
||||
// QueryFuturesAccount gets the futures account balances from Binance
|
||||
// Balance.Available = Wallet Balance(in Binance UI) - Used Margin
|
||||
// Balance.Locked = Used Margin
|
||||
func (e *Exchange) QueryFuturesAccount(ctx context.Context) (*types.Account, error) {
|
||||
account, err := e.futuresClient.NewGetAccountService().Do(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
accountBalances, err := e.futuresClient.NewGetBalanceService().Do(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var balances = map[string]types.Balance{}
|
||||
for _, b := range accountBalances {
|
||||
balanceAvailable := fixedpoint.Must(fixedpoint.NewFromString(b.AvailableBalance))
|
||||
balanceTotal := fixedpoint.Must(fixedpoint.NewFromString(b.Balance))
|
||||
unrealizedPnl := fixedpoint.Must(fixedpoint.NewFromString(b.CrossUnPnl))
|
||||
balances[b.Asset] = types.Balance{
|
||||
Currency: b.Asset,
|
||||
Available: balanceAvailable,
|
||||
Locked: balanceTotal.Sub(balanceAvailable.Sub(unrealizedPnl)),
|
||||
}
|
||||
}
|
||||
|
||||
a := &types.Account{
|
||||
AccountType: types.AccountTypeFutures,
|
||||
FuturesInfo: toGlobalFuturesAccountInfo(account), // In binance GO api, Account define account info which mantain []*AccountAsset and []*AccountPosition.
|
||||
CanDeposit: account.CanDeposit, // if can transfer in asset
|
||||
CanTrade: account.CanTrade, // if can trade
|
||||
CanWithdraw: account.CanWithdraw, // if can transfer out asset
|
||||
}
|
||||
a.UpdateBalances(balances)
|
||||
return a, nil
|
||||
}
|
||||
|
||||
func (e *Exchange) QueryAccount(ctx context.Context) (*types.Account, error) {
|
||||
var account *types.Account
|
||||
var err error
|
||||
|
@ -892,31 +831,6 @@ func (e *Exchange) QueryClosedOrders(ctx context.Context, symbol string, since,
|
|||
return toGlobalOrders(binanceOrders, e.IsMargin)
|
||||
}
|
||||
|
||||
func (e *Exchange) cancelFuturesOrders(ctx context.Context, orders ...types.Order) (err error) {
|
||||
for _, o := range orders {
|
||||
var req = e.futuresClient.NewCancelOrderService()
|
||||
|
||||
// Mandatory
|
||||
req.Symbol(o.Symbol)
|
||||
|
||||
if o.OrderID > 0 {
|
||||
req.OrderID(int64(o.OrderID))
|
||||
} else {
|
||||
err = multierr.Append(err, types.NewOrderError(
|
||||
fmt.Errorf("can not cancel %s order, order does not contain orderID or clientOrderID", o.Symbol),
|
||||
o))
|
||||
continue
|
||||
}
|
||||
|
||||
_, err2 := req.Do(ctx)
|
||||
if err2 != nil {
|
||||
err = multierr.Append(err, types.NewOrderError(err2, o))
|
||||
}
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (e *Exchange) CancelOrders(ctx context.Context, orders ...types.Order) (err error) {
|
||||
if err := orderLimiter.Wait(ctx); err != nil {
|
||||
log.WithError(err).Errorf("order rate limiter wait error")
|
||||
|
@ -1068,91 +982,6 @@ func (e *Exchange) submitMarginOrder(ctx context.Context, order types.SubmitOrde
|
|||
return createdOrder, err
|
||||
}
|
||||
|
||||
func (e *Exchange) submitFuturesOrder(ctx context.Context, order types.SubmitOrder) (*types.Order, error) {
|
||||
orderType, err := toLocalFuturesOrderType(order.Type)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
req := e.futuresClient.NewCreateOrderService().
|
||||
Symbol(order.Symbol).
|
||||
Type(orderType).
|
||||
Side(futures.SideType(order.Side)).
|
||||
ReduceOnly(order.ReduceOnly)
|
||||
|
||||
clientOrderID := newFuturesClientOrderID(order.ClientOrderID)
|
||||
if len(clientOrderID) > 0 {
|
||||
req.NewClientOrderID(clientOrderID)
|
||||
}
|
||||
|
||||
// use response result format
|
||||
req.NewOrderResponseType(futures.NewOrderRespTypeRESULT)
|
||||
|
||||
if order.Market.Symbol != "" {
|
||||
req.Quantity(order.Market.FormatQuantity(order.Quantity))
|
||||
} else {
|
||||
// TODO report error
|
||||
req.Quantity(order.Quantity.FormatString(8))
|
||||
}
|
||||
|
||||
// set price field for limit orders
|
||||
switch order.Type {
|
||||
case types.OrderTypeStopLimit, types.OrderTypeLimit, types.OrderTypeLimitMaker:
|
||||
if order.Market.Symbol != "" {
|
||||
req.Price(order.Market.FormatPrice(order.Price))
|
||||
} else {
|
||||
// TODO report error
|
||||
req.Price(order.Price.FormatString(8))
|
||||
}
|
||||
}
|
||||
|
||||
// set stop price
|
||||
switch order.Type {
|
||||
|
||||
case types.OrderTypeStopLimit, types.OrderTypeStopMarket:
|
||||
if order.Market.Symbol != "" {
|
||||
req.StopPrice(order.Market.FormatPrice(order.StopPrice))
|
||||
} else {
|
||||
// TODO report error
|
||||
req.StopPrice(order.StopPrice.FormatString(8))
|
||||
}
|
||||
}
|
||||
|
||||
// could be IOC or FOK
|
||||
if len(order.TimeInForce) > 0 {
|
||||
// TODO: check the TimeInForce value
|
||||
req.TimeInForce(futures.TimeInForceType(order.TimeInForce))
|
||||
} else {
|
||||
switch order.Type {
|
||||
case types.OrderTypeLimit, types.OrderTypeLimitMaker, types.OrderTypeStopLimit:
|
||||
req.TimeInForce(futures.TimeInForceTypeGTC)
|
||||
}
|
||||
}
|
||||
|
||||
response, err := req.Do(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
log.Infof("futures order creation response: %+v", response)
|
||||
|
||||
createdOrder, err := toGlobalFuturesOrder(&futures.Order{
|
||||
Symbol: response.Symbol,
|
||||
OrderID: response.OrderID,
|
||||
ClientOrderID: response.ClientOrderID,
|
||||
Price: response.Price,
|
||||
OrigQuantity: response.OrigQuantity,
|
||||
ExecutedQuantity: response.ExecutedQuantity,
|
||||
Status: response.Status,
|
||||
TimeInForce: response.TimeInForce,
|
||||
Type: response.Type,
|
||||
Side: response.Side,
|
||||
ReduceOnly: response.ReduceOnly,
|
||||
}, false)
|
||||
|
||||
return createdOrder, err
|
||||
}
|
||||
|
||||
// BBGO is a broker on Binance
|
||||
const spotBrokerID = "NSUYEBKM"
|
||||
|
||||
|
@ -1379,60 +1208,6 @@ func (e *Exchange) QueryKLines(ctx context.Context, symbol string, interval type
|
|||
return kLines, nil
|
||||
}
|
||||
|
||||
func (e *Exchange) QueryFuturesKLines(ctx context.Context, symbol string, interval types.Interval, options types.KLineQueryOptions) ([]types.KLine, error) {
|
||||
|
||||
var limit = 1000
|
||||
if options.Limit > 0 {
|
||||
// default limit == 1000
|
||||
limit = options.Limit
|
||||
}
|
||||
|
||||
log.Infof("querying kline %s %s %v", symbol, interval, options)
|
||||
|
||||
req := e.futuresClient.NewKlinesService().
|
||||
Symbol(symbol).
|
||||
Interval(string(interval)).
|
||||
Limit(limit)
|
||||
|
||||
if options.StartTime != nil {
|
||||
req.StartTime(options.StartTime.UnixMilli())
|
||||
}
|
||||
|
||||
if options.EndTime != nil {
|
||||
req.EndTime(options.EndTime.UnixMilli())
|
||||
}
|
||||
|
||||
resp, err := req.Do(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var kLines []types.KLine
|
||||
for _, k := range resp {
|
||||
kLines = append(kLines, types.KLine{
|
||||
Exchange: types.ExchangeBinance,
|
||||
Symbol: symbol,
|
||||
Interval: interval,
|
||||
StartTime: types.NewTimeFromUnix(0, k.OpenTime*int64(time.Millisecond)),
|
||||
EndTime: types.NewTimeFromUnix(0, k.CloseTime*int64(time.Millisecond)),
|
||||
Open: fixedpoint.MustNewFromString(k.Open),
|
||||
Close: fixedpoint.MustNewFromString(k.Close),
|
||||
High: fixedpoint.MustNewFromString(k.High),
|
||||
Low: fixedpoint.MustNewFromString(k.Low),
|
||||
Volume: fixedpoint.MustNewFromString(k.Volume),
|
||||
QuoteVolume: fixedpoint.MustNewFromString(k.QuoteAssetVolume),
|
||||
TakerBuyBaseAssetVolume: fixedpoint.MustNewFromString(k.TakerBuyBaseAssetVolume),
|
||||
TakerBuyQuoteAssetVolume: fixedpoint.MustNewFromString(k.TakerBuyQuoteAssetVolume),
|
||||
LastTradeID: 0,
|
||||
NumberOfTrades: uint64(k.TradeNum),
|
||||
Closed: true,
|
||||
})
|
||||
}
|
||||
|
||||
kLines = types.SortKLinesAscending(kLines)
|
||||
return kLines, nil
|
||||
}
|
||||
|
||||
func (e *Exchange) queryMarginTrades(ctx context.Context, symbol string, options *types.TradeQueryOptions) (trades []types.Trade, err error) {
|
||||
var remoteTrades []*binance.TradeV3
|
||||
req := e.client.NewListMarginTradesService().
|
||||
|
@ -1482,55 +1257,6 @@ func (e *Exchange) queryMarginTrades(ctx context.Context, symbol string, options
|
|||
return trades, nil
|
||||
}
|
||||
|
||||
func (e *Exchange) queryFuturesTrades(ctx context.Context, symbol string, options *types.TradeQueryOptions) (trades []types.Trade, err error) {
|
||||
|
||||
var remoteTrades []*futures.AccountTrade
|
||||
req := e.futuresClient.NewListAccountTradeService().
|
||||
Symbol(symbol)
|
||||
if options.Limit > 0 {
|
||||
req.Limit(int(options.Limit))
|
||||
} else {
|
||||
req.Limit(1000)
|
||||
}
|
||||
|
||||
// BINANCE uses inclusive last trade ID
|
||||
if options.LastTradeID > 0 {
|
||||
req.FromID(int64(options.LastTradeID))
|
||||
}
|
||||
|
||||
// The parameter fromId cannot be sent with startTime or endTime.
|
||||
// Mentioned in binance futures docs
|
||||
if options.LastTradeID <= 0 {
|
||||
if options.StartTime != nil && options.EndTime != nil {
|
||||
if options.EndTime.Sub(*options.StartTime) < 24*time.Hour {
|
||||
req.StartTime(options.StartTime.UnixMilli())
|
||||
req.EndTime(options.EndTime.UnixMilli())
|
||||
} else {
|
||||
req.StartTime(options.StartTime.UnixMilli())
|
||||
}
|
||||
} else if options.EndTime != nil {
|
||||
req.EndTime(options.EndTime.UnixMilli())
|
||||
}
|
||||
}
|
||||
|
||||
remoteTrades, err = req.Do(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, t := range remoteTrades {
|
||||
localTrade, err := toGlobalFuturesTrade(*t)
|
||||
if err != nil {
|
||||
log.WithError(err).Errorf("can not convert binance futures trade: %+v", t)
|
||||
continue
|
||||
}
|
||||
|
||||
trades = append(trades, *localTrade)
|
||||
}
|
||||
|
||||
trades = types.SortTradesAscending(trades)
|
||||
return trades, nil
|
||||
}
|
||||
|
||||
func (e *Exchange) querySpotTrades(ctx context.Context, symbol string, options *types.TradeQueryOptions) (trades []types.Trade, err error) {
|
||||
req := e.client2.NewGetMyTradesRequest()
|
||||
req.Symbol(symbol)
|
||||
|
|
288
pkg/exchange/binance/futures.go
Normal file
288
pkg/exchange/binance/futures.go
Normal file
|
@ -0,0 +1,288 @@
|
|||
package binance
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/adshao/go-binance/v2/futures"
|
||||
"go.uber.org/multierr"
|
||||
|
||||
"github.com/c9s/bbgo/pkg/exchange/binance/binanceapi"
|
||||
"github.com/c9s/bbgo/pkg/fixedpoint"
|
||||
"github.com/c9s/bbgo/pkg/types"
|
||||
)
|
||||
|
||||
func (e *Exchange) TransferFuturesAccountAsset(ctx context.Context, asset string, amount fixedpoint.Value, io types.TransferDirection) error {
|
||||
req := e.client2.NewFuturesTransferRequest()
|
||||
req.Asset(asset)
|
||||
req.Amount(amount.String())
|
||||
|
||||
if io == types.TransferIn {
|
||||
req.TransferType(binanceapi.FuturesTransferSpotToUsdtFutures)
|
||||
} else if io == types.TransferOut {
|
||||
req.TransferType(binanceapi.FuturesTransferUsdtFuturesToSpot)
|
||||
} else {
|
||||
return fmt.Errorf("unexpected transfer direction: %d given", io)
|
||||
}
|
||||
|
||||
resp, err := req.Do(ctx)
|
||||
|
||||
switch io {
|
||||
case types.TransferIn:
|
||||
log.Infof("internal transfer (spot) => (futures) %s %s, transaction = %+v, err = %+v", amount.String(), asset, resp, err)
|
||||
case types.TransferOut:
|
||||
log.Infof("internal transfer (futures) => (spot) %s %s, transaction = %+v, err = %+v", amount.String(), asset, resp, err)
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// QueryFuturesAccount gets the futures account balances from Binance
|
||||
// Balance.Available = Wallet Balance(in Binance UI) - Used Margin
|
||||
// Balance.Locked = Used Margin
|
||||
func (e *Exchange) QueryFuturesAccount(ctx context.Context) (*types.Account, error) {
|
||||
account, err := e.futuresClient.NewGetAccountService().Do(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
accountBalances, err := e.futuresClient.NewGetBalanceService().Do(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var balances = map[string]types.Balance{}
|
||||
for _, b := range accountBalances {
|
||||
balanceAvailable := fixedpoint.Must(fixedpoint.NewFromString(b.AvailableBalance))
|
||||
balanceTotal := fixedpoint.Must(fixedpoint.NewFromString(b.Balance))
|
||||
unrealizedPnl := fixedpoint.Must(fixedpoint.NewFromString(b.CrossUnPnl))
|
||||
balances[b.Asset] = types.Balance{
|
||||
Currency: b.Asset,
|
||||
Available: balanceAvailable,
|
||||
Locked: balanceTotal.Sub(balanceAvailable.Sub(unrealizedPnl)),
|
||||
}
|
||||
}
|
||||
|
||||
a := &types.Account{
|
||||
AccountType: types.AccountTypeFutures,
|
||||
FuturesInfo: toGlobalFuturesAccountInfo(account), // In binance GO api, Account define account info which mantain []*AccountAsset and []*AccountPosition.
|
||||
CanDeposit: account.CanDeposit, // if can transfer in asset
|
||||
CanTrade: account.CanTrade, // if can trade
|
||||
CanWithdraw: account.CanWithdraw, // if can transfer out asset
|
||||
}
|
||||
a.UpdateBalances(balances)
|
||||
return a, nil
|
||||
}
|
||||
|
||||
func (e *Exchange) cancelFuturesOrders(ctx context.Context, orders ...types.Order) (err error) {
|
||||
for _, o := range orders {
|
||||
var req = e.futuresClient.NewCancelOrderService()
|
||||
|
||||
// Mandatory
|
||||
req.Symbol(o.Symbol)
|
||||
|
||||
if o.OrderID > 0 {
|
||||
req.OrderID(int64(o.OrderID))
|
||||
} else {
|
||||
err = multierr.Append(err, types.NewOrderError(
|
||||
fmt.Errorf("can not cancel %s order, order does not contain orderID or clientOrderID", o.Symbol),
|
||||
o))
|
||||
continue
|
||||
}
|
||||
|
||||
_, err2 := req.Do(ctx)
|
||||
if err2 != nil {
|
||||
err = multierr.Append(err, types.NewOrderError(err2, o))
|
||||
}
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (e *Exchange) submitFuturesOrder(ctx context.Context, order types.SubmitOrder) (*types.Order, error) {
|
||||
orderType, err := toLocalFuturesOrderType(order.Type)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
req := e.futuresClient.NewCreateOrderService().
|
||||
Symbol(order.Symbol).
|
||||
Type(orderType).
|
||||
Side(futures.SideType(order.Side)).
|
||||
ReduceOnly(order.ReduceOnly)
|
||||
|
||||
clientOrderID := newFuturesClientOrderID(order.ClientOrderID)
|
||||
if len(clientOrderID) > 0 {
|
||||
req.NewClientOrderID(clientOrderID)
|
||||
}
|
||||
|
||||
// use response result format
|
||||
req.NewOrderResponseType(futures.NewOrderRespTypeRESULT)
|
||||
|
||||
if order.Market.Symbol != "" {
|
||||
req.Quantity(order.Market.FormatQuantity(order.Quantity))
|
||||
} else {
|
||||
// TODO report error
|
||||
req.Quantity(order.Quantity.FormatString(8))
|
||||
}
|
||||
|
||||
// set price field for limit orders
|
||||
switch order.Type {
|
||||
case types.OrderTypeStopLimit, types.OrderTypeLimit, types.OrderTypeLimitMaker:
|
||||
if order.Market.Symbol != "" {
|
||||
req.Price(order.Market.FormatPrice(order.Price))
|
||||
} else {
|
||||
// TODO report error
|
||||
req.Price(order.Price.FormatString(8))
|
||||
}
|
||||
}
|
||||
|
||||
// set stop price
|
||||
switch order.Type {
|
||||
|
||||
case types.OrderTypeStopLimit, types.OrderTypeStopMarket:
|
||||
if order.Market.Symbol != "" {
|
||||
req.StopPrice(order.Market.FormatPrice(order.StopPrice))
|
||||
} else {
|
||||
// TODO report error
|
||||
req.StopPrice(order.StopPrice.FormatString(8))
|
||||
}
|
||||
}
|
||||
|
||||
// could be IOC or FOK
|
||||
if len(order.TimeInForce) > 0 {
|
||||
// TODO: check the TimeInForce value
|
||||
req.TimeInForce(futures.TimeInForceType(order.TimeInForce))
|
||||
} else {
|
||||
switch order.Type {
|
||||
case types.OrderTypeLimit, types.OrderTypeLimitMaker, types.OrderTypeStopLimit:
|
||||
req.TimeInForce(futures.TimeInForceTypeGTC)
|
||||
}
|
||||
}
|
||||
|
||||
response, err := req.Do(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
log.Infof("futures order creation response: %+v", response)
|
||||
|
||||
createdOrder, err := toGlobalFuturesOrder(&futures.Order{
|
||||
Symbol: response.Symbol,
|
||||
OrderID: response.OrderID,
|
||||
ClientOrderID: response.ClientOrderID,
|
||||
Price: response.Price,
|
||||
OrigQuantity: response.OrigQuantity,
|
||||
ExecutedQuantity: response.ExecutedQuantity,
|
||||
Status: response.Status,
|
||||
TimeInForce: response.TimeInForce,
|
||||
Type: response.Type,
|
||||
Side: response.Side,
|
||||
ReduceOnly: response.ReduceOnly,
|
||||
}, false)
|
||||
|
||||
return createdOrder, err
|
||||
}
|
||||
|
||||
func (e *Exchange) QueryFuturesKLines(ctx context.Context, symbol string, interval types.Interval, options types.KLineQueryOptions) ([]types.KLine, error) {
|
||||
|
||||
var limit = 1000
|
||||
if options.Limit > 0 {
|
||||
// default limit == 1000
|
||||
limit = options.Limit
|
||||
}
|
||||
|
||||
log.Infof("querying kline %s %s %v", symbol, interval, options)
|
||||
|
||||
req := e.futuresClient.NewKlinesService().
|
||||
Symbol(symbol).
|
||||
Interval(string(interval)).
|
||||
Limit(limit)
|
||||
|
||||
if options.StartTime != nil {
|
||||
req.StartTime(options.StartTime.UnixMilli())
|
||||
}
|
||||
|
||||
if options.EndTime != nil {
|
||||
req.EndTime(options.EndTime.UnixMilli())
|
||||
}
|
||||
|
||||
resp, err := req.Do(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var kLines []types.KLine
|
||||
for _, k := range resp {
|
||||
kLines = append(kLines, types.KLine{
|
||||
Exchange: types.ExchangeBinance,
|
||||
Symbol: symbol,
|
||||
Interval: interval,
|
||||
StartTime: types.NewTimeFromUnix(0, k.OpenTime*int64(time.Millisecond)),
|
||||
EndTime: types.NewTimeFromUnix(0, k.CloseTime*int64(time.Millisecond)),
|
||||
Open: fixedpoint.MustNewFromString(k.Open),
|
||||
Close: fixedpoint.MustNewFromString(k.Close),
|
||||
High: fixedpoint.MustNewFromString(k.High),
|
||||
Low: fixedpoint.MustNewFromString(k.Low),
|
||||
Volume: fixedpoint.MustNewFromString(k.Volume),
|
||||
QuoteVolume: fixedpoint.MustNewFromString(k.QuoteAssetVolume),
|
||||
TakerBuyBaseAssetVolume: fixedpoint.MustNewFromString(k.TakerBuyBaseAssetVolume),
|
||||
TakerBuyQuoteAssetVolume: fixedpoint.MustNewFromString(k.TakerBuyQuoteAssetVolume),
|
||||
LastTradeID: 0,
|
||||
NumberOfTrades: uint64(k.TradeNum),
|
||||
Closed: true,
|
||||
})
|
||||
}
|
||||
|
||||
kLines = types.SortKLinesAscending(kLines)
|
||||
return kLines, nil
|
||||
}
|
||||
|
||||
func (e *Exchange) queryFuturesTrades(ctx context.Context, symbol string, options *types.TradeQueryOptions) (trades []types.Trade, err error) {
|
||||
|
||||
var remoteTrades []*futures.AccountTrade
|
||||
req := e.futuresClient.NewListAccountTradeService().
|
||||
Symbol(symbol)
|
||||
if options.Limit > 0 {
|
||||
req.Limit(int(options.Limit))
|
||||
} else {
|
||||
req.Limit(1000)
|
||||
}
|
||||
|
||||
// BINANCE uses inclusive last trade ID
|
||||
if options.LastTradeID > 0 {
|
||||
req.FromID(int64(options.LastTradeID))
|
||||
}
|
||||
|
||||
// The parameter fromId cannot be sent with startTime or endTime.
|
||||
// Mentioned in binance futures docs
|
||||
if options.LastTradeID <= 0 {
|
||||
if options.StartTime != nil && options.EndTime != nil {
|
||||
if options.EndTime.Sub(*options.StartTime) < 24*time.Hour {
|
||||
req.StartTime(options.StartTime.UnixMilli())
|
||||
req.EndTime(options.EndTime.UnixMilli())
|
||||
} else {
|
||||
req.StartTime(options.StartTime.UnixMilli())
|
||||
}
|
||||
} else if options.EndTime != nil {
|
||||
req.EndTime(options.EndTime.UnixMilli())
|
||||
}
|
||||
}
|
||||
|
||||
remoteTrades, err = req.Do(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, t := range remoteTrades {
|
||||
localTrade, err := toGlobalFuturesTrade(*t)
|
||||
if err != nil {
|
||||
log.WithError(err).Errorf("can not convert binance futures trade: %+v", t)
|
||||
continue
|
||||
}
|
||||
|
||||
trades = append(trades, *localTrade)
|
||||
}
|
||||
|
||||
trades = types.SortTradesAscending(trades)
|
||||
return trades, nil
|
||||
}
|
Loading…
Reference in New Issue
Block a user