2022-09-06 05:43:05 +00:00
|
|
|
package bbgo
|
2022-09-01 04:09:03 +00:00
|
|
|
|
|
|
|
import (
|
2022-09-06 10:08:05 +00:00
|
|
|
"encoding/json"
|
2022-09-01 04:09:03 +00:00
|
|
|
"strings"
|
|
|
|
|
|
|
|
"github.com/c9s/bbgo/pkg/fixedpoint"
|
|
|
|
"github.com/c9s/bbgo/pkg/types"
|
|
|
|
log "github.com/sirupsen/logrus"
|
|
|
|
)
|
|
|
|
|
|
|
|
type SourceFunc func(*types.KLine) fixedpoint.Value
|
|
|
|
|
2022-09-06 10:08:05 +00:00
|
|
|
type selectorInternal struct {
|
2022-09-06 10:15:13 +00:00
|
|
|
Source string
|
|
|
|
sourceGetter SourceFunc
|
2022-09-06 10:08:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (s *selectorInternal) UnmarshalJSON(d []byte) error {
|
|
|
|
if err := json.Unmarshal(d, &s.Source); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
s.init()
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s selectorInternal) MarshalJSON() ([]byte, error) {
|
|
|
|
if s.Source == "" {
|
|
|
|
s.Source = "close"
|
|
|
|
s.init()
|
|
|
|
}
|
|
|
|
return []byte("\"" + s.Source + "\""), nil
|
|
|
|
}
|
2022-09-01 04:09:03 +00:00
|
|
|
|
|
|
|
type SourceSelector struct {
|
2022-09-06 10:08:05 +00:00
|
|
|
Source selectorInternal `json:"source,omitempty"`
|
2022-09-01 04:09:03 +00:00
|
|
|
}
|
|
|
|
|
2022-09-06 10:08:05 +00:00
|
|
|
func (s *selectorInternal) init() {
|
2022-09-01 04:09:03 +00:00
|
|
|
switch strings.ToLower(s.Source) {
|
|
|
|
case "close":
|
2022-09-06 10:15:13 +00:00
|
|
|
s.sourceGetter = func(kline *types.KLine) fixedpoint.Value { return kline.Close }
|
2022-09-01 04:09:03 +00:00
|
|
|
case "high":
|
2022-09-06 10:15:13 +00:00
|
|
|
s.sourceGetter = func(kline *types.KLine) fixedpoint.Value { return kline.High }
|
2022-09-01 04:09:03 +00:00
|
|
|
case "low":
|
2022-09-06 10:15:13 +00:00
|
|
|
s.sourceGetter = func(kline *types.KLine) fixedpoint.Value { return kline.Low }
|
2022-09-01 04:09:03 +00:00
|
|
|
case "hl2":
|
2022-09-06 10:15:13 +00:00
|
|
|
s.sourceGetter = func(kline *types.KLine) fixedpoint.Value { return kline.High.Add(kline.Low).Div(fixedpoint.Two) }
|
2022-09-01 04:09:03 +00:00
|
|
|
case "hlc3":
|
2022-09-06 10:15:13 +00:00
|
|
|
s.sourceGetter = func(kline *types.KLine) fixedpoint.Value {
|
2022-09-06 10:08:05 +00:00
|
|
|
return kline.High.Add(kline.Low).Add(kline.Close).Div(fixedpoint.Three)
|
2022-09-01 04:09:03 +00:00
|
|
|
}
|
|
|
|
case "ohlc4":
|
2022-09-06 10:15:13 +00:00
|
|
|
s.sourceGetter = func(kline *types.KLine) fixedpoint.Value {
|
2022-09-06 10:08:05 +00:00
|
|
|
return kline.High.Add(kline.Low).Add(kline.Close).Add(kline.Open).Div(fixedpoint.Four)
|
2022-09-01 04:09:03 +00:00
|
|
|
}
|
|
|
|
case "open":
|
2022-09-06 10:15:13 +00:00
|
|
|
s.sourceGetter = func(kline *types.KLine) fixedpoint.Value { return kline.Open }
|
2022-09-07 06:02:38 +00:00
|
|
|
case "oc2":
|
|
|
|
s.sourceGetter = func(kline *types.KLine) fixedpoint.Value { return kline.Open.Add(kline.Close).Div(fixedpoint.Two) }
|
2022-09-01 04:09:03 +00:00
|
|
|
default:
|
|
|
|
log.Infof("source not set: %s, use hl2 by default", s.Source)
|
2022-09-06 10:15:13 +00:00
|
|
|
s.sourceGetter = func(kline *types.KLine) fixedpoint.Value { return kline.High.Add(kline.Low).Div(fixedpoint.Two) }
|
2022-09-06 10:08:05 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *selectorInternal) String() string {
|
|
|
|
if s.Source == "" {
|
|
|
|
s.Source = "close"
|
|
|
|
s.init()
|
2022-09-01 04:09:03 +00:00
|
|
|
}
|
2022-09-06 10:08:05 +00:00
|
|
|
return s.Source
|
2022-09-01 04:09:03 +00:00
|
|
|
}
|
|
|
|
|
2022-09-06 10:08:05 +00:00
|
|
|
// lazy init if empty struct is passed in
|
2022-09-01 04:09:03 +00:00
|
|
|
func (s *SourceSelector) GetSource(kline *types.KLine) fixedpoint.Value {
|
2022-09-06 10:08:05 +00:00
|
|
|
if s.Source.Source == "" {
|
|
|
|
s.Source.Source = "close"
|
|
|
|
s.Source.init()
|
|
|
|
}
|
2022-09-06 10:15:13 +00:00
|
|
|
return s.Source.sourceGetter(kline)
|
2022-09-01 04:09:03 +00:00
|
|
|
}
|