bollmaker: add ema cross signal to bollmaker strategy

This commit is contained in:
c9s 2023-12-19 22:17:33 +08:00
parent 6a07af80d8
commit 46329c3a24
No known key found for this signature in database
GPG Key ID: 7385E7E464CB0A54
2 changed files with 39 additions and 3 deletions

View File

@ -17,7 +17,7 @@ backtest:
# see here for more details # see here for more details
# https://www.investopedia.com/terms/m/maximum-drawdown-mdd.asp # https://www.investopedia.com/terms/m/maximum-drawdown-mdd.asp
startTime: "2022-05-01" startTime: "2022-05-01"
endTime: "2022-08-14" endTime: "2023-11-01"
sessions: sessions:
- binance - binance
symbols: symbols:
@ -200,6 +200,12 @@ exchangeStrategies:
# buyBelowNeutralSMA: when this set, it will only place buy order when the current price is below the SMA line. # buyBelowNeutralSMA: when this set, it will only place buy order when the current price is below the SMA line.
buyBelowNeutralSMA: true buyBelowNeutralSMA: true
emaCross:
enabled: true
interval: 1h
fastWindow: 3
slowWindow: 12
exits: exits:
# roiTakeProfit is used to force taking profit by percentage of the position ROI (currently the price change) # roiTakeProfit is used to force taking profit by percentage of the position ROI (currently the price change)

View File

@ -46,9 +46,13 @@ type BollingerSetting struct {
} }
type EMACrossSetting struct { type EMACrossSetting struct {
Enabled bool `json:"enabled"`
Interval types.Interval `json:"interval"` Interval types.Interval `json:"interval"`
FastWindow int `json:"fastWindow"` FastWindow int `json:"fastWindow"`
SlowWindow int `json:"slowWindow"` SlowWindow int `json:"slowWindow"`
fastEMA, slowEMA *indicatorv2.EWMAStream
cross *indicatorv2.CrossStream
} }
type Strategy struct { type Strategy struct {
@ -174,6 +178,8 @@ type Strategy struct {
// neutralBoll is the neutral price section // neutralBoll is the neutral price section
neutralBoll *indicatorv2.BOLLStream neutralBoll *indicatorv2.BOLLStream
shouldBuy bool
// StrategyController // StrategyController
bbgo.StrategyController bbgo.StrategyController
} }
@ -280,6 +286,7 @@ func (s *Strategy) placeOrders(ctx context.Context, midPrice fixedpoint.Value, k
Price: askPrice, Price: askPrice,
Market: s.Market, Market: s.Market,
} }
buyOrder := types.SubmitOrder{ buyOrder := types.SubmitOrder{
Symbol: s.Symbol, Symbol: s.Symbol,
Side: types.SideTypeBuy, Side: types.SideTypeBuy,
@ -438,14 +445,20 @@ func (s *Strategy) placeOrders(ctx context.Context, midPrice fixedpoint.Value, k
} }
} }
if !s.shouldBuy {
log.Infof("shouldBuy is turned off, skip placing buy order")
canBuy = false
}
if canSell { if canSell {
submitOrders = append(submitOrders, sellOrder) submitOrders = append(submitOrders, sellOrder)
} }
if canBuy { if canBuy {
submitOrders = append(submitOrders, buyOrder) submitOrders = append(submitOrders, buyOrder)
} }
// condition for lower the average cost // condition for lowering the average cost
/* /*
if midPrice < s.Position.AverageCost.MulFloat64(1.0-s.MinProfitSpread.Float64()) && canBuy { if midPrice < s.Position.AverageCost.MulFloat64(1.0-s.MinProfitSpread.Float64()) && canBuy {
submitOrders = append(submitOrders, buyOrder) submitOrders = append(submitOrders, buyOrder)
@ -481,9 +494,26 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
// StrategyController // StrategyController
s.Status = types.StrategyStatusRunning s.Status = types.StrategyStatusRunning
s.shouldBuy = true
s.neutralBoll = session.Indicators(s.Symbol).BOLL(s.NeutralBollinger.IntervalWindow, s.NeutralBollinger.BandWidth) s.neutralBoll = session.Indicators(s.Symbol).BOLL(s.NeutralBollinger.IntervalWindow, s.NeutralBollinger.BandWidth)
s.defaultBoll = session.Indicators(s.Symbol).BOLL(s.DefaultBollinger.IntervalWindow, s.DefaultBollinger.BandWidth) s.defaultBoll = session.Indicators(s.Symbol).BOLL(s.DefaultBollinger.IntervalWindow, s.DefaultBollinger.BandWidth)
if s.EMACrossSetting != nil && s.EMACrossSetting.Enabled {
s.EMACrossSetting.fastEMA = session.Indicators(s.Symbol).EWMA(types.IntervalWindow{Interval: s.Interval, Window: s.EMACrossSetting.FastWindow})
s.EMACrossSetting.slowEMA = session.Indicators(s.Symbol).EWMA(types.IntervalWindow{Interval: s.Interval, Window: s.EMACrossSetting.SlowWindow})
s.EMACrossSetting.cross = indicatorv2.Cross(s.EMACrossSetting.fastEMA, s.EMACrossSetting.slowEMA)
s.EMACrossSetting.cross.OnUpdate(func(v float64) {
switch indicatorv2.CrossType(v) {
case indicatorv2.CrossOver:
s.shouldBuy = true
case indicatorv2.CrossUnder:
s.shouldBuy = false
// TODO: can partially close position when necessary
// s.orderExecutor.ClosePosition(ctx)
}
})
}
// Setup dynamic spread // Setup dynamic spread
if s.DynamicSpread.IsEnabled() { if s.DynamicSpread.IsEnabled() {
if s.DynamicSpread.Interval == "" { if s.DynamicSpread.Interval == "" {
@ -565,7 +595,7 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
}) })
session.UserDataStream.OnStart(func() { session.UserDataStream.OnStart(func() {
if s.UseTickerPrice { if !bbgo.IsBackTesting && s.UseTickerPrice {
ticker, err := s.session.Exchange.QueryTicker(ctx, s.Symbol) ticker, err := s.session.Exchange.QueryTicker(ctx, s.Symbol)
if err != nil { if err != nil {
return return