diff --git a/pkg/bbgo/scale.go b/pkg/bbgo/scale.go index 5c0806d64..e51ef2633 100644 --- a/pkg/bbgo/scale.go +++ b/pkg/bbgo/scale.go @@ -218,6 +218,27 @@ type SlideRule struct { QuadraticScale *QuadraticScale `json:"quadratic"` } +func (rule *SlideRule) Range() ([2]float64, error) { + if rule.LogScale != nil { + return rule.LogScale.Range, nil + } + + if rule.ExpScale != nil { + return rule.ExpScale.Range, nil + } + + if rule.LinearScale != nil { + return rule.LinearScale.Range, nil + } + + if rule.QuadraticScale != nil { + r := rule.QuadraticScale.Range + return [2]float64{r[0], r[len(r)-1]}, nil + } + + return [2]float64{}, errors.New("no any scale domain is defined") +} + func (rule *SlideRule) Scale() (Scale, error) { if rule.LogScale != nil { return rule.LogScale, nil @@ -238,7 +259,6 @@ func (rule *SlideRule) Scale() (Scale, error) { return nil, errors.New("no any scale is defined") } - // LayerScale defines the scale DSL for maker layers, e.g., // // quantityScale: @@ -276,7 +296,6 @@ func (s *LayerScale) Scale(layer int) (quantity float64, err error) { return scale.Call(float64(layer)), nil } - // PriceVolumeScale defines the scale DSL for strategy, e.g., // // quantityScale: diff --git a/pkg/strategy/support/strategy.go b/pkg/strategy/support/strategy.go index 35df9df75..5d8299c8d 100644 --- a/pkg/strategy/support/strategy.go +++ b/pkg/strategy/support/strategy.go @@ -43,6 +43,7 @@ type Strategy struct { MovingAverageWindow int `json:"movingAverageWindow"` Quantity fixedpoint.Value `json:"quantity"` MinVolume fixedpoint.Value `json:"minVolume"` + Sensitivity fixedpoint.Value `json:"sensitivity"` TakerBuyRatio fixedpoint.Value `json:"takerBuyRatio"` MarginOrderSideEffect types.MarginOrderSideEffectType `json:"marginOrderSideEffect"` Targets []Target `json:"targets"` @@ -68,8 +69,8 @@ func (s *Strategy) Validate() error { return fmt.Errorf("quantity or scaleQuantity can not be zero") } - if s.MinVolume == 0 { - return fmt.Errorf("minVolume can not be zero") + if s.MinVolume == 0 && s.Sensitivity == 0 { + return fmt.Errorf("either minVolume nor sensitivity can not be zero") } return nil @@ -137,6 +138,16 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se s.MovingAverageWindow = 99 } + if s.Sensitivity > 0 { + volRange, err := s.ScaleQuantity.ByVolumeRule.Range() + if err != nil { + return err + } + + s.MinVolume = fixedpoint.NewFromFloat(volRange[1]).Mul(fixedpoint.NewFromFloat(1.0) - s.Sensitivity) + log.Infof("adjusted minimal triggering volume to %f according to sensitivity %f", s.MinVolume.Float64(), s.Sensitivity.Float64()) + } + market, ok := session.Market(s.Symbol) if !ok { return fmt.Errorf("market %s is not defined", s.Symbol)