7 "github.com/bytom/vapor/application/mov/common"
8 "github.com/bytom/vapor/application/mov/database"
11 // OrderBook is used to handle the mov orders in memory like stack
12 type OrderBook struct {
13 movStore database.MovStore
14 // key of tradePair -> []order
16 // key of tradePair -> iterator
17 orderIterators *sync.Map
19 // key of tradePair -> []order
20 arrivalAddOrders *sync.Map
21 // key of order -> order
22 arrivalDelOrders *sync.Map
25 func arrangeArrivalAddOrders(orders []*common.Order) *sync.Map {
26 orderMap := make(map[string][]*common.Order)
27 for _, order := range orders {
28 orderMap[order.TradePair().Key()] = append(orderMap[order.TradePair().Key()], order)
31 arrivalOrderMap := &sync.Map{}
32 for key, orders := range orderMap {
33 sort.Sort(sort.Reverse(common.OrderSlice(orders)))
34 arrivalOrderMap.Store(key, orders)
36 return arrivalOrderMap
39 func arrangeArrivalDelOrders(orders []*common.Order) *sync.Map {
40 arrivalDelOrderMap := &sync.Map{}
41 for _, order := range orders {
42 arrivalDelOrderMap.Store(order.Key(), order)
44 return arrivalDelOrderMap
47 // NewOrderBook create a new OrderBook object
48 func NewOrderBook(movStore database.MovStore, arrivalAddOrders, arrivalDelOrders []*common.Order) *OrderBook {
51 dbOrders: &sync.Map{},
52 orderIterators: &sync.Map{},
54 arrivalAddOrders: arrangeArrivalAddOrders(arrivalAddOrders),
55 arrivalDelOrders: arrangeArrivalDelOrders(arrivalDelOrders),
59 // AddOrder add the in memory temp order to order table, because temp order is what left for the
60 // partial trade order, so the price should be lowest.
61 func (o *OrderBook) AddOrder(order *common.Order) error {
62 tradePairKey := order.TradePair().Key()
63 orders := o.getArrivalAddOrders(tradePairKey)
64 // use binary search to find the insert position
65 i := sort.Search(len(orders), func(i int) bool { return order.Cmp(orders[i]) > 0 })
66 orders = append(orders, order)
67 copy(orders[i+1:], orders[i:])
70 o.arrivalAddOrders.Store(tradePairKey, orders)
74 // DelOrder mark the order has been deleted in order book
75 func (o *OrderBook) DelOrder(order *common.Order) {
76 o.arrivalDelOrders.Store(order.Key(), order)
79 // PeekOrder return the next lowest order of given trade pair
80 func (o *OrderBook) PeekOrder(tradePair *common.TradePair) *common.Order {
81 if len(o.getDBOrders(tradePair.Key())) == 0 {
82 o.extendDBOrders(tradePair)
85 var nextOrder *common.Order
86 orders := o.getDBOrders(tradePair.Key())
88 nextOrder = orders[len(orders)-1]
91 if nextOrder != nil && o.getArrivalDelOrders(nextOrder.Key()) != nil {
92 o.dbOrders.Store(tradePair.Key(), orders[0:len(orders)-1])
93 return o.PeekOrder(tradePair)
96 arrivalOrder := o.peekArrivalOrder(tradePair)
97 if nextOrder == nil || (arrivalOrder != nil && arrivalOrder.Cmp(nextOrder) < 0) {
98 nextOrder = arrivalOrder
103 // PeekOrders return the next lowest orders by given array of trade pairs
104 func (o *OrderBook) PeekOrders(tradePairs []*common.TradePair) []*common.Order {
105 var orders []*common.Order
106 for _, tradePair := range tradePairs {
107 order := o.PeekOrder(tradePair)
112 orders = append(orders, order)
117 // PopOrder delete the next lowest order of given trade pair
118 func (o *OrderBook) PopOrder(tradePair *common.TradePair) {
119 order := o.PeekOrder(tradePair)
124 orders := o.getDBOrders(tradePair.Key())
125 if len(orders) != 0 && orders[len(orders)-1].Key() == order.Key() {
126 o.dbOrders.Store(tradePair.Key(), orders[0:len(orders)-1])
130 arrivalOrders := o.getArrivalAddOrders(tradePair.Key())
131 if len(arrivalOrders) != 0 && arrivalOrders[len(arrivalOrders)-1].Key() == order.Key() {
132 o.arrivalAddOrders.Store(tradePair.Key(), arrivalOrders[0:len(arrivalOrders)-1])
136 // PopOrders delete the next lowest orders by given trade pairs
137 func (o *OrderBook) PopOrders(tradePairs []*common.TradePair) []*common.Order {
138 var orders []*common.Order
139 for _, tradePair := range tradePairs {
140 o.PopOrder(tradePair)
145 func (o *OrderBook) getDBOrders(tradePairKey string) []*common.Order {
146 if orders, ok := o.dbOrders.Load(tradePairKey); ok {
147 return orders.([]*common.Order)
149 return []*common.Order{}
152 func (o *OrderBook) getArrivalAddOrders(tradePairKey string) []*common.Order {
153 if orders, ok := o.arrivalAddOrders.Load(tradePairKey); ok {
154 return orders.([]*common.Order)
156 return []*common.Order{}
159 func (o *OrderBook) getArrivalDelOrders(orderKey string) *common.Order {
160 if order, ok := o.arrivalDelOrders.Load(orderKey); ok {
161 return order.(*common.Order)
166 func (o *OrderBook) extendDBOrders(tradePair *common.TradePair) {
167 iterator, ok := o.orderIterators.Load(tradePair.Key())
169 iterator = database.NewOrderIterator(o.movStore, tradePair)
170 o.orderIterators.Store(tradePair.Key(), iterator)
173 nextOrders := iterator.(*database.OrderIterator).NextBatch()
174 orders := o.getDBOrders(tradePair.Key())
175 for i := len(nextOrders) - 1; i >= 0; i-- {
176 orders = append(orders, nextOrders[i])
178 o.dbOrders.Store(tradePair.Key(), orders)
181 func (o *OrderBook) peekArrivalOrder(tradePair *common.TradePair) *common.Order {
182 orders := o.getArrivalAddOrders(tradePair.Key())
183 delPos := len(orders)
184 for i := delPos - 1; i >= 0; i-- {
185 if o.getArrivalDelOrders(orders[i].Key()) != nil {
192 if delPos < len(orders) {
193 orders = orders[:delPos]
194 o.arrivalAddOrders.Store(tradePair.Key(), orders)
197 if size := len(orders); size > 0 {
198 return orders[size-1]