mirror of
https://github.com/c9s/bbgo.git
synced 2024-11-22 06:53:52 +00:00
bollmaker: add Test_calculateBandPercentage test
This commit is contained in:
parent
f9d650cd23
commit
aea8f97ab9
|
@ -287,6 +287,18 @@ func (s *Strategy) LoadState() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Strategy) getCurrentAllowedExposurePosition(bandPercentage float64) (fixedpoint.Value, error) {
|
||||||
|
if s.DynamicExposurePositionScale != nil {
|
||||||
|
v, err := s.DynamicExposurePositionScale.Scale(bandPercentage)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return fixedpoint.NewFromFloat(v), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return s.MaxExposurePosition, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Strategy) placeOrders(ctx context.Context, orderExecutor bbgo.OrderExecutor, midPrice fixedpoint.Value, kline *types.KLine) {
|
func (s *Strategy) placeOrders(ctx context.Context, orderExecutor bbgo.OrderExecutor, midPrice fixedpoint.Value, kline *types.KLine) {
|
||||||
askPrice := midPrice.Mul(one + s.Spread)
|
askPrice := midPrice.Mul(one + s.Spread)
|
||||||
bidPrice := midPrice.Mul(one - s.Spread)
|
bidPrice := midPrice.Mul(one - s.Spread)
|
||||||
|
@ -301,7 +313,6 @@ func (s *Strategy) placeOrders(ctx context.Context, orderExecutor bbgo.OrderExec
|
||||||
s.state.Position.String(),
|
s.state.Position.String(),
|
||||||
)
|
)
|
||||||
|
|
||||||
quantity := s.CalculateQuantity(midPrice)
|
|
||||||
sellQuantity := s.CalculateQuantity(askPrice)
|
sellQuantity := s.CalculateQuantity(askPrice)
|
||||||
buyQuantity := s.CalculateQuantity(bidPrice)
|
buyQuantity := s.CalculateQuantity(bidPrice)
|
||||||
|
|
||||||
|
@ -326,14 +337,25 @@ func (s *Strategy) placeOrders(ctx context.Context, orderExecutor bbgo.OrderExec
|
||||||
|
|
||||||
var submitOrders []types.SubmitOrder
|
var submitOrders []types.SubmitOrder
|
||||||
|
|
||||||
minQuantity := fixedpoint.NewFromFloat(s.market.MinQuantity)
|
|
||||||
baseBalance, hasBaseBalance := balances[s.market.BaseCurrency]
|
baseBalance, hasBaseBalance := balances[s.market.BaseCurrency]
|
||||||
quoteBalance, hasQuoteBalance := balances[s.market.QuoteCurrency]
|
quoteBalance, hasQuoteBalance := balances[s.market.QuoteCurrency]
|
||||||
canBuy := hasQuoteBalance && quoteBalance.Available > s.Quantity.Mul(midPrice) && (s.MaxExposurePosition > 0 && base < s.MaxExposurePosition)
|
|
||||||
canSell := hasBaseBalance && baseBalance.Available > s.Quantity && (s.MaxExposurePosition > 0 && base > -s.MaxExposurePosition)
|
downBand := s.defaultBoll.LastDownBand()
|
||||||
|
upBand := s.defaultBoll.LastUpBand()
|
||||||
|
sma := s.defaultBoll.LastSMA()
|
||||||
|
log.Infof("bollinger band: up %f sma %f down %f", upBand, sma, downBand)
|
||||||
|
|
||||||
|
bandPercentage := calculateBandPercentage(upBand, downBand, sma, midPrice.Float64())
|
||||||
|
maxExposurePosition, err := s.getCurrentAllowedExposurePosition(bandPercentage)
|
||||||
|
if err != nil {
|
||||||
|
log.WithError(err).Errorf("can not calculate CurrentAllowedExposurePosition")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
canBuy := hasQuoteBalance && quoteBalance.Available > s.Quantity.Mul(midPrice) && (maxExposurePosition > 0 && base < maxExposurePosition)
|
||||||
|
canSell := hasBaseBalance && baseBalance.Available > s.Quantity && (maxExposurePosition > 0 && base > -maxExposurePosition)
|
||||||
|
|
||||||
if s.ShadowProtection && kline != nil {
|
if s.ShadowProtection && kline != nil {
|
||||||
|
|
||||||
switch kline.Direction() {
|
switch kline.Direction() {
|
||||||
case types.DirectionDown:
|
case types.DirectionDown:
|
||||||
shadowHeight := kline.GetLowerShadowHeight()
|
shadowHeight := kline.GetLowerShadowHeight()
|
||||||
|
@ -352,26 +374,6 @@ func (s *Strategy) placeOrders(ctx context.Context, orderExecutor bbgo.OrderExec
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// adjust quantity for closing position if we over sold or over bought
|
|
||||||
if s.MaxExposurePosition > 0 && base.Abs() > s.MaxExposurePosition {
|
|
||||||
scale := &bbgo.ExponentialScale{
|
|
||||||
Domain: [2]float64{0, s.MaxExposurePosition.Float64()},
|
|
||||||
Range: [2]float64{quantity.Float64(), base.Abs().Float64()},
|
|
||||||
}
|
|
||||||
if err := scale.Solve(); err != nil {
|
|
||||||
log.WithError(err).Errorf("scale solving error")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
qf := scale.Call(base.Abs().Float64())
|
|
||||||
_ = qf
|
|
||||||
if base > minQuantity {
|
|
||||||
// sellOrder.Quantity = qf
|
|
||||||
} else if base < -minQuantity {
|
|
||||||
// buyOrder.Quantity = qf
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if midPrice.Float64() > s.neutralBoll.LastDownBand() && midPrice.Float64() < s.neutralBoll.LastUpBand() {
|
if midPrice.Float64() > s.neutralBoll.LastDownBand() && midPrice.Float64() < s.neutralBoll.LastUpBand() {
|
||||||
// we don't have position yet
|
// we don't have position yet
|
||||||
// place orders on both side if it's in oscillating band
|
// place orders on both side if it's in oscillating band
|
||||||
|
@ -587,3 +589,15 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func calculateBandPercentage(up, down, sma, midPrice float64) float64 {
|
||||||
|
if midPrice < sma {
|
||||||
|
// should be negative percentage
|
||||||
|
return (midPrice - sma) / math.Abs(sma-down)
|
||||||
|
} else if midPrice > sma {
|
||||||
|
// should be positive percentage
|
||||||
|
return (midPrice - sma) / math.Abs(up-sma)
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0.0
|
||||||
|
}
|
||||||
|
|
69
pkg/strategy/bollmaker/strategy_test.go
Normal file
69
pkg/strategy/bollmaker/strategy_test.go
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
package bollmaker
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/c9s/bbgo/pkg/fixedpoint"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_calculateBandPercentage(t *testing.T) {
|
||||||
|
type args struct {
|
||||||
|
up float64
|
||||||
|
down float64
|
||||||
|
sma float64
|
||||||
|
midPrice float64
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
want fixedpoint.Value
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "positive boundary",
|
||||||
|
args: args{
|
||||||
|
up: 2000.0,
|
||||||
|
sma: 1500.0,
|
||||||
|
down: 1000.0,
|
||||||
|
midPrice: 2000.0,
|
||||||
|
},
|
||||||
|
want: fixedpoint.NewFromFloat(1.0),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "inside positive boundary",
|
||||||
|
args: args{
|
||||||
|
up: 2000.0,
|
||||||
|
sma: 1500.0,
|
||||||
|
down: 1000.0,
|
||||||
|
midPrice: 1600.0,
|
||||||
|
},
|
||||||
|
want: fixedpoint.NewFromFloat(0.2), // 20%
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "negative boundary",
|
||||||
|
args: args{
|
||||||
|
up: 2000.0,
|
||||||
|
sma: 1500.0,
|
||||||
|
down: 1000.0,
|
||||||
|
midPrice: 1000.0,
|
||||||
|
},
|
||||||
|
want: fixedpoint.NewFromFloat(-1.0),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "out of negative boundary",
|
||||||
|
args: args{
|
||||||
|
up: 2000.0,
|
||||||
|
sma: 1500.0,
|
||||||
|
down: 1000.0,
|
||||||
|
midPrice: 800.0,
|
||||||
|
},
|
||||||
|
want: fixedpoint.NewFromFloat(-1.4),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
if got := calculateBandPercentage(tt.args.up, tt.args.down, tt.args.sma, tt.args.midPrice); fixedpoint.NewFromFloat(got) != tt.want {
|
||||||
|
t.Errorf("calculateBandPercentage() = %v, want %v", got, tt.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user