pull out active order book to the types package

This commit is contained in:
c9s 2020-10-31 19:54:05 +08:00
parent 1eb263de23
commit 14abe3fb7e
8 changed files with 116 additions and 73 deletions

View File

@ -17,7 +17,7 @@ type ExchangeOrderExecutionRouter struct {
sessions map[string]*ExchangeSession
}
func (e *ExchangeOrderExecutionRouter) SubmitOrdersTo(ctx context.Context, session string, orders ...types.SubmitOrder) ([]types.Order, error) {
func (e *ExchangeOrderExecutionRouter) SubmitOrdersTo(ctx context.Context, session string, orders ...types.SubmitOrder) (types.OrderSlice, error) {
es, ok := e.sessions[session]
if !ok {
return nil, errors.Errorf("exchange session %s not found", session)
@ -51,7 +51,7 @@ func (e *ExchangeOrderExecutor) notifySubmitOrders(orders ...types.SubmitOrder)
}
}
func (e *ExchangeOrderExecutor) SubmitOrders(ctx context.Context, orders ...types.SubmitOrder) ([]types.Order, error) {
func (e *ExchangeOrderExecutor) SubmitOrders(ctx context.Context, orders ...types.SubmitOrder) (types.OrderSlice, error) {
formattedOrders, err := formatOrders(orders, e.session)
if err != nil {
return nil, err
@ -81,7 +81,7 @@ type BasicRiskControlOrderExecutor struct {
MaxOrderAmount fixedpoint.Value `json:"maxOrderAmount,omitempty"`
}
func (e *BasicRiskControlOrderExecutor) SubmitOrders(ctx context.Context, orders ...types.SubmitOrder) ([]types.Order, error) {
func (e *BasicRiskControlOrderExecutor) SubmitOrders(ctx context.Context, orders ...types.SubmitOrder) (types.OrderSlice, error) {
var formattedOrders []types.SubmitOrder
for _, order := range orders {
currentPrice, ok := e.session.LastPrice(order.Symbol)

View File

@ -17,7 +17,7 @@ type RiskControlOrderExecutors struct {
BySymbol map[string]*SymbolBasedOrderExecutor `json:"bySymbol,omitempty" yaml:"bySymbol,omitempty"`
}
func (e *RiskControlOrderExecutors) SubmitOrders(ctx context.Context, orders ...types.SubmitOrder) ([]types.Order, error) {
func (e *RiskControlOrderExecutors) SubmitOrders(ctx context.Context, orders ...types.SubmitOrder) (types.OrderSlice, error) {
var symbolOrders = make(map[string][]types.SubmitOrder, len(orders))
for _, order := range orders {
symbolOrders[order.Symbol] = append(symbolOrders[order.Symbol], order)

View File

@ -295,10 +295,10 @@ func (trader *Trader) ReportPnL() *PnLReporterManager {
}
type OrderExecutor interface {
SubmitOrders(ctx context.Context, orders ...types.SubmitOrder) (createdOrders []types.Order, err error)
SubmitOrders(ctx context.Context, orders ...types.SubmitOrder) (createdOrders types.OrderSlice, err error)
}
type OrderExecutionRouter interface {
// SubmitOrderTo submit order to a specific exchange session
SubmitOrdersTo(ctx context.Context, session string, orders ...types.SubmitOrder) (createdOrders []types.Order, err error)
SubmitOrdersTo(ctx context.Context, session string, orders ...types.SubmitOrder) (createdOrders types.OrderSlice, err error)
}

View File

@ -310,7 +310,7 @@ func (e *Exchange) CancelOrders(ctx context.Context, orders ...types.Order) (err
return err2
}
func (e *Exchange) SubmitOrders(ctx context.Context, orders ...types.SubmitOrder) (createdOrders []types.Order, err error) {
func (e *Exchange) SubmitOrders(ctx context.Context, orders ...types.SubmitOrder) (createdOrders types.OrderSlice, err error) {
for _, order := range orders {
orderType, err := toLocalOrderType(order.Type)
if err != nil {

View File

@ -111,7 +111,7 @@ func (e *Exchange) CancelOrders(ctx context.Context, orders ...types.Order) (err
return err2
}
func (e *Exchange) SubmitOrders(ctx context.Context, orders ...types.SubmitOrder) (createdOrders []types.Order, err error) {
func (e *Exchange) SubmitOrders(ctx context.Context, orders ...types.SubmitOrder) (createdOrders types.OrderSlice, err error) {
for _, order := range orders {
orderType, err := toLocalOrderType(order.Type)
if err != nil {

View File

@ -64,8 +64,7 @@ type Strategy struct {
BaseQuantity float64 `json:"baseQuantity"`
activeBidOrders *types.SyncOrderMap
activeAskOrders *types.SyncOrderMap
activeOrders *types.LocalActiveOrderBook
boll *indicator.BOLL
}
@ -84,7 +83,7 @@ func (s *Strategy) updateBidOrders(orderExecutor bbgo.OrderExecutor, session *bb
return
}
var numOrders = s.GridNum - s.activeBidOrders.Len()
var numOrders = s.GridNum - s.activeOrders.NumOfBids()
if numOrders <= 0 {
return
}
@ -113,10 +112,7 @@ func (s *Strategy) updateBidOrders(orderExecutor bbgo.OrderExecutor, session *bb
return
}
for _, o := range orders {
log.Infof("adding order %d to the active bid order pool...", o.OrderID)
s.activeBidOrders.Add(o)
}
s.activeOrders.Add(orders...)
}
func (s *Strategy) updateAskOrders(orderExecutor bbgo.OrderExecutor, session *bbgo.ExchangeSession) {
@ -128,7 +124,7 @@ func (s *Strategy) updateAskOrders(orderExecutor bbgo.OrderExecutor, session *bb
return
}
var numOrders = s.GridNum - s.activeAskOrders.Len()
var numOrders = s.GridNum - s.activeOrders.NumOfAsks()
if numOrders <= 0 {
return
}
@ -157,30 +153,22 @@ func (s *Strategy) updateAskOrders(orderExecutor bbgo.OrderExecutor, session *bb
return
}
for _, o := range orders {
log.Infof("adding order %d to the active ask order pool...", o.OrderID)
s.activeAskOrders.Add(o)
}
log.Infof("adding orders to the active ask order pool...")
s.activeOrders.Add(orders...)
}
func (s *Strategy) updateOrders(orderExecutor bbgo.OrderExecutor, session *bbgo.ExchangeSession) {
log.Infof("checking grid orders, bids=%d asks=%d", s.activeBidOrders.Len(), s.activeAskOrders.Len())
log.Infof("checking grid orders, bids=%d asks=%d", s.activeOrders.Bids.Len(), s.activeOrders.Asks.Len())
for _, o := range s.activeBidOrders.Orders() {
log.Infof("bid order: %d -> %s", o.OrderID, o.Status)
}
s.activeOrders.Print()
for _, o := range s.activeAskOrders.Orders() {
log.Infof("ask order: %d -> %s", o.OrderID, o.Status)
}
if s.activeBidOrders.Len() < s.GridNum {
log.Infof("active bid orders not enough: %d < %d, updating...", s.activeBidOrders.Len(), s.GridNum)
if s.activeOrders.Bids.Len() < s.GridNum {
log.Infof("active bid orders not enough: %d < %d, updating...", s.activeOrders.Bids.Len(), s.GridNum)
s.updateBidOrders(orderExecutor, session)
}
if s.activeAskOrders.Len() < s.GridNum {
log.Infof("active ask orders not enough: %d < %d, updating...", s.activeAskOrders.Len(), s.GridNum)
if s.activeOrders.Asks.Len() < s.GridNum {
log.Infof("active ask orders not enough: %d < %d, updating...", s.activeOrders.Asks.Len(), s.GridNum)
s.updateAskOrders(orderExecutor, session)
}
}
@ -196,9 +184,7 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
})
// we don't persist orders so that we can not clear the previous orders for now. just need time to support this.
// TODO: pull this map out and add mutex lock
s.activeBidOrders = types.NewSyncOrderMap()
s.activeAskOrders = types.NewSyncOrderMap()
s.activeOrders = types.NewLocalActiveOrderBook()
session.Stream.OnOrderUpdate(func(order types.Order) {
log.Infof("received order update: %+v", order)
@ -208,43 +194,16 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
}
switch order.Status {
case types.OrderStatusFilled:
switch order.Side {
case types.SideTypeSell:
// find the filled bid to remove
if filledOrder, ok := s.activeBidOrders.AnyFilled(); ok {
s.activeBidOrders.Delete(filledOrder.OrderID)
s.activeAskOrders.Delete(order.OrderID)
}
case types.SideTypeBuy:
// find the filled ask order to remove
if filledOrder, ok := s.activeAskOrders.AnyFilled(); ok {
s.activeAskOrders.Delete(filledOrder.OrderID)
s.activeBidOrders.Delete(order.OrderID)
}
}
s.activeOrders.WriteOff(order)
case types.OrderStatusCanceled, types.OrderStatusRejected:
log.Infof("order status %s, removing %d from the active order pool...", order.Status, order.OrderID)
switch order.Side {
case types.SideTypeSell:
s.activeAskOrders.Delete(order.OrderID)
case types.SideTypeBuy:
s.activeBidOrders.Delete(order.OrderID)
}
s.activeOrders.Delete(order)
default:
log.Infof("order status %s, updating %d to the active order pool...", order.Status, order.OrderID)
switch order.Side {
case types.SideTypeSell:
s.activeAskOrders.Add(order)
case types.SideTypeBuy:
s.activeBidOrders.Add(order)
}
s.activeOrders.Add(order)
}
})
@ -255,13 +214,7 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
s.updateOrders(orderExecutor, session)
defer func() {
for _, o := range s.activeBidOrders.Orders() {
_ = session.Exchange.CancelOrders(context.Background(), o)
}
for _, o := range s.activeAskOrders.Orders() {
_ = session.Exchange.CancelOrders(context.Background(), o)
}
_ = session.Exchange.CancelOrders(context.Background(), s.activeOrders.Orders()...)
}()
for {

90
pkg/types/active_book.go Normal file
View File

@ -0,0 +1,90 @@
package types
import log "github.com/sirupsen/logrus"
// LocalActiveOrderBook manages the local active order books.
type LocalActiveOrderBook struct {
Bids *SyncOrderMap
Asks *SyncOrderMap
}
func NewLocalActiveOrderBook() *LocalActiveOrderBook {
return &LocalActiveOrderBook{
Bids: NewSyncOrderMap(),
Asks: NewSyncOrderMap(),
}
}
func (b *LocalActiveOrderBook) Print() {
for _, o := range b.Bids.Orders() {
log.Infof("bid order: %d -> %s", o.OrderID, o.Status)
}
for _, o := range b.Asks.Orders() {
log.Infof("ask order: %d -> %s", o.OrderID, o.Status)
}
}
func (b *LocalActiveOrderBook) Add(orders ...Order) {
for _, order := range orders {
switch order.Side {
case SideTypeBuy:
b.Bids.Add(order)
case SideTypeSell:
b.Asks.Add(order)
}
}
}
func (b *LocalActiveOrderBook) NumOfBids() int {
return b.Bids.Len()
}
func (b *LocalActiveOrderBook) NumOfAsks() int {
return b.Asks.Len()
}
func (b *LocalActiveOrderBook) Delete(order Order) {
switch order.Side {
case SideTypeBuy:
b.Bids.Delete(order.OrderID)
case SideTypeSell:
b.Asks.Delete(order.OrderID)
}
}
// WriteOff writes off the filled order on the opposite side.
// This method does not write off order by order amount or order quantity.
func (b *LocalActiveOrderBook) WriteOff(order Order) bool {
if order.Status != OrderStatusFilled {
return false
}
switch order.Side {
case SideTypeSell:
// find the filled bid to remove
if filledOrder, ok := b.Bids.AnyFilled(); ok {
b.Bids.Delete(filledOrder.OrderID)
b.Asks.Delete(order.OrderID)
return true
}
case SideTypeBuy:
// find the filled ask order to remove
if filledOrder, ok := b.Asks.AnyFilled(); ok {
b.Asks.Delete(filledOrder.OrderID)
b.Bids.Delete(order.OrderID)
return true
}
}
return false
}
func (b *LocalActiveOrderBook) Orders() OrderSlice {
return append(b.Asks.Orders(), b.Bids.Orders()...)
}

View File

@ -54,7 +54,7 @@ type Exchange interface {
QueryWithdrawHistory(ctx context.Context, asset string, since, until time.Time) (allWithdraws []Withdraw, err error)
SubmitOrders(ctx context.Context, orders ...SubmitOrder) (createdOrders []Order, err error)
SubmitOrders(ctx context.Context, orders ...SubmitOrder) (createdOrders OrderSlice, err error)
QueryOpenOrders(ctx context.Context, symbol string) (orders []Order, err error)