diff --git a/config/bbgo.yaml b/config/bbgo.yaml index 54c1d346a6..759ac626b1 100644 --- a/config/bbgo.yaml +++ b/config/bbgo.yaml @@ -65,5 +65,6 @@ exchangeStrategies: buyandhold: symbol: "BTCUSDT" interval: "1h" - minDropPercentage: -0.01 baseQuantity: 0.01 + # minDropPercentage: 0.01 + minDropChange: 100.0 diff --git a/pkg/strategy/buyandhold/strategy.go b/pkg/strategy/buyandhold/strategy.go index 8f72c9cb06..39e4e69d15 100644 --- a/pkg/strategy/buyandhold/strategy.go +++ b/pkg/strategy/buyandhold/strategy.go @@ -2,23 +2,29 @@ package buyandhold import ( "context" + "fmt" "math" - log "github.com/sirupsen/logrus" + "github.com/sirupsen/logrus" "github.com/c9s/bbgo/pkg/bbgo" + "github.com/c9s/bbgo/pkg/fixedpoint" "github.com/c9s/bbgo/pkg/types" ) +var log = logrus.WithField("strategy", "buyandhold") + func init() { bbgo.RegisterStrategy("buyandhold", &Strategy{}) } type Strategy struct { - Symbol string `json:"symbol"` - Interval string `json:"interval"` - BaseQuantity float64 `json:"baseQuantity"` - MinDropPercentage float64 `json:"minDropPercentage"` + Symbol string `json:"symbol"` + + Interval string `json:"interval"` + BaseQuantity float64 `json:"baseQuantity"` + MinDropPercentage fixedpoint.Value `json:"minDropPercentage"` + MinDropChange fixedpoint.Value `json:"minDropChange"` } func (s *Strategy) Subscribe(session *bbgo.ExchangeSession) { @@ -26,6 +32,12 @@ func (s *Strategy) Subscribe(session *bbgo.ExchangeSession) { } func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, session *bbgo.ExchangeSession) error { + // buy when price drops -8% + market, ok := session.Market(s.Symbol) + if !ok { + return fmt.Errorf("market %s is not defined", s.Symbol) + } + session.Stream.OnKLine(func(kline types.KLine) { // skip k-lines from other symbols if kline.Symbol != s.Symbol { @@ -33,7 +45,7 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se } changePercentage := kline.GetChange() / kline.Open - log.Infof("change %f <=> %f", changePercentage, s.MinDropPercentage) + log.Infof("change %f <=> %f", changePercentage, s.MinDropPercentage.Float64()) }) session.Stream.OnKLineClosed(func(kline types.KLine) { @@ -42,20 +54,30 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se return } - changePercentage := kline.GetChange() / kline.Open + change := kline.GetChange() - if changePercentage > s.MinDropPercentage { + // skip positive change + if change > 0 { return } - // buy when price drops -8% - market, ok := session.Market(s.Symbol) - if !ok { - log.Warnf("market %s is not defined", s.Symbol) + changeP := change / kline.Open + + if s.MinDropPercentage != 0 { + if math.Abs(changeP) < math.Abs(s.MinDropPercentage.Float64()) { + return + } + } else if s.MinDropChange != 0 { + if math.Abs(change) < math.Abs(s.MinDropChange.Float64()) { + return + } + } else { + // not configured, we shall skip + log.Warnf("parameters are not configured, skipping action...") return } - quantity := s.BaseQuantity * (1.0 + math.Abs(changePercentage)) + quantity := s.BaseQuantity * (1.0 + math.Abs(changeP)) _, err := orderExecutor.SubmitOrders(ctx, types.SubmitOrder{ Symbol: kline.Symbol, Market: market,