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) {
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)
73 // DelOrder mark the order has been deleted in order book
74 func (o *OrderBook) DelOrder(order *common.Order) {
75 o.arrivalDelOrders.Store(order.Key(), order)
78 // PeekOrder return the next lowest order of given trade pair
79 func (o *OrderBook) PeekOrder(tradePair *common.TradePair) *common.Order {
80 if len(o.getDBOrders(tradePair.Key())) == 0 {
81 o.extendDBOrders(tradePair)
84 var nextOrder *common.Order
85 orders := o.getDBOrders(tradePair.Key())
87 nextOrder = orders[len(orders)-1]
90 if nextOrder != nil && o.getArrivalDelOrders(nextOrder.Key()) != nil {
91 o.dbOrders.Store(tradePair.Key(), orders[0:len(orders)-1])
92 return o.PeekOrder(tradePair)
95 arrivalOrder := o.peekArrivalOrder(tradePair)
96 if nextOrder == nil || (arrivalOrder != nil && arrivalOrder.Cmp(nextOrder) < 0) {
97 nextOrder = arrivalOrder
102 // PeekOrders return the next lowest orders by given array of trade pairs
103 func (o *OrderBook) PeekOrders(tradePairs []*common.TradePair) []*common.Order {
104 var orders []*common.Order
105 for _, tradePair := range tradePairs {
106 order := o.PeekOrder(tradePair)
111 orders = append(orders, order)
116 // PopOrder delete the next lowest order of given trade pair
117 func (o *OrderBook) PopOrder(tradePair *common.TradePair) {
118 order := o.PeekOrder(tradePair)
123 orders := o.getDBOrders(tradePair.Key())
124 if len(orders) != 0 && orders[len(orders)-1].Key() == order.Key() {
125 o.dbOrders.Store(tradePair.Key(), orders[0:len(orders)-1])
129 arrivalOrders := o.getArrivalAddOrders(tradePair.Key())
130 if len(arrivalOrders) != 0 && arrivalOrders[len(arrivalOrders)-1].Key() == order.Key() {
131 o.arrivalAddOrders.Store(tradePair.Key(), arrivalOrders[0:len(arrivalOrders)-1])
135 // PopOrders delete the next lowest orders by given trade pairs
136 func (o *OrderBook) PopOrders(tradePairs []*common.TradePair) []*common.Order {
137 var orders []*common.Order
138 for _, tradePair := range tradePairs {
139 o.PopOrder(tradePair)
144 func (o *OrderBook) getDBOrders(tradePairKey string) []*common.Order {
145 if orders, ok := o.dbOrders.Load(tradePairKey); ok {
146 return orders.([]*common.Order)
148 return []*common.Order{}
151 func (o *OrderBook) getArrivalAddOrders(tradePairKey string) []*common.Order {
152 if orders, ok := o.arrivalAddOrders.Load(tradePairKey); ok {
153 return orders.([]*common.Order)
155 return []*common.Order{}
158 func (o *OrderBook) getArrivalDelOrders(orderKey string) *common.Order {
159 if order, ok := o.arrivalDelOrders.Load(orderKey); ok {
160 return order.(*common.Order)
165 func (o *OrderBook) extendDBOrders(tradePair *common.TradePair) {
166 iterator, ok := o.orderIterators.Load(tradePair.Key())
168 iterator = database.NewOrderIterator(o.movStore, tradePair)
169 o.orderIterators.Store(tradePair.Key(), iterator)
172 nextOrders := iterator.(*database.OrderIterator).NextBatch()
173 orders := o.getDBOrders(tradePair.Key())
174 for i := len(nextOrders) - 1; i >= 0; i-- {
175 orders = append(orders, nextOrders[i])
177 o.dbOrders.Store(tradePair.Key(), orders)
180 func (o *OrderBook) peekArrivalOrder(tradePair *common.TradePair) *common.Order {
181 orders := o.getArrivalAddOrders(tradePair.Key())
182 delPos := len(orders)
183 for i := delPos - 1; i >= 0; i-- {
184 if o.getArrivalDelOrders(orders[i].Key()) != nil {
191 if delPos < len(orders) {
192 orders = orders[:delPos]
193 o.arrivalAddOrders.Store(tradePair.Key(), orders)
196 if size := len(orders); size > 0 {
197 return orders[size-1]