mirror of
https://github.com/c9s/bbgo.git
synced 2024-11-10 09:11:55 +00:00
Merge pull request #359 from austin362667/submit-order
binance: support submit futures order
This commit is contained in:
commit
7fcbc1edcf
|
@ -161,6 +161,10 @@ type ExchangeSession struct {
|
||||||
IsolatedMargin bool `json:"isolatedMargin,omitempty" yaml:"isolatedMargin,omitempty"`
|
IsolatedMargin bool `json:"isolatedMargin,omitempty" yaml:"isolatedMargin,omitempty"`
|
||||||
IsolatedMarginSymbol string `json:"isolatedMarginSymbol,omitempty" yaml:"isolatedMarginSymbol,omitempty"`
|
IsolatedMarginSymbol string `json:"isolatedMarginSymbol,omitempty" yaml:"isolatedMarginSymbol,omitempty"`
|
||||||
|
|
||||||
|
Futures bool `json:"futures,omitempty" yaml:"futures"`
|
||||||
|
IsolatedFutures bool `json:"isolatedFutures,omitempty" yaml:"isolatedFutures,omitempty"`
|
||||||
|
IsolatedFuturesSymbol string `json:"isolatedFuturesSymbol,omitempty" yaml:"isolatedFuturesSymbol,omitempty"`
|
||||||
|
|
||||||
// ---------------------------
|
// ---------------------------
|
||||||
// Runtime fields
|
// Runtime fields
|
||||||
// ---------------------------
|
// ---------------------------
|
||||||
|
@ -691,6 +695,19 @@ func InitExchangeSession(name string, session *ExchangeSession) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if session.Futures {
|
||||||
|
futuresExchange, ok := exchange.(types.FuturesExchange)
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("exchange %s does not support futures", exchangeName)
|
||||||
|
}
|
||||||
|
|
||||||
|
if session.IsolatedFutures {
|
||||||
|
futuresExchange.UseIsolatedFutures(session.IsolatedFuturesSymbol)
|
||||||
|
} else {
|
||||||
|
futuresExchange.UseFutures()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
session.Name = name
|
session.Name = name
|
||||||
session.Notifiability = Notifiability{
|
session.Notifiability = Notifiability{
|
||||||
SymbolChannelRouter: NewPatternChannelRouter(nil),
|
SymbolChannelRouter: NewPatternChannelRouter(nil),
|
||||||
|
|
|
@ -161,6 +161,28 @@ func toLocalOrderType(orderType types.OrderType) (binance.OrderType, error) {
|
||||||
return "", fmt.Errorf("can not convert to local order, order type %s not supported", orderType)
|
return "", fmt.Errorf("can not convert to local order, order type %s not supported", orderType)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func toLocalFuturesOrderType(orderType types.OrderType) (futures.OrderType, error) {
|
||||||
|
switch orderType {
|
||||||
|
|
||||||
|
// case types.OrderTypeLimitMaker:
|
||||||
|
// return futures.OrderTypeLimitMaker, nil //TODO
|
||||||
|
|
||||||
|
case types.OrderTypeLimit:
|
||||||
|
return futures.OrderTypeLimit, nil
|
||||||
|
|
||||||
|
// case types.OrderTypeStopLimit:
|
||||||
|
// return futures.OrderTypeStopLossLimit, nil //TODO
|
||||||
|
|
||||||
|
// case types.OrderTypeStopMarket:
|
||||||
|
// return futures.OrderTypeStopLoss, nil //TODO
|
||||||
|
|
||||||
|
case types.OrderTypeMarket:
|
||||||
|
return futures.OrderTypeMarket, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return "", fmt.Errorf("can not convert to local order, order type %s not supported", orderType)
|
||||||
|
}
|
||||||
|
|
||||||
func toGlobalOrders(binanceOrders []*binance.Order) (orders []types.Order, err error) {
|
func toGlobalOrders(binanceOrders []*binance.Order) (orders []types.Order, err error) {
|
||||||
for _, binanceOrder := range binanceOrders {
|
for _, binanceOrder := range binanceOrders {
|
||||||
order, err := toGlobalOrder(binanceOrder, false)
|
order, err := toGlobalOrder(binanceOrder, false)
|
||||||
|
@ -174,6 +196,19 @@ func toGlobalOrders(binanceOrders []*binance.Order) (orders []types.Order, err e
|
||||||
return orders, err
|
return orders, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func toGlobalFuturesOrders(futuresOrders []*futures.Order) (orders []types.Order, err error) {
|
||||||
|
for _, futuresOrder := range futuresOrders {
|
||||||
|
order, err := toGlobalFuturesOrder(futuresOrder, false)
|
||||||
|
if err != nil {
|
||||||
|
return orders, err
|
||||||
|
}
|
||||||
|
|
||||||
|
orders = append(orders, *order)
|
||||||
|
}
|
||||||
|
|
||||||
|
return orders, err
|
||||||
|
}
|
||||||
|
|
||||||
func toGlobalOrder(binanceOrder *binance.Order, isMargin bool) (*types.Order, error) {
|
func toGlobalOrder(binanceOrder *binance.Order, isMargin bool) (*types.Order, error) {
|
||||||
return &types.Order{
|
return &types.Order{
|
||||||
SubmitOrder: types.SubmitOrder{
|
SubmitOrder: types.SubmitOrder{
|
||||||
|
@ -197,6 +232,31 @@ func toGlobalOrder(binanceOrder *binance.Order, isMargin bool) (*types.Order, er
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func toGlobalFuturesOrder(futuresOrder *futures.Order, isMargin bool) (*types.Order, error) {
|
||||||
|
return &types.Order{
|
||||||
|
SubmitOrder: types.SubmitOrder{
|
||||||
|
ClientOrderID: futuresOrder.ClientOrderID,
|
||||||
|
Symbol: futuresOrder.Symbol,
|
||||||
|
Side: toGlobalFuturesSideType(futuresOrder.Side),
|
||||||
|
Type: toGlobalFuturesOrderType(futuresOrder.Type),
|
||||||
|
ReduceOnly: futuresOrder.ReduceOnly,
|
||||||
|
ClosePosition: futuresOrder.ClosePosition,
|
||||||
|
Quantity: util.MustParseFloat(futuresOrder.OrigQuantity),
|
||||||
|
Price: util.MustParseFloat(futuresOrder.Price),
|
||||||
|
TimeInForce: string(futuresOrder.TimeInForce),
|
||||||
|
},
|
||||||
|
Exchange: types.ExchangeBinance,
|
||||||
|
// IsWorking: futuresOrder.IsWorking,
|
||||||
|
OrderID: uint64(futuresOrder.OrderID),
|
||||||
|
Status: toGlobalFuturesOrderStatus(futuresOrder.Status),
|
||||||
|
ExecutedQuantity: util.MustParseFloat(futuresOrder.ExecutedQuantity),
|
||||||
|
CreationTime: types.Time(millisecondTime(futuresOrder.Time)),
|
||||||
|
UpdateTime: types.Time(millisecondTime(futuresOrder.UpdateTime)),
|
||||||
|
IsMargin: isMargin,
|
||||||
|
// IsIsolated: futuresOrder.IsIsolated,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
func millisecondTime(t int64) time.Time {
|
func millisecondTime(t int64) time.Time {
|
||||||
return time.Unix(0, t*int64(time.Millisecond))
|
return time.Unix(0, t*int64(time.Millisecond))
|
||||||
}
|
}
|
||||||
|
|
|
@ -600,6 +600,95 @@ func (e *Exchange) submitMarginOrder(ctx context.Context, order types.SubmitOrde
|
||||||
return createdOrder, err
|
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))
|
||||||
|
|
||||||
|
clientOrderID := newSpotClientOrderID(order.ClientOrderID)
|
||||||
|
if len(clientOrderID) > 0 {
|
||||||
|
req.NewClientOrderID(clientOrderID)
|
||||||
|
}
|
||||||
|
|
||||||
|
// use response result format
|
||||||
|
req.NewOrderResponseType(futures.NewOrderRespTypeRESULT)
|
||||||
|
// if e.IsIsolatedFutures {
|
||||||
|
// req.IsIsolated(e.IsIsolatedFutures)
|
||||||
|
// }
|
||||||
|
|
||||||
|
if len(order.QuantityString) > 0 {
|
||||||
|
req.Quantity(order.QuantityString)
|
||||||
|
} else if order.Market.Symbol != "" {
|
||||||
|
req.Quantity(order.Market.FormatQuantity(order.Quantity))
|
||||||
|
} else {
|
||||||
|
req.Quantity(strconv.FormatFloat(order.Quantity, 'f', 8, 64))
|
||||||
|
}
|
||||||
|
|
||||||
|
// set price field for limit orders
|
||||||
|
switch order.Type {
|
||||||
|
case types.OrderTypeStopLimit, types.OrderTypeLimit, types.OrderTypeLimitMaker:
|
||||||
|
if len(order.PriceString) > 0 {
|
||||||
|
req.Price(order.PriceString)
|
||||||
|
} else if order.Market.Symbol != "" {
|
||||||
|
req.Price(order.Market.FormatPrice(order.Price))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// set stop price
|
||||||
|
switch order.Type {
|
||||||
|
|
||||||
|
case types.OrderTypeStopLimit, types.OrderTypeStopMarket:
|
||||||
|
if len(order.StopPriceString) == 0 {
|
||||||
|
return nil, fmt.Errorf("stop price string can not be empty")
|
||||||
|
}
|
||||||
|
|
||||||
|
req.StopPrice(order.StopPriceString)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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.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,
|
||||||
|
// CummulativeQuoteQuantity: response.CummulativeQuoteQuantity,
|
||||||
|
Status: response.Status,
|
||||||
|
TimeInForce: response.TimeInForce,
|
||||||
|
Type: response.Type,
|
||||||
|
Side: response.Side,
|
||||||
|
// UpdateTime: response.TransactTime,
|
||||||
|
// Time: response.TransactTime,
|
||||||
|
// IsIsolated: response.IsIsolated,
|
||||||
|
}, true)
|
||||||
|
|
||||||
|
return createdOrder, err
|
||||||
|
}
|
||||||
|
|
||||||
// BBGO is a broker on Binance
|
// BBGO is a broker on Binance
|
||||||
const spotBrokerID = "NSUYEBKM"
|
const spotBrokerID = "NSUYEBKM"
|
||||||
|
|
||||||
|
@ -725,6 +814,8 @@ func (e *Exchange) SubmitOrders(ctx context.Context, orders ...types.SubmitOrder
|
||||||
var createdOrder *types.Order
|
var createdOrder *types.Order
|
||||||
if e.IsMargin {
|
if e.IsMargin {
|
||||||
createdOrder, err = e.submitMarginOrder(ctx, order)
|
createdOrder, err = e.submitMarginOrder(ctx, order)
|
||||||
|
} else if e.IsFutures {
|
||||||
|
createdOrder, err = e.submitFuturesOrder(ctx, order)
|
||||||
} else {
|
} else {
|
||||||
createdOrder, err = e.submitSpotOrder(ctx, order)
|
createdOrder, err = e.submitSpotOrder(ctx, order)
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,11 +4,12 @@ import "github.com/c9s/bbgo/pkg/fixedpoint"
|
||||||
|
|
||||||
type FuturesExchange interface {
|
type FuturesExchange interface {
|
||||||
UseFutures()
|
UseFutures()
|
||||||
|
UseIsolatedFutures(symbol string)
|
||||||
GetFuturesSettings() FuturesSettings
|
GetFuturesSettings() FuturesSettings
|
||||||
}
|
}
|
||||||
|
|
||||||
type FuturesSettings struct {
|
type FuturesSettings struct {
|
||||||
IsFutures bool
|
IsFutures bool
|
||||||
IsIsolatedFutures bool
|
IsIsolatedFutures bool
|
||||||
IsolatedFuturesSymbol string
|
IsolatedFuturesSymbol string
|
||||||
}
|
}
|
||||||
|
@ -25,10 +26,8 @@ func (s *FuturesSettings) UseIsolatedFutures(symbol string) {
|
||||||
s.IsFutures = true
|
s.IsFutures = true
|
||||||
s.IsIsolatedFutures = true
|
s.IsIsolatedFutures = true
|
||||||
s.IsolatedFuturesSymbol = symbol
|
s.IsolatedFuturesSymbol = symbol
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
type MarginExchange interface {
|
type MarginExchange interface {
|
||||||
UseMargin()
|
UseMargin()
|
||||||
UseIsolatedMargin(symbol string)
|
UseIsolatedMargin(symbol string)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user