mirror of
https://github.com/c9s/bbgo.git
synced 2024-11-26 16:55:15 +00:00
bollmaker: pull out skew options
This commit is contained in:
parent
d94cc2df31
commit
b98777afe4
|
@ -3,6 +3,7 @@ package bollmaker
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"math"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -66,8 +67,35 @@ type Strategy struct {
|
||||||
DisableShort bool `json:"disableShort"`
|
DisableShort bool `json:"disableShort"`
|
||||||
|
|
||||||
DefaultBollinger *BollingerSetting `json:"defaultBollinger"`
|
DefaultBollinger *BollingerSetting `json:"defaultBollinger"`
|
||||||
|
|
||||||
|
// NeutralBollinger is the smaller range of the bollinger band
|
||||||
|
// If price is in this band, it usually means the price is oscillating.
|
||||||
NeutralBollinger *BollingerSetting `json:"neutralBollinger"`
|
NeutralBollinger *BollingerSetting `json:"neutralBollinger"`
|
||||||
|
|
||||||
|
// StrongDowntrendSkew is the order quantity skew for strong downtrend band.
|
||||||
|
// when the bollinger band detect a strong downtrend, what's the order quantity skew we want to use.
|
||||||
|
// greater than 1.0 means when placing buy order, place sell order with less quantity
|
||||||
|
// less than 1.0 means when placing sell order, place buy order with less quantity
|
||||||
|
StrongDowntrendSkew fixedpoint.Value `json:"strongDowntrendSkew"`
|
||||||
|
|
||||||
|
// StrongUptrendSkew is the order quantity skew for strong uptrend band.
|
||||||
|
// when the bollinger band detect a strong uptrend, what's the order quantity skew we want to use.
|
||||||
|
// greater than 1.0 means when placing buy order, place sell order with less quantity
|
||||||
|
// less than 1.0 means when placing sell order, place buy order with less quantity
|
||||||
|
StrongUptrendSkew fixedpoint.Value `json:"strongUptrendSkew"`
|
||||||
|
|
||||||
|
// DowntrendSkew is the order quantity skew for normal downtrend band.
|
||||||
|
// The price is still in the default bollinger band.
|
||||||
|
// greater than 1.0 means when placing buy order, place sell order with less quantity
|
||||||
|
// less than 1.0 means when placing sell order, place buy order with less quantity
|
||||||
|
DowntrendSkew fixedpoint.Value `json:"downtrendSkew"`
|
||||||
|
|
||||||
|
// UptrendSkew is the order quantity skew for normal uptrend band.
|
||||||
|
// The price is still in the default bollinger band.
|
||||||
|
// greater than 1.0 means when placing buy order, place sell order with less quantity
|
||||||
|
// less than 1.0 means when placing sell order, place buy order with less quantity
|
||||||
|
UptrendSkew fixedpoint.Value `json:"uptrendSkew"`
|
||||||
|
|
||||||
session *bbgo.ExchangeSession
|
session *bbgo.ExchangeSession
|
||||||
book *types.StreamOrderBook
|
book *types.StreamOrderBook
|
||||||
market types.Market
|
market types.Market
|
||||||
|
@ -214,11 +242,12 @@ func (s *Strategy) placeOrders(ctx context.Context, orderExecutor bbgo.OrderExec
|
||||||
base := s.state.Position.GetBase()
|
base := s.state.Position.GetBase()
|
||||||
balances := s.session.Account.Balances()
|
balances := s.session.Account.Balances()
|
||||||
|
|
||||||
log.Infof("mid price:%f spread: %s ask:%f bid: %f",
|
log.Infof("mid price:%f spread: %s ask:%f bid: %f position: %s",
|
||||||
midPrice.Float64(),
|
midPrice.Float64(),
|
||||||
s.Spread.Percentage(),
|
s.Spread.Percentage(),
|
||||||
askPrice.Float64(),
|
askPrice.Float64(),
|
||||||
bidPrice.Float64(),
|
bidPrice.Float64(),
|
||||||
|
s.state.Position.String(),
|
||||||
)
|
)
|
||||||
|
|
||||||
quantity := s.Quantity
|
quantity := s.Quantity
|
||||||
|
@ -246,8 +275,8 @@ func (s *Strategy) placeOrders(ctx context.Context, orderExecutor bbgo.OrderExec
|
||||||
minQuantity := fixedpoint.NewFromFloat(s.market.MinQuantity)
|
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)
|
canBuy := hasQuoteBalance && quoteBalance.Available > s.Quantity.Mul(midPrice) && (s.MaxExposurePosition > 0 && base < s.MaxExposurePosition)
|
||||||
canSell := hasBaseBalance && baseBalance.Available > s.Quantity
|
canSell := hasBaseBalance && baseBalance.Available > s.Quantity && (s.MaxExposurePosition > 0 && base > -s.MaxExposurePosition)
|
||||||
|
|
||||||
// adjust quantity for closing position if we over sold or over bought
|
// adjust quantity for closing position if we over sold or over bought
|
||||||
if s.MaxExposurePosition > 0 && base.Abs() > s.MaxExposurePosition {
|
if s.MaxExposurePosition > 0 && base.Abs() > s.MaxExposurePosition {
|
||||||
|
@ -261,10 +290,11 @@ func (s *Strategy) placeOrders(ctx context.Context, orderExecutor bbgo.OrderExec
|
||||||
}
|
}
|
||||||
|
|
||||||
qf := scale.Call(base.Abs().Float64())
|
qf := scale.Call(base.Abs().Float64())
|
||||||
|
_ = qf
|
||||||
if base > minQuantity {
|
if base > minQuantity {
|
||||||
sellOrder.Quantity = qf
|
// sellOrder.Quantity = qf
|
||||||
} else if base < -minQuantity {
|
} else if base < -minQuantity {
|
||||||
buyOrder.Quantity = qf
|
// buyOrder.Quantity = qf
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -278,31 +308,42 @@ func (s *Strategy) placeOrders(ctx context.Context, orderExecutor bbgo.OrderExec
|
||||||
if !s.DisableShort && canSell {
|
if !s.DisableShort && canSell {
|
||||||
submitOrders = append(submitOrders, sellOrder)
|
submitOrders = append(submitOrders, sellOrder)
|
||||||
}
|
}
|
||||||
} else if base > minQuantity {
|
|
||||||
if midPrice > s.state.Position.AverageCost.MulFloat64(1.0+s.MinProfitSpread.Float64()) && canSell {
|
|
||||||
if !(s.DisableShort && (base.Float64() - sellOrder.Quantity < 0)) {
|
|
||||||
submitOrders = append(submitOrders, sellOrder)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
} else if midPrice.Float64() > s.defaultBoll.LastDownBand() && midPrice.Float64() < s.neutralBoll.LastDownBand() { // downtrend, might bounce back
|
||||||
|
|
||||||
if midPrice < s.state.Position.AverageCost.MulFloat64(1.0-s.MinProfitSpread.Float64()) && canBuy {
|
skew := 2.0
|
||||||
submitOrders = append(submitOrders, buyOrder)
|
ratio := 1.0 / skew
|
||||||
}
|
sellOrder.Quantity = math.Max(s.market.MinQuantity, buyOrder.Quantity*ratio)
|
||||||
} else if base < -minQuantity {
|
|
||||||
if midPrice > s.state.Position.AverageCost.MulFloat64(1.0+s.MinProfitSpread.Float64()) && canSell {
|
} else if midPrice.Float64() < s.defaultBoll.LastUpBand() && midPrice.Float64() > s.neutralBoll.LastUpBand() { // uptrend, might bounce back
|
||||||
if !(s.DisableShort && (base.Float64() - sellOrder.Quantity < 0)) {
|
|
||||||
submitOrders = append(submitOrders, sellOrder)
|
skew := 0.5
|
||||||
}
|
buyOrder.Quantity = math.Max(s.market.MinQuantity, sellOrder.Quantity*skew)
|
||||||
}
|
|
||||||
|
|
||||||
if midPrice < s.state.Position.AverageCost.MulFloat64(1.0-s.MinProfitSpread.Float64()) && canBuy {
|
|
||||||
submitOrders = append(submitOrders, buyOrder)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if midPrice.Float64() < s.defaultBoll.LastDownBand() { // strong downtrend
|
} else if midPrice.Float64() < s.defaultBoll.LastDownBand() { // strong downtrend
|
||||||
|
|
||||||
|
skew := s.StrongDowntrendSkew.Float64()
|
||||||
|
ratio := 1.0 / skew
|
||||||
|
sellOrder.Quantity = math.Max(s.market.MinQuantity, buyOrder.Quantity*ratio)
|
||||||
|
|
||||||
} else if midPrice.Float64() > s.defaultBoll.LastUpBand() { // strong uptrend
|
} else if midPrice.Float64() > s.defaultBoll.LastUpBand() { // strong uptrend
|
||||||
|
|
||||||
|
skew := s.StrongUptrendSkew.Float64()
|
||||||
|
buyOrder.Quantity = math.Max(s.market.MinQuantity, sellOrder.Quantity*skew)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if midPrice > s.state.Position.AverageCost.MulFloat64(1.0+s.MinProfitSpread.Float64()) && canSell {
|
||||||
|
if !(s.DisableShort && (base.Float64()-sellOrder.Quantity < 0)) {
|
||||||
|
submitOrders = append(submitOrders, sellOrder)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if midPrice < s.state.Position.AverageCost.MulFloat64(1.0-s.MinProfitSpread.Float64()) && canBuy {
|
||||||
|
// submitOrders = append(submitOrders, buyOrder)
|
||||||
|
}
|
||||||
|
if canBuy {
|
||||||
|
submitOrders = append(submitOrders, buyOrder)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(submitOrders) == 0 {
|
if len(submitOrders) == 0 {
|
||||||
|
@ -318,13 +359,29 @@ func (s *Strategy) placeOrders(ctx context.Context, orderExecutor bbgo.OrderExec
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, session *bbgo.ExchangeSession) error {
|
func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, session *bbgo.ExchangeSession) error {
|
||||||
// initial required information
|
|
||||||
s.session = session
|
|
||||||
|
|
||||||
if s.MinProfitSpread == 0 {
|
if s.MinProfitSpread == 0 {
|
||||||
s.MinProfitSpread = fixedpoint.NewFromFloat(0.001)
|
s.MinProfitSpread = fixedpoint.NewFromFloat(0.001)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if s.StrongUptrendSkew == 0 {
|
||||||
|
s.StrongUptrendSkew = fixedpoint.NewFromFloat(1.0 / 5.0)
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.StrongDowntrendSkew == 0 {
|
||||||
|
s.StrongDowntrendSkew = fixedpoint.NewFromFloat(5.0)
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.UptrendSkew == 0 {
|
||||||
|
s.UptrendSkew = fixedpoint.NewFromFloat(1.0 / 2.0)
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.DowntrendSkew == 0 {
|
||||||
|
s.DowntrendSkew = fixedpoint.NewFromFloat(2.0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// initial required information
|
||||||
|
s.session = session
|
||||||
|
|
||||||
market, ok := session.Market(s.Symbol)
|
market, ok := session.Market(s.Symbol)
|
||||||
if !ok {
|
if !ok {
|
||||||
return fmt.Errorf("market %s not found", s.Symbol)
|
return fmt.Errorf("market %s not found", s.Symbol)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user