OSDN Git Service

Merge pull request #473 from Bytom/master
[bytom/vapor.git] / application / mov / match / order_book.go
1 package match
2
3 import (
4         "sort"
5
6         "github.com/bytom/vapor/application/mov/common"
7         "github.com/bytom/vapor/application/mov/database"
8         "github.com/bytom/vapor/errors"
9 )
10
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
15         dbOrders map[string][]*common.Order
16         // key of tradePair -> iterator
17         orderIterators map[string]*database.OrderIterator
18
19         // key of tradePair -> []order
20         arrivalAddOrders map[string][]*common.Order
21         // key of order -> order
22         arrivalDelOrders map[string]*common.Order
23 }
24
25 // NewOrderBook create a new OrderBook object
26 func NewOrderBook(movStore database.MovStore, arrivalAddOrders, arrivalDelOrders []*common.Order) *OrderBook {
27         return &OrderBook{
28                 movStore:       movStore,
29                 dbOrders:       make(map[string][]*common.Order),
30                 orderIterators: make(map[string]*database.OrderIterator),
31
32                 arrivalAddOrders: arrangeArrivalAddOrders(arrivalAddOrders),
33                 arrivalDelOrders: arrangeArrivalDelOrders(arrivalDelOrders),
34         }
35 }
36
37 // AddOrder add the in memory temp order to order table
38 func (o *OrderBook) AddOrder(order *common.Order) error {
39         tradePairKey := order.TradePair().Key()
40         orders := o.arrivalAddOrders[tradePairKey]
41         if len(orders) > 0 && order.Rate() > orders[len(orders)-1].Rate() {
42                 return errors.New("rate of order must less than the min order in order table")
43         }
44
45         o.arrivalAddOrders[tradePairKey] = append(orders, order)
46         return nil
47 }
48
49 // PeekOrder return the next lowest order of given trade pair
50 func (o *OrderBook) PeekOrder(tradePair *common.TradePair) *common.Order {
51         if len(o.dbOrders[tradePair.Key()]) == 0 {
52                 o.extendDBOrders(tradePair)
53         }
54
55         var nextOrder *common.Order
56         orders := o.dbOrders[tradePair.Key()]
57         if len(orders) != 0 {
58                 nextOrder = orders[len(orders)-1]
59         }
60
61         if nextOrder != nil && o.arrivalDelOrders[nextOrder.Key()] != nil {
62                 o.dbOrders[tradePair.Key()] = orders[0 : len(orders)-1]
63                 return o.PeekOrder(tradePair)
64         }
65
66         arrivalOrder := o.peekArrivalOrder(tradePair)
67         if nextOrder == nil || (arrivalOrder != nil && arrivalOrder.Rate() < nextOrder.Rate()) {
68                 nextOrder = arrivalOrder
69         }
70         return nextOrder
71 }
72
73 // PeekOrders return the next lowest orders by given array of trade pairs
74 func (o *OrderBook) PeekOrders(tradePairs []*common.TradePair) []*common.Order {
75         var orders []*common.Order
76         for _, tradePair := range tradePairs {
77                 order := o.PeekOrder(tradePair)
78                 if order == nil {
79                         return nil
80                 }
81
82                 orders = append(orders, order)
83         }
84         return orders
85 }
86
87 // PopOrder delete the next lowest order of given trade pair
88 func (o *OrderBook) PopOrder(tradePair *common.TradePair) {
89         order := o.PeekOrder(tradePair)
90         if order == nil {
91                 return
92         }
93
94         orders := o.dbOrders[tradePair.Key()]
95         if len(orders) != 0 && orders[len(orders)-1].Key() == order.Key() {
96                 o.dbOrders[tradePair.Key()] = orders[0 : len(orders)-1]
97         }
98
99         arrivalOrders := o.arrivalAddOrders[tradePair.Key()]
100         if len(arrivalOrders) != 0 && arrivalOrders[len(arrivalOrders)-1].Key() == order.Key() {
101                 o.arrivalAddOrders[tradePair.Key()] = arrivalOrders[0 : len(arrivalOrders)-1]
102         }
103 }
104
105 // PopOrders delete the next lowest orders by given trade pairs
106 func (o *OrderBook) PopOrders(tradePairs []*common.TradePair) []*common.Order {
107         var orders []*common.Order
108         for _, tradePair := range tradePairs {
109                 o.PopOrder(tradePair)
110         }
111         return orders
112 }
113
114 func arrangeArrivalAddOrders(orders []*common.Order) map[string][]*common.Order {
115         arrivalAddOrderMap := make(map[string][]*common.Order)
116         for _, order := range orders {
117                 arrivalAddOrderMap[order.TradePair().Key()] = append(arrivalAddOrderMap[order.TradePair().Key()], order)
118         }
119
120         for _, orders := range arrivalAddOrderMap {
121                 sort.Sort(sort.Reverse(common.OrderSlice(orders)))
122         }
123         return arrivalAddOrderMap
124 }
125
126 func arrangeArrivalDelOrders(orders []*common.Order) map[string]*common.Order {
127         arrivalDelOrderMap := make(map[string]*common.Order)
128         for _, order := range orders {
129                 arrivalDelOrderMap[order.Key()] = order
130         }
131         return arrivalDelOrderMap
132 }
133
134 func (o *OrderBook) extendDBOrders(tradePair *common.TradePair) {
135         iterator, ok := o.orderIterators[tradePair.Key()]
136         if !ok {
137                 iterator = database.NewOrderIterator(o.movStore, tradePair)
138                 o.orderIterators[tradePair.Key()] = iterator
139         }
140
141         nextOrders := iterator.NextBatch()
142         for i := len(nextOrders) - 1; i >= 0; i-- {
143                 o.dbOrders[tradePair.Key()] = append(o.dbOrders[tradePair.Key()], nextOrders[i])
144         }
145 }
146
147 func (o *OrderBook) peekArrivalOrder(tradePair *common.TradePair) *common.Order {
148         if arrivalAddOrders := o.arrivalAddOrders[tradePair.Key()]; len(arrivalAddOrders) > 0 {
149                 return arrivalAddOrders[len(arrivalAddOrders)-1]
150         }
151         return nil
152 }