2020-10-25 16:26:17 +00:00
|
|
|
package bbgo
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
|
|
|
|
"github.com/pkg/errors"
|
|
|
|
|
2020-10-26 10:17:18 +00:00
|
|
|
"github.com/c9s/bbgo/pkg/fixedpoint"
|
2020-10-25 16:26:17 +00:00
|
|
|
"github.com/c9s/bbgo/pkg/types"
|
|
|
|
)
|
|
|
|
|
|
|
|
type ExchangeOrderExecutionRouter struct {
|
|
|
|
Notifiability
|
|
|
|
|
|
|
|
sessions map[string]*ExchangeSession
|
|
|
|
}
|
|
|
|
|
|
|
|
func (e *ExchangeOrderExecutionRouter) SubmitOrdersTo(ctx context.Context, session string, orders ...types.SubmitOrder) ([]types.Order, error) {
|
|
|
|
es, ok := e.sessions[session]
|
|
|
|
if !ok {
|
|
|
|
return nil, errors.Errorf("exchange session %s not found", session)
|
|
|
|
}
|
|
|
|
|
2020-10-26 10:17:18 +00:00
|
|
|
formattedOrders, err := formatOrders(orders, es)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
2020-10-25 16:26:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// e.Notify(":memo: Submitting order to %s %s %s %s with quantity: %s", session, order.Symbol, order.Type, order.Side, order.QuantityString, order)
|
|
|
|
return es.Exchange.SubmitOrders(ctx, formattedOrders...)
|
|
|
|
}
|
|
|
|
|
|
|
|
// ExchangeOrderExecutor is an order executor wrapper for single exchange instance.
|
|
|
|
type ExchangeOrderExecutor struct {
|
2020-10-26 10:17:18 +00:00
|
|
|
Notifiability `json:"-"`
|
2020-10-25 16:26:17 +00:00
|
|
|
|
2020-10-26 10:17:18 +00:00
|
|
|
session *ExchangeSession `json:"-"`
|
2020-10-25 16:26:17 +00:00
|
|
|
}
|
|
|
|
|
2020-10-26 10:17:18 +00:00
|
|
|
func (e *ExchangeOrderExecutor) SubmitOrders(ctx context.Context, orders ...types.SubmitOrder) ([]types.Order, error) {
|
|
|
|
formattedOrders, err := formatOrders(orders, e.session)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// e.Notify(":memo: Submitting %s %s %s order with quantity: %s", order.Symbol, order.Type, order.Side, order.QuantityString, order)
|
|
|
|
|
|
|
|
return e.session.Exchange.SubmitOrders(ctx, formattedOrders...)
|
2020-10-25 16:26:17 +00:00
|
|
|
}
|
|
|
|
|
2020-10-26 10:17:18 +00:00
|
|
|
type RiskControlOrderExecutor struct {
|
|
|
|
Notifiability `json:"-"`
|
|
|
|
|
|
|
|
MinQuoteBalance fixedpoint.Value `json:"minQuoteBalance,omitempty"`
|
|
|
|
MaxAssetBalance fixedpoint.Value `json:"maxBaseAssetBalance,omitempty"`
|
|
|
|
MinAssetBalance fixedpoint.Value `json:"minBaseAssetBalance,omitempty"`
|
|
|
|
MaxOrderAmount fixedpoint.Value `json:"maxOrderAmount,omitempty"`
|
|
|
|
|
|
|
|
session *ExchangeSession `json:"-"`
|
|
|
|
}
|
|
|
|
|
|
|
|
func (e *RiskControlOrderExecutor) SubmitOrders(ctx context.Context, orders ...types.SubmitOrder) ([]types.Order, error) {
|
|
|
|
formattedOrders, err := formatOrders(orders, e.session)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// e.Notify(":memo: Submitting %s %s %s order with quantity: %s", order.Symbol, order.Type, order.Side, order.QuantityString, order)
|
|
|
|
return e.session.Exchange.SubmitOrders(ctx, formattedOrders...)
|
|
|
|
}
|
|
|
|
|
|
|
|
func formatOrders(orders []types.SubmitOrder, session *ExchangeSession) (formattedOrders []types.SubmitOrder, err error) {
|
2020-10-25 16:26:17 +00:00
|
|
|
for _, order := range orders {
|
2020-10-26 10:17:18 +00:00
|
|
|
market, ok := session.Market(order.Symbol)
|
2020-10-25 16:26:17 +00:00
|
|
|
if !ok {
|
2020-10-26 10:17:18 +00:00
|
|
|
return formattedOrders, errors.Errorf("market is not defined: %s", order.Symbol)
|
2020-10-25 16:26:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
order.Market = market
|
|
|
|
order.PriceString = market.FormatPrice(order.Price)
|
|
|
|
order.QuantityString = market.FormatVolume(order.Quantity)
|
|
|
|
formattedOrders = append(formattedOrders, order)
|
|
|
|
}
|
|
|
|
|
2020-10-26 10:17:18 +00:00
|
|
|
return formattedOrders, err
|
2020-10-25 16:26:17 +00:00
|
|
|
}
|