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 )
}
2022-09-14 10:33:06 +00:00
type MACDConfig struct {
types . IntervalWindow
}
2022-07-20 17:04:49 +00:00
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-09-14 10:33:06 +00:00
iwbIndicators map [ types . IntervalWindowBandWidth ] * indicator . BOLL
iwIndicators map [ indicatorKey ] indicator . KLinePusher
macdIndicators map [ indicator . MACDConfig ] * indicator . MACD
2022-07-20 17:04:49 +00:00
stream types . Stream
store * MarketDataStore
}
2022-08-30 17:21:32 +00:00
type indicatorKey struct {
iw types . IntervalWindow
id string
}
2022-07-20 17:04:49 +00:00
func NewStandardIndicatorSet ( symbol string , stream types . Stream , store * MarketDataStore ) * StandardIndicatorSet {
return & StandardIndicatorSet {
2022-09-14 10:44:38 +00:00
Symbol : symbol ,
store : store ,
stream : stream ,
iwIndicators : make ( map [ indicatorKey ] indicator . KLinePusher ) ,
iwbIndicators : make ( map [ types . IntervalWindowBandWidth ] * indicator . BOLL ) ,
macdIndicators : make ( map [ indicator . MACDConfig ] * indicator . MACD ) ,
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-08-30 17:21:32 +00:00
func ( s * StandardIndicatorSet ) allocateSimpleIndicator ( t indicator . KLinePusher , iw types . IntervalWindow , id string ) indicator . KLinePusher {
k := indicatorKey {
iw : iw ,
id : id ,
}
inc , ok := s . iwIndicators [ k ]
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 )
2022-08-30 17:21:32 +00:00
s . iwIndicators [ k ] = 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 {
2022-08-30 17:21:32 +00:00
inc := s . allocateSimpleIndicator ( & indicator . SMA { IntervalWindow : iw } , iw , "sma" )
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 {
2022-08-30 17:21:32 +00:00
inc := s . allocateSimpleIndicator ( & indicator . EWMA { IntervalWindow : iw } , iw , "ewma" )
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 {
2022-08-30 17:21:32 +00:00
inc := s . allocateSimpleIndicator ( & indicator . VWMA { IntervalWindow : iw } , iw , "vwma" )
2022-08-24 09:45:32 +00:00
return inc . ( * indicator . VWMA )
}
2022-08-30 17:43:40 +00:00
func ( s * StandardIndicatorSet ) PivotHigh ( iw types . IntervalWindow ) * indicator . PivotHigh {
2022-08-30 17:21:32 +00:00
inc := s . allocateSimpleIndicator ( & indicator . PivotHigh { IntervalWindow : iw } , iw , "pivothigh" )
2022-08-30 17:43:40 +00:00
return inc . ( * indicator . PivotHigh )
}
2022-07-26 09:57:42 +00:00
func ( s * StandardIndicatorSet ) PivotLow ( iw types . IntervalWindow ) * indicator . PivotLow {
2022-08-30 17:21:32 +00:00
inc := s . allocateSimpleIndicator ( & indicator . PivotLow { IntervalWindow : iw } , iw , "pivotlow" )
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 {
2022-08-30 17:21:32 +00:00
inc := s . allocateSimpleIndicator ( & indicator . ATR { IntervalWindow : iw } , iw , "atr" )
2022-07-26 10:03:42 +00:00
return inc . ( * indicator . ATR )
}
func ( s * StandardIndicatorSet ) ATRP ( iw types . IntervalWindow ) * indicator . ATRP {
2022-08-30 17:21:32 +00:00
inc := s . allocateSimpleIndicator ( & indicator . ATRP { IntervalWindow : iw } , iw , "atrp" )
2022-07-26 10:03:42 +00:00
return inc . ( * indicator . ATRP )
}
func ( s * StandardIndicatorSet ) EMV ( iw types . IntervalWindow ) * indicator . EMV {
2022-08-30 17:21:32 +00:00
inc := s . allocateSimpleIndicator ( & indicator . EMV { IntervalWindow : iw } , iw , "emv" )
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 {
2022-08-30 17:21:32 +00:00
inc := s . allocateSimpleIndicator ( & indicator . CCI { IntervalWindow : iw } , iw , "cci" )
2022-07-26 10:04:57 +00:00
return inc . ( * indicator . CCI )
}
2022-07-26 10:27:22 +00:00
func ( s * StandardIndicatorSet ) HULL ( iw types . IntervalWindow ) * indicator . HULL {
2022-08-30 17:21:32 +00:00
inc := s . allocateSimpleIndicator ( & indicator . HULL { IntervalWindow : iw } , iw , "hull" )
2022-07-26 10:27:22 +00:00
return inc . ( * indicator . HULL )
}
2022-07-26 09:57:42 +00:00
func ( s * StandardIndicatorSet ) STOCH ( iw types . IntervalWindow ) * indicator . STOCH {
2022-08-30 17:21:32 +00:00
inc := s . allocateSimpleIndicator ( & indicator . STOCH { IntervalWindow : iw } , iw , "stoch" )
2022-08-24 09:34:19 +00:00
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-12-15 09:50:05 +00:00
inc = & indicator . BOLL { IntervalWindow : iw , K : bandWidth , SMA : & indicator . SMA { IntervalWindow : iw } }
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
}
2022-09-05 09:13:50 +00:00
2022-09-14 10:33:06 +00:00
func ( s * StandardIndicatorSet ) MACD ( iw types . IntervalWindow , shortPeriod , longPeriod int ) * indicator . MACD {
config := indicator . MACDConfig { IntervalWindow : iw , ShortPeriod : shortPeriod , LongPeriod : longPeriod }
inc , ok := s . macdIndicators [ config ]
if ok {
return inc
}
inc = & indicator . MACD { MACDConfig : config }
s . macdIndicators [ config ] = inc
s . initAndBind ( inc , config . IntervalWindow . Interval )
return inc
}
2022-09-05 09:13:50 +00:00
// GHFilter is a helper function that returns the G-H (alpha beta) digital filter of the given interval and the window size.
func ( s * StandardIndicatorSet ) GHFilter ( iw types . IntervalWindow ) * indicator . GHFilter {
inc := s . allocateSimpleIndicator ( & indicator . GHFilter { IntervalWindow : iw } , iw , "ghfilter" )
return inc . ( * indicator . GHFilter )
}
// KalmanFilter is a helper function that returns the Kalman digital filter of the given interval and the window size.
// Note that the additional smooth window is set to zero in standard indicator set. Users have to create their own instance and push K-lines if a smoother filter is needed.
func ( s * StandardIndicatorSet ) KalmanFilter ( iw types . IntervalWindow ) * indicator . KalmanFilter {
inc := s . allocateSimpleIndicator ( & indicator . KalmanFilter { IntervalWindow : iw , AdditionalSmoothWindow : 0 } , iw , "kalmanfilter" )
return inc . ( * indicator . KalmanFilter )
}