This repository has been archived by the owner on Jun 8, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 138
/
ticklist.go
155 lines (137 loc) 路 3.57 KB
/
ticklist.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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
package entities
import (
"errors"
"math"
"math/big"
)
var (
ErrZeroTickSpacing = errors.New("tick spacing must be greater than 0")
ErrInvalidTickSpacing = errors.New("invalid tick spacing")
ErrZeroNet = errors.New("tick net delta must be zero")
ErrSorted = errors.New("ticks must be sorted")
)
func ValidateList(ticks []Tick, tickSpacing int) error {
if tickSpacing <= 0 {
return ErrZeroTickSpacing
}
// ensure ticks are spaced appropriately
for _, t := range ticks {
if t.Index%tickSpacing != 0 {
return ErrInvalidTickSpacing
}
}
// ensure tick liquidity deltas sum to 0
sum := big.NewInt(0)
for _, tick := range ticks {
sum.Add(sum, tick.LiquidityNet)
}
if sum.Cmp(big.NewInt(0)) != 0 {
return ErrZeroNet
}
if !isTicksSorted(ticks) {
return ErrSorted
}
return nil
}
func IsBelowSmallest(ticks []Tick, tick int) bool {
if len(ticks) == 0 {
panic("empty tick list")
}
return tick < ticks[0].Index
}
func IsAtOrAboveLargest(ticks []Tick, tick int) bool {
if len(ticks) == 0 {
panic("empty tick list")
}
return tick >= ticks[len(ticks)-1].Index
}
func GetTick(ticks []Tick, index int) Tick {
tick := ticks[binarySearch(ticks, index)]
if tick.Index != index {
panic("index is not contained in ticks")
}
return tick
}
func NextInitializedTick(ticks []Tick, tick int, lte bool) Tick {
if lte {
if IsBelowSmallest(ticks, tick) {
panic("below smallest")
}
if IsAtOrAboveLargest(ticks, tick) {
return ticks[len(ticks)-1]
}
index := binarySearch(ticks, tick)
return ticks[index]
} else {
if IsAtOrAboveLargest(ticks, tick) {
panic("at or above largest")
}
if IsBelowSmallest(ticks, tick) {
return ticks[0]
}
index := binarySearch(ticks, tick)
return ticks[index+1]
}
}
func NextInitializedTickWithinOneWord(ticks []Tick, tick int, lte bool, tickSpacing int) (int, bool) {
compressed := math.Floor(float64(tick) / float64(tickSpacing)) // matches rounding in the code
if lte {
wordPos := int(compressed) >> 8
minimum := (wordPos << 8) * tickSpacing
if IsBelowSmallest(ticks, tick) {
return minimum, false
}
index := NextInitializedTick(ticks, tick, lte).Index
nextInitializedTick := math.Max(float64(minimum), float64(index))
return int(nextInitializedTick), int(nextInitializedTick) == index
} else {
wordPos := int(compressed+1) >> 8
maximum := ((wordPos+1)<<8)*tickSpacing - 1
if IsAtOrAboveLargest(ticks, tick) {
return maximum, false
}
index := NextInitializedTick(ticks, tick, lte).Index
nextInitializedTick := math.Min(float64(maximum), float64(index))
return int(nextInitializedTick), int(nextInitializedTick) == index
}
}
// utils
func isTicksSorted(ticks []Tick) bool {
for i := 0; i < len(ticks)-1; i++ {
if ticks[i].Index > ticks[i+1].Index {
return false
}
}
return true
}
/**
* Finds the largest tick in the list of ticks that is less than or equal to tick
* @param ticks list of ticks
* @param tick tick to find the largest tick that is less than or equal to tick
* @private
*/
func binarySearch(ticks []Tick, tick int) int {
if IsBelowSmallest(ticks, tick) {
panic("tick is below smallest tick")
}
// binary search
start := 0
end := len(ticks) - 1
for start <= end {
mid := (start + end) / 2
if ticks[mid].Index == tick {
return mid
} else if ticks[mid].Index < tick {
start = mid + 1
} else {
end = mid - 1
}
}
// if we get here, we didn't find a tick that is less than or equal to tick
// so we return the index of the tick that is closest to tick
if ticks[start].Index < tick {
return start
} else {
return start - 1
}
}