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
|
2020-11-17 07:53:46 +00:00
|
|
|
|
2021-01-21 06:51:37 +00:00
|
|
|
Symbol string
|
2020-11-17 07:53:46 +00:00
|
|
|
RemoveCancelled bool
|
2021-05-20 16:07:43 +00:00
|
|
|
RemoveFilled bool
|
2021-01-24 12:13:05 +00:00
|
|
|
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),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-16 05:39:06 +00:00
|
|
|
func (s *OrderStore) AllFilled() bool {
|
2021-12-26 16:51:57 +00:00
|
|
|
s.mu.Lock()
|
|
|
|
defer s.mu.Unlock()
|
|
|
|
|
2021-10-16 05:39:06 +00:00
|
|
|
// 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
|
|
|
|
}
|
|
|
|
|
2021-05-20 16:07:43 +00:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
|
|
|
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()
|
|
|
|
|
|
|
|
_, ok := s.orders[o.OrderID]
|
|
|
|
if ok {
|
|
|
|
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) {
|
2021-12-26 16:51:57 +00:00
|
|
|
// 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
|
|
|
}
|
2021-12-26 16:51:57 +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 {
|
2021-01-24 12:13:05 +00:00
|
|
|
|
|
|
|
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
|
|
|
|
2021-05-20 16:07:43 +00:00
|
|
|
if s.RemoveFilled && order.Status == types.OrderStatusFilled {
|
|
|
|
s.Remove(order)
|
|
|
|
}
|
|
|
|
|
2020-11-17 07:53:46 +00:00
|
|
|
case types.OrderStatusCanceled:
|
|
|
|
if s.RemoveCancelled {
|
2021-12-26 07:47:39 +00:00
|
|
|
s.Remove(order)
|
2021-12-30 17:55:22 +00:00
|
|
|
} else if order.ExecutedQuantity == 0.0 {
|
|
|
|
s.Remove(order)
|
2020-11-17 07:53:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
case types.OrderStatusRejected:
|
2020-11-11 15:18:53 +00:00
|
|
|
s.Remove(order)
|
|
|
|
}
|
|
|
|
}
|