qbtrade/pkg/types/interval.go
2024-06-27 22:42:38 +08:00

193 lines
3.7 KiB
Go

package types
import (
"encoding/json"
"fmt"
"sort"
"strings"
"time"
)
type Interval string
func (i Interval) Minutes() int {
m, ok := SupportedIntervals[i]
if !ok {
return ParseInterval(i) / 60
}
return m / 60
}
func (i Interval) Seconds() int {
m, ok := SupportedIntervals[i]
if !ok {
return ParseInterval(i)
}
return m
}
// Milliseconds is specially handled, for better precision
// for ms level interval, calling Seconds and Minutes directly might trigger panic error
func (i Interval) Milliseconds() int {
t := 0
index := 0
for i, rn := range string(i) {
if rn >= '0' && rn <= '9' {
t = t*10 + int(rn-'0')
} else {
index = i
break
}
}
switch strings.ToLower(string(i[index:])) {
case "ms":
return t
case "s":
return t * 1000
case "m":
t *= 60
case "h":
t *= 60 * 60
case "d":
t *= 60 * 60 * 24
case "w":
t *= 60 * 60 * 24 * 7
case "mo":
t *= 60 * 60 * 24 * 30
default:
panic("unknown interval input: " + i)
}
return t * 1000
}
func (i Interval) Duration() time.Duration {
return time.Duration(i.Milliseconds()) * time.Millisecond
}
func (i *Interval) UnmarshalJSON(b []byte) (err error) {
var a string
err = json.Unmarshal(b, &a)
if err != nil {
return err
}
*i = Interval(a)
return
}
func (i Interval) String() string {
return string(i)
}
type IntervalSlice []Interval
func (s IntervalSlice) Sort() {
sort.Slice(s, func(i, j int) bool {
return s[i].Duration() < s[j].Duration()
})
}
func (s IntervalSlice) StringSlice() (slice []string) {
for _, interval := range s {
slice = append(slice, `"`+interval.String()+`"`)
}
return slice
}
var Interval1s = Interval("1s")
var Interval1m = Interval("1m")
var Interval3m = Interval("3m")
var Interval5m = Interval("5m")
var Interval15m = Interval("15m")
var Interval30m = Interval("30m")
var Interval1h = Interval("1h")
var Interval2h = Interval("2h")
var Interval4h = Interval("4h")
var Interval6h = Interval("6h")
var Interval12h = Interval("12h")
var Interval1d = Interval("1d")
var Interval3d = Interval("3d")
var Interval1w = Interval("1w")
var Interval2w = Interval("2w")
var Interval1mo = Interval("1mo")
func ParseInterval(input Interval) int {
t := 0
index := 0
for i, rn := range string(input) {
if rn >= '0' && rn <= '9' {
t = t*10 + int(rn-'0')
} else {
index = i
break
}
}
switch strings.ToLower(string(input[index:])) {
case "s":
return t
case "m":
t *= 60
case "h":
t *= 60 * 60
case "d":
t *= 60 * 60 * 24
case "w":
t *= 60 * 60 * 24 * 7
case "mo":
t *= 60 * 60 * 24 * 30
default:
panic("unknown interval input: " + input)
}
return t
}
type IntervalMap map[Interval]int
func (m IntervalMap) Slice() (slice IntervalSlice) {
for interval := range m {
slice = append(slice, interval)
}
return slice
}
var SupportedIntervals = IntervalMap{
Interval1s: 1,
Interval1m: 1 * 60,
Interval3m: 3 * 60,
Interval5m: 5 * 60,
Interval15m: 15 * 60,
Interval30m: 30 * 60,
Interval1h: 60 * 60,
Interval2h: 60 * 60 * 2,
Interval4h: 60 * 60 * 4,
Interval6h: 60 * 60 * 6,
Interval12h: 60 * 60 * 12,
Interval1d: 60 * 60 * 24,
Interval3d: 60 * 60 * 24 * 3,
Interval1w: 60 * 60 * 24 * 7,
Interval2w: 60 * 60 * 24 * 14,
Interval1mo: 60 * 60 * 24 * 30,
}
// IntervalWindow is used by the indicators
type IntervalWindow struct {
// The interval of kline
Interval Interval `json:"interval"`
// The windows size of the indicator (for example, EWMA and SMA)
Window int `json:"window"`
// RightWindow is used by the pivot indicator
RightWindow *int `json:"rightWindow"`
}
type IntervalWindowBandWidth struct {
IntervalWindow
BandWidth float64 `json:"bandWidth"`
}
func (iw IntervalWindow) String() string {
return fmt.Sprintf("%s (%d)", iw.Interval, iw.Window)
}