diff --git a/pkg/strategy/pivotshort/breaklow.go b/pkg/strategy/pivotshort/breaklow.go index d0d744454..807e8d8a8 100644 --- a/pkg/strategy/pivotshort/breaklow.go +++ b/pkg/strategy/pivotshort/breaklow.go @@ -17,6 +17,28 @@ type StopEMA struct { type TrendEMA struct { types.IntervalWindow + + trendEWMA *indicator.EWMA + + trendEWMALast, trendEWMACurrent float64 +} + +func (s *TrendEMA) Bind(session *bbgo.ExchangeSession, orderExecutor *bbgo.GeneralOrderExecutor) { + symbol := orderExecutor.Position().Symbol + s.trendEWMA = session.StandardIndicatorSet(symbol).EWMA(s.IntervalWindow) + session.MarketDataStream.OnKLineClosed(types.KLineWith(symbol, s.Interval, func(kline types.KLine) { + s.trendEWMALast = s.trendEWMACurrent + s.trendEWMACurrent = s.trendEWMA.Last() + })) +} + +func (s *TrendEMA) Gradient() (float64, bool) { + if s.trendEWMALast > 0.0 && s.trendEWMACurrent > 0.0 { + gradient := s.trendEWMALast / s.trendEWMACurrent + return gradient, true + } + + return 0.0, false } type FakeBreakStop struct { @@ -58,7 +80,6 @@ type BreakLow struct { stopEWMA *indicator.EWMA - trendEWMA *indicator.EWMA trendEWMALast, trendEWMACurrent float64 orderExecutor *bbgo.GeneralOrderExecutor @@ -99,12 +120,7 @@ func (s *BreakLow) Bind(session *bbgo.ExchangeSession, orderExecutor *bbgo.Gener } if s.TrendEMA != nil { - s.trendEWMA = standardIndicator.EWMA(s.TrendEMA.IntervalWindow) - - session.MarketDataStream.OnKLineClosed(types.KLineWith(s.Symbol, s.TrendEMA.Interval, func(kline types.KLine) { - s.trendEWMALast = s.trendEWMACurrent - s.trendEWMACurrent = s.trendEWMA.Last() - })) + s.TrendEMA.Bind(session, orderExecutor) } // update pivot low data @@ -197,14 +213,13 @@ func (s *BreakLow) Bind(session *bbgo.ExchangeSession, orderExecutor *bbgo.Gener } // trend EMA protection - if s.trendEWMALast > 0.0 && s.trendEWMACurrent > 0.0 { - slope := s.trendEWMALast / s.trendEWMACurrent - if slope > 1.0 { - log.Infof("trendEMA %+v current=%f last=%f slope=%f: skip short", s.TrendEMA, s.trendEWMACurrent, s.trendEWMALast, slope) + if gradient, ok := s.TrendEMA.Gradient(); ok { + if gradient > 1.0 { + log.Infof("trendEMA %+v current=%f last=%f slope=%f: skip short", s.TrendEMA, s.TrendEMA.trendEWMACurrent, s.TrendEMA.trendEWMALast, gradient) return } - log.Infof("trendEMA %+v current=%f last=%f slope=%f: short is enabled", s.TrendEMA, s.trendEWMACurrent, s.trendEWMALast, slope) + log.Infof("trendEMA %+v current=%f last=%f slope=%f: short is enabled", s.TrendEMA, s.TrendEMA.trendEWMACurrent, s.TrendEMA.trendEWMALast, gradient) } // stop EMA protection diff --git a/pkg/strategy/pivotshort/resistance.go b/pkg/strategy/pivotshort/resistance.go index 4342d78b1..dde5d3220 100644 --- a/pkg/strategy/pivotshort/resistance.go +++ b/pkg/strategy/pivotshort/resistance.go @@ -25,6 +25,8 @@ type ResistanceShort struct { Leverage fixedpoint.Value `json:"leverage"` Ratio fixedpoint.Value `json:"ratio"` + TrendEMA *TrendEMA `json:"trendEMA"` + session *bbgo.ExchangeSession orderExecutor *bbgo.GeneralOrderExecutor @@ -35,7 +37,17 @@ type ResistanceShort struct { activeOrders *bbgo.ActiveOrderBook } +func (s *ResistanceShort) Subscribe(session *bbgo.ExchangeSession) { + if s.TrendEMA != nil { + session.Subscribe(types.KLineChannel, s.Symbol, types.SubscribeOptions{Interval: s.TrendEMA.Interval}) + } +} + func (s *ResistanceShort) Bind(session *bbgo.ExchangeSession, orderExecutor *bbgo.GeneralOrderExecutor) { + if s.GroupDistance.IsZero() { + s.GroupDistance = fixedpoint.NewFromFloat(0.01) + } + s.session = session s.orderExecutor = orderExecutor s.activeOrders = bbgo.NewActiveOrderBook(s.Symbol) @@ -45,8 +57,8 @@ func (s *ResistanceShort) Bind(session *bbgo.ExchangeSession, orderExecutor *bbg }) s.activeOrders.BindStream(session.UserDataStream) - if s.GroupDistance.IsZero() { - s.GroupDistance = fixedpoint.NewFromFloat(0.01) + if s.TrendEMA != nil { + s.TrendEMA.Bind(session, orderExecutor) } s.resistancePivot = session.StandardIndicatorSet(s.Symbol).PivotLow(s.IntervalWindow) @@ -55,6 +67,16 @@ func (s *ResistanceShort) Bind(session *bbgo.ExchangeSession, orderExecutor *bbg s.updateResistanceOrders(fixedpoint.NewFromFloat(s.resistancePivot.Last())) session.MarketDataStream.OnKLineClosed(types.KLineWith(s.Symbol, s.Interval, func(kline types.KLine) { + // trend EMA protection + if gradient, ok := s.TrendEMA.Gradient(); ok { + if gradient > 1.0 { + log.Infof("trendEMA %+v current=%f last=%f slope=%f: skip short", s.TrendEMA, s.TrendEMA.trendEWMACurrent, s.TrendEMA.trendEWMALast, gradient) + return + } + + log.Infof("trendEMA %+v current=%f last=%f slope=%f: short is enabled", s.TrendEMA, s.TrendEMA.trendEWMACurrent, s.TrendEMA.trendEWMALast, gradient) + } + position := s.orderExecutor.Position() if position.IsOpened(kline.Close) { return