bbgo_origin/pkg/bbgo/order_store.go

152 lines
2.8 KiB
Go
Raw Normal View History

2020-11-11 15:18:53 +00:00
package bbgo
import (
"sync"
"github.com/c9s/bbgo/pkg/types"
)
type OrderStore struct {
// any created orders for tracking trades
mu sync.Mutex
orders map[uint64]types.Order
2021-01-21 06:51:37 +00:00
Symbol string
RemoveCancelled bool
RemoveFilled bool
AddOrderUpdate bool
2020-11-11 15:18:53 +00:00
}
2021-01-21 06:51:37 +00:00
func NewOrderStore(symbol string) *OrderStore {
2020-11-11 15:18:53 +00:00
return &OrderStore{
2021-01-21 06:51:37 +00:00
Symbol: symbol,
2020-11-11 15:18:53 +00:00
orders: make(map[uint64]types.Order),
}
}
func (s *OrderStore) AllFilled() bool {
s.mu.Lock()
defer s.mu.Unlock()
// If any order is new or partially filled, we return false
for _, o := range s.orders {
switch o.Status {
case types.OrderStatusCanceled, types.OrderStatusRejected:
continue
case types.OrderStatusNew, types.OrderStatusPartiallyFilled:
return false
case types.OrderStatusFilled:
// do nothing for the filled order
}
}
// If we pass through the for loop, then all the orders filled
return true
}
func (s *OrderStore) NumOfOrders() (num int) {
s.mu.Lock()
num = len(s.orders)
s.mu.Unlock()
return num
}
2021-01-24 11:07:32 +00:00
func (s *OrderStore) Orders() (orders []types.Order) {
s.mu.Lock()
defer s.mu.Unlock()
for _, o := range s.orders {
orders = append(orders, o)
}
return orders
}
2020-11-17 00:53:22 +00:00
func (s *OrderStore) Exists(oID uint64) (ok bool) {
2020-11-11 15:18:53 +00:00
s.mu.Lock()
defer s.mu.Unlock()
2020-11-17 00:53:22 +00:00
_, ok = s.orders[oID]
2020-11-11 15:18:53 +00:00
return ok
}
// Get a single order from the order store by order ID
// Should check ok to make sure the order is returned successfully
func (s *OrderStore) Get(oID uint64) (order types.Order, ok bool) {
s.mu.Lock()
defer s.mu.Unlock()
order, ok = s.orders[oID]
return order, ok
}
2020-11-11 15:18:53 +00:00
func (s *OrderStore) Add(orders ...types.Order) {
s.mu.Lock()
defer s.mu.Unlock()
for _, o := range orders {
s.orders[o.OrderID] = o
}
}
func (s *OrderStore) Remove(o types.Order) {
s.mu.Lock()
defer s.mu.Unlock()
delete(s.orders, o.OrderID)
}
func (s *OrderStore) Update(o types.Order) bool {
s.mu.Lock()
defer s.mu.Unlock()
old, ok := s.orders[o.OrderID]
2020-11-11 15:18:53 +00:00
if ok {
o.Tag = old.Tag
2020-11-11 15:18:53 +00:00
s.orders[o.OrderID] = o
}
return ok
}
func (s *OrderStore) BindStream(stream types.Stream) {
2021-01-21 06:51:37 +00:00
hasSymbol := s.Symbol != ""
stream.OnOrderUpdate(func(order types.Order) {
// if we have symbol defined, we should filter out the orders that we are not interested in
if hasSymbol && order.Symbol != s.Symbol {
return
2021-01-21 06:51:37 +00:00
}
s.handleOrderUpdate(order)
2021-01-21 06:51:37 +00:00
})
2020-11-11 15:18:53 +00:00
}
func (s *OrderStore) handleOrderUpdate(order types.Order) {
switch order.Status {
case types.OrderStatusNew, types.OrderStatusPartiallyFilled, types.OrderStatusFilled:
if s.AddOrderUpdate {
s.Add(order)
} else {
s.Update(order)
}
2020-11-11 15:18:53 +00:00
if s.RemoveFilled && order.Status == types.OrderStatusFilled {
s.Remove(order)
}
case types.OrderStatusCanceled:
if s.RemoveCancelled {
2021-12-26 07:47:39 +00:00
s.Remove(order)
} else if order.ExecutedQuantity.IsZero() {
s.Remove(order)
}
case types.OrderStatusRejected:
2020-11-11 15:18:53 +00:00
s.Remove(order)
}
}