-
Notifications
You must be signed in to change notification settings - Fork 0
/
quota.go
143 lines (122 loc) · 3.24 KB
/
quota.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
package quota
import (
"errors"
"sort"
"time"
"github.com/amir-the-h/okex"
)
// Quota is the group of candles and make time-series.
type Quota []*Candle
// Symbol will return the symbol of candles.
func (q *Quota) Symbol() string {
for _, candle := range *q {
return candle.Symbol
}
return ""
}
// BarSize will return the okex.BarSize of candles.
func (q *Quota) BarSize() okex.BarSize {
for _, candle := range *q {
return candle.BarSize
}
return ""
}
// IndicatorTags returns a list of indicators used in quota.
func (q *Quota) IndicatorTags() []IndicatorTag {
var tags []IndicatorTag
for _, candle := range *q {
for indicator := range candle.Indicators {
hasIndicator := false
for _, tag := range tags {
if tag == indicator {
hasIndicator = true
break
}
}
if !hasIndicator {
tags = append(tags, indicator)
}
}
}
return tags
}
// Find searches for a candle, and its index among Quota by its symbol and provided timestamp.
func (q *Quota) Find(timestamp int64) (*Candle, int) {
for i, candle := range *q {
if candle.OpenTime.Unix() == timestamp || (candle.OpenTime.Unix() < timestamp && candle.CloseTime.Unix() > timestamp) {
return candle, i
}
}
return nil, -1
}
// Sort runs through the quota and reorder candles by the open time.
func (q *Quota) Sort() {
sort.Slice(*q, func(i, j int) bool { return (*q)[i].OpenTime.Before((*q)[j].OpenTime) })
for i, candle := range *q {
if i > 0 {
candle.Previous = (*q)[i-1]
}
if i < len(*q)-1 {
candle.Next = (*q)[i+1]
}
}
}
// Sync searches the quota for provided candle and update it if it exists, otherwise, it will append to end of the quota.
//
// If you want to update a candle directly then pass sCandle.
func (q *Quota) Sync(open, high, low, close, volume float64, openTime, closeTime time.Time, sCandle ...*Candle) (candle *Candle, err CandleError) {
var lc *Candle
checker := func(candle *Candle, openTime, closeTime time.Time) bool {
return candle.OpenTime.Equal(openTime) && candle.CloseTime.Equal(closeTime)
}
// try last candle first
if len(*q) > 0 {
lc = (*q)[len(*q)-1]
candle = lc
}
// if any suspicious candle provided try it then.
if len(sCandle) > 0 {
candle = sCandle[0]
}
if candle == nil || !checker(candle, openTime, closeTime) {
candle, _ = q.Find(openTime.Unix())
if candle == nil {
candle, err = NewCandle(open, high, low, close, volume, q.Symbol(), q.BarSize(), openTime, closeTime, lc, nil)
if err != nil {
return
}
*q = append(*q, candle)
if lc != nil {
lc.Next = candle
}
}
}
candle.Open = open
candle.High = high
candle.Low = low
candle.Close = close
candle.Volume = volume
return
}
// Merge target quota into the current quota, rewrite duplicates and sort it.
func (q *Quota) Merge(target *Quota) {
for _, candle := range *target {
c, i := q.Find(candle.OpenTime.Unix())
if c != nil {
(*q)[i] = candle
} else {
*q = append(*q, candle)
}
}
}
// AddIndicator adds unimplementedIndicator values by the given tag into the quota.
func (q *Quota) AddIndicator(tag IndicatorTag, values []float64) error {
quota := *q
if len(values) != len(quota) {
return errors.New("count mismatched")
}
for i := range values {
(*q)[i].Indicators[tag] = values[i]
}
return nil
}