From 825be2a08eee8681b079b8a6d034a003d3590dc0 Mon Sep 17 00:00:00 2001 From: Michal Jirman Date: Sat, 3 Feb 2024 17:13:51 +0545 Subject: [PATCH] indicator: keltner channel --- pkg/bbgo/indicator_set.go | 4 +++ pkg/indicator/v2/keltner.go | 61 +++++++++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+) create mode 100644 pkg/indicator/v2/keltner.go diff --git a/pkg/bbgo/indicator_set.go b/pkg/bbgo/indicator_set.go index 0d5dbd3636..c297a5810d 100644 --- a/pkg/bbgo/indicator_set.go +++ b/pkg/bbgo/indicator_set.go @@ -93,6 +93,10 @@ func (i *IndicatorSet) BOLL(iw types.IntervalWindow, k float64) *indicatorv2.BOL return indicatorv2.BOLL(i.CLOSE(iw.Interval), iw.Window, k) } +func (i *IndicatorSet) Keltner(iw types.IntervalWindow, atrLength int) *indicatorv2.KeltnerStream { + return indicatorv2.Keltner(i.KLines(iw.Interval), iw.Window, atrLength) +} + func (i *IndicatorSet) MACD(interval types.Interval, shortWindow, longWindow, signalWindow int) *indicatorv2.MACDStream { return indicatorv2.MACD2(i.CLOSE(interval), shortWindow, longWindow, signalWindow) } diff --git a/pkg/indicator/v2/keltner.go b/pkg/indicator/v2/keltner.go new file mode 100644 index 0000000000..364d3e0375 --- /dev/null +++ b/pkg/indicator/v2/keltner.go @@ -0,0 +1,61 @@ +package indicatorv2 + +import ( + "github.com/c9s/bbgo/pkg/types" +) + +type KeltnerStream struct { + types.SeriesBase + + window, atrLength int + + EWMA *EWMAStream + StdDev *StdDevStream + ATR *ATRStream + + highPrices, lowPrices, closePrices *PriceStream + + Mid *types.Float64Series + FirstUpperBand, FirstLowerBand *types.Float64Series + SecondUpperBand, SecondLowerBand *types.Float64Series + ThirdUpperBand, ThirdLowerBand *types.Float64Series +} + +func Keltner(source KLineSubscription, window, atrLength int) *KeltnerStream { + atr := ATR2(source, atrLength) + + highPrices := HighPrices(source) + lowPrices := LowPrices(source) + closePrices := ClosePrices(source) + ewma := EWMA2(closePrices, window) + + s := &KeltnerStream{ + window: window, + atrLength: atrLength, + highPrices: highPrices, + lowPrices: lowPrices, + closePrices: closePrices, + ATR: atr, + EWMA: ewma, + Mid: types.NewFloat64Series(), + FirstUpperBand: types.NewFloat64Series(), + FirstLowerBand: types.NewFloat64Series(), + SecondUpperBand: types.NewFloat64Series(), + SecondLowerBand: types.NewFloat64Series(), + ThirdUpperBand: types.NewFloat64Series(), + ThirdLowerBand: types.NewFloat64Series(), + } + + source.AddSubscriber(func(kLine types.KLine) { + mid := s.EWMA.Last(0) + atr := s.ATR.Last(0) + s.Mid.PushAndEmit(mid) + s.FirstUpperBand.PushAndEmit(mid + atr) + s.FirstLowerBand.PushAndEmit(mid - atr) + s.SecondUpperBand.PushAndEmit(mid + 2*atr) + s.SecondLowerBand.PushAndEmit(mid - 2*atr) + s.ThirdUpperBand.PushAndEmit(mid + 3*atr) + s.ThirdLowerBand.PushAndEmit(mid - 3*atr) + }) + return s +}