/
depth_book.go
128 lines (112 loc) · 3.8 KB
/
depth_book.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
package types
import (
"sort"
sdk "github.com/FiboChain/fbc/libs/cosmos-sdk/types"
)
// nolint
type Deal struct {
OrderID string `json:"order_id"`
Side string `json:"side"`
Quantity sdk.Dec `json:"quantity"`
Fee string `json:"fee"`
FeeReceiver string `json:"fee_receiver"`
}
// nolint
type MatchResult struct {
BlockHeight int64 `json:"block_height"`
Price sdk.Dec `json:"price"`
Quantity sdk.Dec `json:"quantity"`
Deals []Deal `json:"deals"`
}
// nolint
type BlockMatchResult struct {
BlockHeight int64 `json:"block_height"`
ResultMap map[string]MatchResult `json:"result_map"`
TimeStamp int64 `json:"timestamp"`
}
// nolint
type DepthBookItem struct {
Price sdk.Dec `json:"price"`
BuyQuantity sdk.Dec `json:"buy_quantity"`
SellQuantity sdk.Dec `json:"sell_quantity"`
}
// nolint
type DepthBook struct {
Items []DepthBookItem
}
// InsertOrder : Items in depth book are sorted by price desc
// insert a new order into depth book
func (depthBook *DepthBook) InsertOrder(order *Order) {
bookLength := len(depthBook.Items)
newItem := DepthBookItem{
Price: order.Price,
BuyQuantity: sdk.ZeroDec(),
SellQuantity: sdk.ZeroDec(),
}
if order.Side == BuyOrder {
newItem.BuyQuantity = order.RemainQuantity
} else {
newItem.SellQuantity = order.RemainQuantity
}
if bookLength == 0 || order.Price.LT(depthBook.Items[bookLength-1].Price) {
depthBook.Items = append(depthBook.Items, newItem)
return
}
// find first index, s.t. order.Price >= depthBook[index].Price
index := sort.Search(bookLength, func(i int) bool {
return order.Price.GTE(depthBook.Items[i].Price)
})
if order.Price.Equal(depthBook.Items[index].Price) {
if order.Side == BuyOrder {
depthBook.Items[index].BuyQuantity =
depthBook.Items[index].BuyQuantity.Add(order.RemainQuantity)
} else {
depthBook.Items[index].SellQuantity =
depthBook.Items[index].SellQuantity.Add(order.RemainQuantity)
}
} else { // order.InitPrice > depthBook[index].InitPrice
rear := append([]DepthBookItem{newItem}, depthBook.Items[index:]...)
depthBook.Items = append(depthBook.Items[:index], rear...)
}
}
// RemoveOrder : remove an order from depth book when order cancelled/expired
func (depthBook *DepthBook) RemoveOrder(order *Order) {
bookLen := len(depthBook.Items)
// find first index, s.t. order.Price >= depthBook[index].Price
// i.e. order.Price == depthBook[index].Price
index := sort.Search(bookLen, func(i int) bool {
return order.Price.GTE(depthBook.Items[i].Price)
})
if index < bookLen && depthBook.Items[index].Price.Equal(order.Price) {
if order.Side == BuyOrder {
depthBook.Items[index].BuyQuantity =
depthBook.Items[index].BuyQuantity.Sub(order.RemainQuantity)
} else if order.Side == SellOrder {
depthBook.Items[index].SellQuantity =
depthBook.Items[index].SellQuantity.Sub(order.RemainQuantity)
}
depthBook.RemoveIfEmpty(index)
}
}
// Sub : subtract the buy or sell quantity
func (depthBook *DepthBook) Sub(index int, num sdk.Dec, side string) {
if side == BuyOrder {
depthBook.Items[index].BuyQuantity = depthBook.Items[index].BuyQuantity.Sub(num)
} else if side == SellOrder {
depthBook.Items[index].SellQuantity = depthBook.Items[index].SellQuantity.Sub(num)
}
}
// RemoveIfEmpty : remove the filled or empty item
func (depthBook *DepthBook) RemoveIfEmpty(index int) bool {
res := depthBook.Items[index].BuyQuantity.IsZero() && depthBook.Items[index].SellQuantity.IsZero()
if res {
depthBook.Items = append(depthBook.Items[:index], depthBook.Items[index+1:]...)
}
return res
}
// Copy : depth copy of depth book
func (depthBook *DepthBook) Copy() *DepthBook {
itemList := make([]DepthBookItem, 0, len(depthBook.Items))
itemList = append(itemList, depthBook.Items...)
return &DepthBook{Items: itemList}
}