2022-07-20 17:04:49 +00:00
|
|
|
package bbgo
|
|
|
|
|
|
|
|
import (
|
|
|
|
"github.com/sirupsen/logrus"
|
|
|
|
|
|
|
|
"github.com/c9s/bbgo/pkg/indicator"
|
|
|
|
"github.com/c9s/bbgo/pkg/types"
|
|
|
|
"github.com/c9s/bbgo/pkg/util"
|
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
|
|
|
debugBOLL = false
|
|
|
|
)
|
|
|
|
|
|
|
|
func init() {
|
|
|
|
// when using --dotenv option, the dotenv is loaded from command.PersistentPreRunE, not init.
|
|
|
|
// hence here the env var won't enable the debug flag
|
|
|
|
util.SetEnvVarBool("DEBUG_BOLL", &debugBOLL)
|
|
|
|
}
|
|
|
|
|
|
|
|
type StandardIndicatorSet struct {
|
|
|
|
Symbol string
|
2022-07-26 09:56:31 +00:00
|
|
|
|
2022-07-20 17:04:49 +00:00
|
|
|
// Standard indicators
|
|
|
|
// interval -> window
|
2022-08-24 09:43:28 +00:00
|
|
|
iwbIndicators map[types.IntervalWindowBandWidth]*indicator.BOLL
|
|
|
|
iwIndicators map[types.IntervalWindow]indicator.KLinePusher
|
2022-07-20 17:04:49 +00:00
|
|
|
|
|
|
|
stream types.Stream
|
|
|
|
store *MarketDataStore
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewStandardIndicatorSet(symbol string, stream types.Stream, store *MarketDataStore) *StandardIndicatorSet {
|
|
|
|
return &StandardIndicatorSet{
|
2022-08-24 09:43:28 +00:00
|
|
|
Symbol: symbol,
|
|
|
|
store: store,
|
|
|
|
stream: stream,
|
|
|
|
iwIndicators: make(map[types.IntervalWindow]indicator.KLinePusher),
|
|
|
|
iwbIndicators: make(map[types.IntervalWindowBandWidth]*indicator.BOLL),
|
2022-07-20 17:04:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-08-24 09:43:28 +00:00
|
|
|
func (s *StandardIndicatorSet) initAndBind(inc indicator.KLinePusher, interval types.Interval) {
|
|
|
|
if klines, ok := s.store.KLinesOfInterval(interval); ok {
|
2022-07-26 09:56:31 +00:00
|
|
|
for _, k := range *klines {
|
|
|
|
inc.PushK(k)
|
2022-07-20 17:04:49 +00:00
|
|
|
}
|
2022-07-26 09:56:31 +00:00
|
|
|
}
|
2022-07-20 17:04:49 +00:00
|
|
|
|
2022-08-24 09:43:28 +00:00
|
|
|
s.stream.OnKLineClosed(types.KLineWith(s.Symbol, interval, inc.PushK))
|
2022-07-26 09:56:31 +00:00
|
|
|
}
|
2022-07-20 17:04:49 +00:00
|
|
|
|
2022-07-26 18:21:25 +00:00
|
|
|
func (s *StandardIndicatorSet) allocateSimpleIndicator(t indicator.KLinePusher, iw types.IntervalWindow) indicator.KLinePusher {
|
2022-08-24 09:43:28 +00:00
|
|
|
inc, ok := s.iwIndicators[iw]
|
2022-07-26 09:56:31 +00:00
|
|
|
if ok {
|
|
|
|
return inc
|
2022-07-20 17:04:49 +00:00
|
|
|
}
|
|
|
|
|
2022-07-26 09:56:31 +00:00
|
|
|
inc = t
|
2022-08-24 09:43:28 +00:00
|
|
|
s.initAndBind(inc, iw.Interval)
|
|
|
|
s.iwIndicators[iw] = inc
|
2022-07-26 09:56:31 +00:00
|
|
|
return t
|
2022-07-20 17:04:49 +00:00
|
|
|
}
|
|
|
|
|
2022-07-26 09:56:31 +00:00
|
|
|
// SMA is a helper function that returns the simple moving average indicator of the given interval and the window size.
|
2022-07-26 09:57:42 +00:00
|
|
|
func (s *StandardIndicatorSet) SMA(iw types.IntervalWindow) *indicator.SMA {
|
|
|
|
inc := s.allocateSimpleIndicator(&indicator.SMA{IntervalWindow: iw}, iw)
|
2022-07-26 09:56:31 +00:00
|
|
|
return inc.(*indicator.SMA)
|
2022-07-20 17:04:49 +00:00
|
|
|
}
|
|
|
|
|
2022-07-26 09:56:31 +00:00
|
|
|
// EWMA is a helper function that returns the exponential weighed moving average indicator of the given interval and the window size.
|
2022-07-26 09:57:42 +00:00
|
|
|
func (s *StandardIndicatorSet) EWMA(iw types.IntervalWindow) *indicator.EWMA {
|
|
|
|
inc := s.allocateSimpleIndicator(&indicator.EWMA{IntervalWindow: iw}, iw)
|
2022-07-26 09:56:31 +00:00
|
|
|
return inc.(*indicator.EWMA)
|
|
|
|
}
|
2022-07-20 17:04:49 +00:00
|
|
|
|
2022-08-24 09:45:32 +00:00
|
|
|
// VWMA
|
|
|
|
func (s *StandardIndicatorSet) VWMA(iw types.IntervalWindow) *indicator.VWMA {
|
|
|
|
inc := s.allocateSimpleIndicator(&indicator.VWMA{IntervalWindow: iw}, iw)
|
|
|
|
return inc.(*indicator.VWMA)
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2022-08-30 17:43:40 +00:00
|
|
|
func (s *StandardIndicatorSet) PivotHigh(iw types.IntervalWindow) *indicator.PivotHigh {
|
|
|
|
inc := s.allocateSimpleIndicator(&indicator.PivotHigh{IntervalWindow: iw}, iw)
|
|
|
|
return inc.(*indicator.PivotHigh)
|
|
|
|
}
|
|
|
|
|
2022-07-26 09:57:42 +00:00
|
|
|
func (s *StandardIndicatorSet) PivotLow(iw types.IntervalWindow) *indicator.PivotLow {
|
|
|
|
inc := s.allocateSimpleIndicator(&indicator.PivotLow{IntervalWindow: iw}, iw)
|
2022-07-26 09:56:31 +00:00
|
|
|
return inc.(*indicator.PivotLow)
|
|
|
|
}
|
2022-07-20 17:04:49 +00:00
|
|
|
|
2022-07-26 10:03:42 +00:00
|
|
|
func (s *StandardIndicatorSet) ATR(iw types.IntervalWindow) *indicator.ATR {
|
|
|
|
inc := s.allocateSimpleIndicator(&indicator.ATR{IntervalWindow: iw}, iw)
|
|
|
|
return inc.(*indicator.ATR)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *StandardIndicatorSet) ATRP(iw types.IntervalWindow) *indicator.ATRP {
|
|
|
|
inc := s.allocateSimpleIndicator(&indicator.ATRP{IntervalWindow: iw}, iw)
|
|
|
|
return inc.(*indicator.ATRP)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *StandardIndicatorSet) EMV(iw types.IntervalWindow) *indicator.EMV {
|
2022-07-26 10:04:57 +00:00
|
|
|
inc := s.allocateSimpleIndicator(&indicator.EMV{IntervalWindow: iw}, iw)
|
2022-07-26 10:03:42 +00:00
|
|
|
return inc.(*indicator.EMV)
|
|
|
|
}
|
|
|
|
|
2022-07-26 10:04:57 +00:00
|
|
|
func (s *StandardIndicatorSet) CCI(iw types.IntervalWindow) *indicator.CCI {
|
|
|
|
inc := s.allocateSimpleIndicator(&indicator.CCI{IntervalWindow: iw}, iw)
|
|
|
|
return inc.(*indicator.CCI)
|
|
|
|
}
|
|
|
|
|
2022-07-26 10:27:22 +00:00
|
|
|
func (s *StandardIndicatorSet) HULL(iw types.IntervalWindow) *indicator.HULL {
|
|
|
|
inc := s.allocateSimpleIndicator(&indicator.HULL{IntervalWindow: iw}, iw)
|
|
|
|
return inc.(*indicator.HULL)
|
|
|
|
}
|
|
|
|
|
2022-07-26 09:57:42 +00:00
|
|
|
func (s *StandardIndicatorSet) STOCH(iw types.IntervalWindow) *indicator.STOCH {
|
2022-08-24 09:34:19 +00:00
|
|
|
inc := s.allocateSimpleIndicator(&indicator.STOCH{IntervalWindow: iw}, iw)
|
|
|
|
return inc.(*indicator.STOCH)
|
2022-07-20 17:04:49 +00:00
|
|
|
}
|
|
|
|
|
2022-07-26 09:56:31 +00:00
|
|
|
// BOLL returns the bollinger band indicator of the given interval, the window and bandwidth
|
2022-07-26 09:57:42 +00:00
|
|
|
func (s *StandardIndicatorSet) BOLL(iw types.IntervalWindow, bandWidth float64) *indicator.BOLL {
|
2022-07-26 09:56:31 +00:00
|
|
|
iwb := types.IntervalWindowBandWidth{IntervalWindow: iw, BandWidth: bandWidth}
|
2022-08-24 09:43:28 +00:00
|
|
|
inc, ok := s.iwbIndicators[iwb]
|
2022-07-20 17:04:49 +00:00
|
|
|
if !ok {
|
2022-07-26 09:56:31 +00:00
|
|
|
inc = &indicator.BOLL{IntervalWindow: iw, K: bandWidth}
|
2022-08-24 09:43:28 +00:00
|
|
|
s.initAndBind(inc, iw.Interval)
|
2022-07-20 17:04:49 +00:00
|
|
|
|
2022-07-26 09:56:31 +00:00
|
|
|
if debugBOLL {
|
|
|
|
inc.OnUpdate(func(sma float64, upBand float64, downBand float64) {
|
2022-07-26 09:57:42 +00:00
|
|
|
logrus.Infof("%s BOLL %s: sma=%f up=%f down=%f", s.Symbol, iw.String(), sma, upBand, downBand)
|
2022-07-26 09:56:31 +00:00
|
|
|
})
|
2022-07-20 17:04:49 +00:00
|
|
|
}
|
2022-08-24 09:43:28 +00:00
|
|
|
s.iwbIndicators[iwb] = inc
|
2022-07-20 17:04:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return inc
|
|
|
|
}
|