-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathstats.go
228 lines (181 loc) · 4.58 KB
/
stats.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
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
package technical
import (
"math"
)
// RoundUp64 rounds the given number up to the nearest nth decimal place
func RoundUp64(x float64, n int) float64 {
roundFactor := math.Pow10(n)
return math.Ceil((x * roundFactor)) / roundFactor
}
// RoundUp32 is 32 bit version of RoundUp64
func RoundUp32(x float32, n int) float32 {
roundFactor := math.Pow10(n)
return float32(math.Ceil((float64(x) * roundFactor)) / roundFactor)
}
// RoundDown64 rounds the given number down to the nearest nth decimal place
func RoundDown64(x float64, n int) float64 {
roundFactor := math.Pow10(n)
return math.Floor((x * roundFactor)) / roundFactor
}
// RoundDown32 is 32 bit version of RoundUp64
func RoundDown32(x float32, n int) float32 {
roundFactor := math.Pow10(n)
return float32(math.Floor((float64(x) * roundFactor)) / roundFactor)
}
// SimpleAvg64 computes the simple average of a given list of values
func SimpleAvg64(xs []float64) float64 {
if len(xs) == 0 {
return 0.0
}
var sum float64
for _, v := range xs {
sum += v
}
return sum / float64(len(xs))
}
// SimpleAvg32 is 32 bit version of SimpleAvg64
func SimpleAvg32(xs []float32) float32 {
if len(xs) == 0 {
return 0.0
}
var sum float32
for _, v := range xs {
sum += v
}
return sum / float32(len(xs))
}
// Variance64 computes the population variance of a given iist of values
func Variance64(xs []float64) float64 {
if len(xs) == 0 {
return 0.0
}
var total float64
avg := SimpleAvg64(xs)
for _, v := range xs {
diff := v - avg
total += (diff * diff)
}
return total / float64(len(xs))
}
// Variance32 is 32 bit version of Variance64
func Variance32(xs []float32) float32 {
if len(xs) == 0 {
return 0.0
}
var total float32
avg := SimpleAvg32(xs)
for _, v := range xs {
diff := v - avg
total += (diff * diff)
}
return total / float32(len(xs))
}
// StdDev64 computes the standard deviation of a given list of values
func StdDev64(xs []float64) float64 {
if len(xs) == 0 {
return 0.0
}
res := math.Sqrt(Variance64(xs))
if math.IsNaN(res) {
return 0.0
}
return res
}
// StdDev32 is 32 bit version of StdDev64
func StdDev32(xs []float32) float32 {
if xs == nil || len(xs) == 0 {
return 0.0
}
res := math.Sqrt(float64(Variance32(xs)))
if math.IsNaN(res) {
return float32(0.0)
}
return float32(res)
}
// EwmaSeries computes a list of Exponentially Weighted Moving Averages for a given list of values
// If xs is time series data assumes ascending time order
//
// Parameters:
// series: the data series
// smoothingMethod: 0 if use default formula. 1 if custom
// y (lambda): decay smoothing factor on the weight of each element
// lb (lookback): size of the period to compute avg. Must be < len of data series
//
// Constraint: 0 < y < 1
//
func EwmaSeries64(series []float64, y float64, lb int) []float64 {
if len(series) == 0 {
return nil
}
size := len(series)
if lb > size { // use full series
lb = size
}
if y == 0.0 { // use default smoothing
y = 2.0 / float64(lb+1)
}
var lastEma float64
ewmas := make([]float64, size)
for i, v := range series {
j := i + 1 // offset 1 bc of idx
switch {
case j < lb:
ewmas[i] = 0.0
case j == lb: // first is simple average
savg := SimpleAvg64(series[j-lb : j])
ewmas[i] = savg
lastEma = savg
default: // compute ewma
curEma := RollingEMA64(v, lastEma, y)
ewmas[i] = curEma
lastEma = curEma
}
}
return ewmas
}
// EwmaSeries32 is 32 bit version of EwmaSeries64
func EwmaSeries32(series []float32, y float32, lb int) []float32 {
if series == nil || len(series) == 0 {
return nil
}
size := len(series)
if lb > size { // use full series
lb = size
}
if y == float32(0.0) { // use default smoothing
y = 2.0 / float32(lb+1)
}
var lastEma float32
ewmas := make([]float32, size)
for i, v := range series {
j := i + 1 // offset by 1 bc of index
switch {
case j < lb:
ewmas[i] = float32(0.0)
case j == lb: // first is simple average
savg := SimpleAvg32(series[j-lb : j])
ewmas[i] = savg
lastEma = savg
default: // compute ewma
curEma := RollingEMA32(v, lastEma, y)
ewmas[i] = curEma
lastEma = curEma
}
}
return ewmas
}
// RollingEwma computes the next EWMA value in a series
// Assumes last EWMA value given is correct
//
// Parameters:
// v: the current value in the series
// last: the last EWMA value of the series
// y (lambda): smoothing factor
// Constraint: 0 < y < 1
func RollingEMA64(v float64, last float64, y float64) float64 {
return v*y + (1-y)*last
}
// RollingEMA32 is 32 bit version of RollingEMA64
func RollingEMA32(v float32, last float32, y float32) float32 {
return v*y + (1-y)*last
}