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) }