diff --git a/pkg/indicator/low.go b/pkg/indicator/low.go index 7a5cdeaa0..c654a0f45 100644 --- a/pkg/indicator/low.go +++ b/pkg/indicator/low.go @@ -34,9 +34,3 @@ func (inc *Low) PushK(k types.KLine) { inc.EndTime = k.EndTime.Time() inc.EmitUpdate(inc.Last()) } - -func (inc *Low) LoadK(allKLines []types.KLine) { - for _, k := range allKLines { - inc.PushK(k) - } -} diff --git a/pkg/indicator/macd.go b/pkg/indicator/macd.go index 81e7a0f70..89ba97294 100644 --- a/pkg/indicator/macd.go +++ b/pkg/indicator/macd.go @@ -60,42 +60,22 @@ func (inc *MACD) Last() float64 { return inc.Values[len(inc.Values)-1] } +func (inc *MACD) Length() int { + return len(inc.Values) +} + func (inc *MACD) PushK(k types.KLine) { inc.Update(k.Close.Float64()) } -func (inc *MACD) CalculateAndUpdate(allKLines []types.KLine) { - if len(allKLines) == 0 { - return - } - - last := allKLines[len(allKLines)-1] - if len(inc.Values) == 0 { - for _, k := range allKLines { - if inc.EndTime != zeroTime && !k.EndTime.After(inc.EndTime) { - continue - } - - inc.PushK(k) - } - } else { - inc.PushK(last) - } - - inc.EmitUpdate(inc.Last()) - inc.EndTime = last.EndTime.Time() +func (inc *MACD) MACD() types.SeriesExtend { + out := &MACDValues{MACD: inc} + out.SeriesBase.Series = out + return out } -func (inc *MACD) handleKLineWindowUpdate(interval types.Interval, window types.KLineWindow) { - if inc.Interval != interval { - return - } - - inc.CalculateAndUpdate(window) -} - -func (inc *MACD) Bind(updater KLineWindowUpdater) { - updater.OnKLineWindowUpdate(inc.handleKLineWindowUpdate) +func (inc *MACD) Singals() types.SeriesExtend { + return inc.SignalLine } type MACDValues struct { @@ -123,13 +103,3 @@ func (inc *MACDValues) Index(i int) float64 { func (inc *MACDValues) Length() int { return len(inc.Values) } - -func (inc *MACD) MACD() types.SeriesExtend { - out := &MACDValues{MACD: inc} - out.SeriesBase.Series = out - return out -} - -func (inc *MACD) Singals() types.SeriesExtend { - return inc.SignalLine -} diff --git a/pkg/indicator/macd_test.go b/pkg/indicator/macd_test.go index 0088f9db9..e3976e003 100644 --- a/pkg/indicator/macd_test.go +++ b/pkg/indicator/macd_test.go @@ -41,7 +41,9 @@ func Test_calculateMACD(t *testing.T) { t.Run(tt.name, func(t *testing.T) { iw := types.IntervalWindow{Window: 9} macd := MACD{IntervalWindow: iw, ShortPeriod: 12, LongPeriod: 26} - macd.CalculateAndUpdate(tt.kLines) + for _, k := range tt.kLines { + macd.PushK(k) + } got := macd.Last() diff := math.Trunc((got-tt.want)*100) / 100 diff --git a/pkg/strategy/pivotshort/breaklow.go b/pkg/strategy/pivotshort/breaklow.go index 7b67af813..565c8336f 100644 --- a/pkg/strategy/pivotshort/breaklow.go +++ b/pkg/strategy/pivotshort/breaklow.go @@ -34,7 +34,7 @@ type BreakLow struct { TrendEMA *types.IntervalWindow `json:"trendEMA"` lastLow fixedpoint.Value - pivot *indicator.Pivot + pivot *indicator.PivotLow stopEWMA *indicator.EWMA trendEWMA *indicator.EWMA @@ -65,14 +65,11 @@ func (s *BreakLow) Bind(session *bbgo.ExchangeSession, orderExecutor *bbgo.Gener position := orderExecutor.Position() symbol := position.Symbol - store, _ := session.MarketDataStore(s.Symbol) standardIndicator := session.StandardIndicatorSet(s.Symbol) s.lastLow = fixedpoint.Zero - s.pivot = &indicator.Pivot{IntervalWindow: s.IntervalWindow} - s.pivot.Bind(store) - preloadPivot(s.pivot, store) + s.pivot = standardIndicator.PivotLow(s.IntervalWindow) if s.StopEMA != nil { s.stopEWMA = standardIndicator.EWMA(*s.StopEMA) @@ -89,13 +86,13 @@ func (s *BreakLow) Bind(session *bbgo.ExchangeSession, orderExecutor *bbgo.Gener // update pivot low data session.MarketDataStream.OnStart(func() { - lastLow := fixedpoint.NewFromFloat(s.pivot.LastLow()) + lastLow := fixedpoint.NewFromFloat(s.pivot.Lows.Last()) if lastLow.IsZero() { return } if lastLow.Compare(s.lastLow) != 0 { - bbgo.Notify("%s found new pivot low: %f", s.Symbol, s.pivot.LastLow()) + bbgo.Notify("%s found new pivot low: %f", s.Symbol, s.pivot.Lows.Last()) } s.lastLow = lastLow @@ -120,8 +117,7 @@ func (s *BreakLow) Bind(session *bbgo.ExchangeSession, orderExecutor *bbgo.Gener }) session.MarketDataStream.OnKLineClosed(types.KLineWith(symbol, s.Interval, func(kline types.KLine) { - - lastLow := fixedpoint.NewFromFloat(s.pivot.LastLow()) + lastLow := fixedpoint.NewFromFloat(s.pivot.Lows.Last()) if lastLow.IsZero() { return } @@ -133,13 +129,12 @@ func (s *BreakLow) Bind(session *bbgo.ExchangeSession, orderExecutor *bbgo.Gener s.lastLow = lastLow s.pivotLowPrices = append(s.pivotLowPrices, s.lastLow) - // when position is opened, do not send pivot low notify if position.IsOpened(kline.Close) { return } - bbgo.Notify("%s new pivot low: %f", s.Symbol, s.pivot.LastLow()) + bbgo.Notify("%s new pivot low: %f", s.Symbol, s.pivot.Lows.Last()) })) session.MarketDataStream.OnKLineClosed(types.KLineWith(symbol, types.Interval1m, func(kline types.KLine) { @@ -246,4 +241,3 @@ func (s *BreakLow) Bind(session *bbgo.ExchangeSession, orderExecutor *bbgo.Gener } })) } - diff --git a/pkg/strategy/pivotshort/resistance.go b/pkg/strategy/pivotshort/resistance.go index b52313eed..2cf336f79 100644 --- a/pkg/strategy/pivotshort/resistance.go +++ b/pkg/strategy/pivotshort/resistance.go @@ -26,7 +26,7 @@ type ResistanceShort struct { session *bbgo.ExchangeSession orderExecutor *bbgo.GeneralOrderExecutor - resistancePivot *indicator.Pivot + resistancePivot *indicator.PivotLow resistancePrices []float64 currentResistancePrice fixedpoint.Value @@ -47,19 +47,10 @@ func (s *ResistanceShort) Bind(session *bbgo.ExchangeSession, orderExecutor *bbg s.GroupDistance = fixedpoint.NewFromFloat(0.01) } - store, _ := session.MarketDataStore(s.Symbol) - - s.resistancePivot = &indicator.Pivot{IntervalWindow: s.IntervalWindow} - s.resistancePivot.Bind(store) - - // preload history kline data to the resistance pivot indicator - // we use the last kline to find the higher lows - lastKLine := preloadPivot(s.resistancePivot, store) + s.resistancePivot = session.StandardIndicatorSet(s.Symbol).PivotLow(s.IntervalWindow) // use the last kline from the history before we get the next closed kline - if lastKLine != nil { - s.updateResistanceOrders(lastKLine.Close) - } + s.updateResistanceOrders(fixedpoint.NewFromFloat(s.resistancePivot.Lows.Last())) session.MarketDataStream.OnKLineClosed(types.KLineWith(s.Symbol, s.Interval, func(kline types.KLine) { position := s.orderExecutor.Position() diff --git a/pkg/strategy/pivotshort/strategy.go b/pkg/strategy/pivotshort/strategy.go index 3e3806caf..8851f1530 100644 --- a/pkg/strategy/pivotshort/strategy.go +++ b/pkg/strategy/pivotshort/strategy.go @@ -35,7 +35,7 @@ type SupportTakeProfit struct { Ratio fixedpoint.Value `json:"ratio"` - pivot *indicator.Pivot + pivot *indicator.PivotLow orderExecutor *bbgo.GeneralOrderExecutor session *bbgo.ExchangeSession activeOrders *bbgo.ActiveOrderBook @@ -62,11 +62,8 @@ func (s *SupportTakeProfit) Bind(session *bbgo.ExchangeSession, orderExecutor *b s.activeOrders.BindStream(session.UserDataStream) position := orderExecutor.Position() - symbol := position.Symbol - store, _ := session.MarketDataStore(symbol) - s.pivot = &indicator.Pivot{IntervalWindow: s.IntervalWindow} - s.pivot.Bind(store) - preloadPivot(s.pivot, store) + + s.pivot = session.StandardIndicatorSet(s.Symbol).PivotLow(s.IntervalWindow) session.MarketDataStream.OnKLineClosed(types.KLineWith(s.Symbol, s.Interval, func(kline types.KLine) { if !s.updateSupportPrice(kline.Close) { @@ -88,7 +85,7 @@ func (s *SupportTakeProfit) Bind(session *bbgo.ExchangeSession, orderExecutor *b bbgo.Notify("placing %s take profit order at price %f", s.Symbol, buyPrice.Float64()) createdOrders, err := orderExecutor.SubmitOrders(ctx, types.SubmitOrder{ - Symbol: symbol, + Symbol: s.Symbol, Type: types.OrderTypeLimitMaker, Side: types.SideTypeBuy, Price: buyPrice, @@ -215,7 +212,6 @@ func (s *Strategy) Subscribe(session *bbgo.ExchangeSession) { s.ExitMethods.SetAndSubscribe(session, s) } - func (s *Strategy) CurrentPosition() *types.Position { return s.Position } @@ -293,21 +289,3 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se return nil } - -func preloadPivot(pivot *indicator.Pivot, store *bbgo.MarketDataStore) *types.KLine { - klines, ok := store.KLinesOfInterval(pivot.Interval) - if !ok { - return nil - } - - last := (*klines)[len(*klines)-1] - log.Debugf("updating pivot indicator: %d klines", len(*klines)) - - for i := pivot.Window; i < len(*klines); i++ { - pivot.CalculateAndUpdate((*klines)[0 : i+1]) - } - - log.Debugf("found %v previous lows: %v", pivot.IntervalWindow, pivot.Lows) - log.Debugf("found %v previous highs: %v", pivot.IntervalWindow, pivot.Highs) - return &last -}