diff --git a/config/pivotshort.yaml b/config/pivotshort.yaml index b322f1705..a9223f8d2 100644 --- a/config/pivotshort.yaml +++ b/config/pivotshort.yaml @@ -101,12 +101,12 @@ exchangeStrategies: minQuoteVolume: 200_000_000 - trailingStop: - callbackRate: 2% + callbackRate: 3% # activationRatio is relative to the average cost, # when side is buy, 1% means lower 1% than the average cost. # when side is sell, 1% means higher 1% than the average cost. - activationRatio: 10% + activationRatio: 40% # minProfit uses the position ROI to calculate the profit ratio # minProfit: 1% diff --git a/pkg/strategy/autoborrow/strategy.go b/pkg/strategy/autoborrow/strategy.go index 94c9f8a6a..f0e4ff180 100644 --- a/pkg/strategy/autoborrow/strategy.go +++ b/pkg/strategy/autoborrow/strategy.go @@ -123,7 +123,7 @@ func (s *Strategy) checkAndBorrow(ctx context.Context) { minMarginLevel := s.MinMarginLevel curMarginLevel := account.MarginLevel - bbgo.Notify("%s: current margin level: %s, margin ratio: %s, margin tolerance: %s", + log.Infof("%s: current margin level: %s, margin ratio: %s, margin tolerance: %s", s.ExchangeSession.Name, account.MarginLevel.String(), account.MarginRatio.String(), diff --git a/pkg/strategy/pivotshort/breaklow.go b/pkg/strategy/pivotshort/breaklow.go index d446a82ff..84678a0bf 100644 --- a/pkg/strategy/pivotshort/breaklow.go +++ b/pkg/strategy/pivotshort/breaklow.go @@ -29,9 +29,15 @@ type BreakLow struct { StopEMARange fixedpoint.Value `json:"stopEMARange"` StopEMA *types.IntervalWindow `json:"stopEMA"` - lastLow fixedpoint.Value - pivot *indicator.Pivot - stopEWMA *indicator.EWMA + TrendEMA *types.IntervalWindow `json:"trendEMA"` + + lastLow fixedpoint.Value + pivot *indicator.Pivot + stopEWMA *indicator.EWMA + + trendEWMA *indicator.EWMA + trendEWMALast, trendEWMACurrent float64 + pivotLowPrices []fixedpoint.Value orderExecutor *bbgo.GeneralOrderExecutor @@ -41,6 +47,14 @@ type BreakLow struct { func (s *BreakLow) Subscribe(session *bbgo.ExchangeSession) { session.Subscribe(types.KLineChannel, s.Symbol, types.SubscribeOptions{Interval: s.Interval}) session.Subscribe(types.KLineChannel, s.Symbol, types.SubscribeOptions{Interval: types.Interval1m}) + + if s.StopEMA != nil { + session.Subscribe(types.KLineChannel, s.Symbol, types.SubscribeOptions{Interval: s.StopEMA.Interval}) + } + + if s.TrendEMA != nil { + session.Subscribe(types.KLineChannel, s.Symbol, types.SubscribeOptions{Interval: s.TrendEMA.Interval}) + } } func (s *BreakLow) Bind(session *bbgo.ExchangeSession, orderExecutor *bbgo.GeneralOrderExecutor) { @@ -62,6 +76,15 @@ func (s *BreakLow) Bind(session *bbgo.ExchangeSession, orderExecutor *bbgo.Gener s.stopEWMA = standardIndicator.EWMA(*s.StopEMA) } + if s.TrendEMA != nil { + s.trendEWMA = standardIndicator.EWMA(*s.TrendEMA) + + session.MarketDataStream.OnKLineClosed(types.KLineWith(s.Symbol, s.TrendEMA.Interval, func(kline types.KLine) { + s.trendEWMALast = s.trendEWMACurrent + s.trendEWMACurrent = s.trendEWMA.Last() + })) + } + // update pivot low data session.MarketDataStream.OnKLineClosed(types.KLineWith(symbol, s.Interval, func(kline types.KLine) { lastLow := fixedpoint.NewFromFloat(s.pivot.LastLow()) @@ -78,10 +101,6 @@ func (s *BreakLow) Bind(session *bbgo.ExchangeSession, orderExecutor *bbgo.Gener })) session.MarketDataStream.OnKLineClosed(types.KLineWith(symbol, types.Interval1m, func(kline types.KLine) { - if position.IsOpened(kline.Close) { - return - } - if len(s.pivotLowPrices) == 0 { log.Infof("currently there is no pivot low prices, can not check break low...") return @@ -114,6 +133,22 @@ func (s *BreakLow) Bind(session *bbgo.ExchangeSession, orderExecutor *bbgo.Gener log.Infof("%s breakLow signal detected, closed price %f < breakPrice %f", kline.Symbol, closePrice.Float64(), breakPrice.Float64()) + if position.IsOpened(kline.Close) { + log.Infof("position is already opened, skip short") + return + } + + // 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) + return + } + + log.Infof("trendEMA %+v current=%f last=%f slope=%f: short is enabled", s.TrendEMA, s.trendEWMACurrent, s.trendEWMALast, slope) + } + // stop EMA protection if s.stopEWMA != nil { ema := fixedpoint.NewFromFloat(s.stopEWMA.Last())