all: refactor and rename indicator.MACD to indicator.MACDLegacy

This commit is contained in:
c9s 2023-05-26 14:31:06 +08:00
parent 171e0678b6
commit 648e99f52a
No known key found for this signature in database
GPG Key ID: 7385E7E464CB0A54
12 changed files with 127 additions and 91 deletions

View File

@ -29,7 +29,7 @@ type StandardIndicatorSet struct {
// interval -> window // interval -> window
iwbIndicators map[types.IntervalWindowBandWidth]*indicator.BOLL iwbIndicators map[types.IntervalWindowBandWidth]*indicator.BOLL
iwIndicators map[indicatorKey]indicator.KLinePusher iwIndicators map[indicatorKey]indicator.KLinePusher
macdIndicators map[indicator.MACDConfig]*indicator.MACD macdIndicators map[indicator.MACDConfig]*indicator.MACDLegacy
stream types.Stream stream types.Stream
store *MarketDataStore store *MarketDataStore
@ -47,7 +47,7 @@ func NewStandardIndicatorSet(symbol string, stream types.Stream, store *MarketDa
stream: stream, stream: stream,
iwIndicators: make(map[indicatorKey]indicator.KLinePusher), iwIndicators: make(map[indicatorKey]indicator.KLinePusher),
iwbIndicators: make(map[types.IntervalWindowBandWidth]*indicator.BOLL), iwbIndicators: make(map[types.IntervalWindowBandWidth]*indicator.BOLL),
macdIndicators: make(map[indicator.MACDConfig]*indicator.MACD), macdIndicators: make(map[indicator.MACDConfig]*indicator.MACDLegacy),
} }
} }
@ -154,14 +154,14 @@ func (s *StandardIndicatorSet) BOLL(iw types.IntervalWindow, bandWidth float64)
return inc return inc
} }
func (s *StandardIndicatorSet) MACD(iw types.IntervalWindow, shortPeriod, longPeriod int) *indicator.MACD { func (s *StandardIndicatorSet) MACD(iw types.IntervalWindow, shortPeriod, longPeriod int) *indicator.MACDLegacy {
config := indicator.MACDConfig{IntervalWindow: iw, ShortPeriod: shortPeriod, LongPeriod: longPeriod} config := indicator.MACDConfig{IntervalWindow: iw, ShortPeriod: shortPeriod, LongPeriod: longPeriod}
inc, ok := s.macdIndicators[config] inc, ok := s.macdIndicators[config]
if ok { if ok {
return inc return inc
} }
inc = &indicator.MACD{MACDConfig: config} inc = &indicator.MACDLegacy{MACDConfig: config}
s.macdIndicators[config] = inc s.macdIndicators[config] = inc
s.initAndBind(inc, config.IntervalWindow.Interval) s.initAndBind(inc, config.IntervalWindow.Interval)
return inc return inc

View File

@ -0,0 +1,6 @@
package indicator
//go:generate callbackgen -type Float64Updater
type Float64Updater struct {
updateCallbacks []func(v float64)
}

View File

@ -0,0 +1,37 @@
package indicator
import "github.com/c9s/bbgo/pkg/types"
const MaxNumOfKLines = 4_000
//go:generate callbackgen -type KLineStream
type KLineStream struct {
updateCallbacks []func(k types.KLine)
kLines []types.KLine
}
// AddSubscriber adds the subscriber function and push histrical data to the subscriber
func (s *KLineStream) AddSubscriber(f func(k types.KLine)) {
if len(s.kLines) > 0 {
// push historical klines to the subscriber
}
s.OnUpdate(f)
}
// KLines creates a KLine stream that pushes the klines to the subscribers
func KLines(source types.Stream) *KLineStream {
s := &KLineStream{}
source.OnKLineClosed(func(k types.KLine) {
s.kLines = append(s.kLines, k)
if len(s.kLines) > MaxNumOfKLines {
s.kLines = s.kLines[len(s.kLines)-1-MaxNumOfKLines:]
}
s.EmitUpdate(k)
})
return s
}

View File

@ -6,12 +6,12 @@ import (
"github.com/c9s/bbgo/pkg/types" "github.com/c9s/bbgo/pkg/types"
) )
func (K *KLineStream) OnUpdate(cb func(k types.KLine)) { func (s *KLineStream) OnUpdate(cb func(k types.KLine)) {
K.updateCallbacks = append(K.updateCallbacks, cb) s.updateCallbacks = append(s.updateCallbacks, cb)
} }
func (K *KLineStream) EmitUpdate(k types.KLine) { func (s *KLineStream) EmitUpdate(k types.KLine) {
for _, cb := range K.updateCallbacks { for _, cb := range s.updateCallbacks {
cb(k) cb(k)
} }
} }

View File

@ -23,50 +23,6 @@ signal := EMA(macd, 16)
histogram := Subtract(macd, signal) histogram := Subtract(macd, signal)
*/ */
//go:generate callbackgen -type KLineStream
type KLineStream struct {
updateCallbacks []func(k types.KLine)
}
func KLines(source types.Stream) *KLineStream {
stream := &KLineStream{}
source.OnKLineClosed(stream.EmitUpdate)
return stream
}
type KLineSource interface {
OnUpdate(f func(k types.KLine))
}
type PriceStream struct {
types.SeriesBase
Float64Updater
slice floats.Slice
mapper KLineValueMapper
}
func Price(source KLineSource, mapper KLineValueMapper) *PriceStream {
s := &PriceStream{
mapper: mapper,
}
s.SeriesBase.Series = s.slice
source.OnUpdate(func(k types.KLine) {
v := s.mapper(k)
s.slice.Push(v)
s.EmitUpdate(v)
})
return s
}
func ClosePrices(source KLineSource) *PriceStream {
return Price(source, KLineClosePriceMapper)
}
func OpenPrices(source KLineSource) *PriceStream {
return Price(source, KLineOpenPriceMapper)
}
type Float64Source interface { type Float64Source interface {
types.Series types.Series
OnUpdate(f func(v float64)) OnUpdate(f func(v float64))
@ -104,11 +60,6 @@ func (s *EWMAStream) calculate(v float64) float64 {
return (1.0-m)*last + m*v return (1.0-m)*last + m*v
} }
//go:generate callbackgen -type Float64Updater
type Float64Updater struct {
updateCallbacks []func(v float64)
}
type SubtractStream struct { type SubtractStream struct {
Float64Updater Float64Updater
types.SeriesBase types.SeriesBase

View File

@ -26,9 +26,5 @@ func TestSubtract(t *testing.T) {
assert.Equal(t, len(subtract.a), len(subtract.b)) assert.Equal(t, len(subtract.a), len(subtract.b))
assert.Equal(t, len(subtract.a), len(subtract.c)) assert.Equal(t, len(subtract.a), len(subtract.c))
assert.Equal(t, subtract.c[0], subtract.a[0]-subtract.b[0]) assert.InDelta(t, subtract.c[0], subtract.a[0]-subtract.b[0], 0.0001)
t.Logf("subtract.a: %+v", subtract.a)
t.Logf("subtract.b: %+v", subtract.b)
t.Logf("subtract.c: %+v", subtract.c)
} }

View File

@ -1,15 +0,0 @@
// Code generated by "callbackgen -type MACD"; DO NOT EDIT.
package indicator
import ()
func (inc *MACD) OnUpdate(cb func(macd float64, signal float64, histogram float64)) {
inc.updateCallbacks = append(inc.updateCallbacks, cb)
}
func (inc *MACD) EmitUpdate(macd float64, signal float64, histogram float64) {
for _, cb := range inc.updateCallbacks {
cb(macd, signal, histogram)
}
}

View File

@ -27,20 +27,19 @@ type MACDConfig struct {
LongPeriod int `json:"long"` LongPeriod int `json:"long"`
} }
//go:generate callbackgen -type MACD //go:generate callbackgen -type MACDLegacy
type MACD struct { type MACDLegacy struct {
MACDConfig MACDConfig
Values floats.Slice `json:"-"` Values floats.Slice `json:"-"`
fastEWMA, slowEWMA, signalLine *EWMA fastEWMA, slowEWMA, signalLine *EWMA
Histogram floats.Slice `json:"-"` Histogram floats.Slice `json:"-"`
EndTime time.Time
updateCallbacks []func(macd, signal, histogram float64) updateCallbacks []func(macd, signal, histogram float64)
EndTime time.Time
} }
func (inc *MACD) Update(x float64) { func (inc *MACDLegacy) Update(x float64) {
if len(inc.Values) == 0 { if len(inc.Values) == 0 {
// apply default values // apply default values
inc.fastEWMA = &EWMA{IntervalWindow: types.IntervalWindow{Window: inc.ShortPeriod}} inc.fastEWMA = &EWMA{IntervalWindow: types.IntervalWindow{Window: inc.ShortPeriod}}
@ -76,7 +75,7 @@ func (inc *MACD) Update(x float64) {
inc.EmitUpdate(macd, signal, histogram) inc.EmitUpdate(macd, signal, histogram)
} }
func (inc *MACD) Last() float64 { func (inc *MACDLegacy) Last() float64 {
if len(inc.Values) == 0 { if len(inc.Values) == 0 {
return 0.0 return 0.0
} }
@ -84,27 +83,27 @@ func (inc *MACD) Last() float64 {
return inc.Values[len(inc.Values)-1] return inc.Values[len(inc.Values)-1]
} }
func (inc *MACD) Length() int { func (inc *MACDLegacy) Length() int {
return len(inc.Values) return len(inc.Values)
} }
func (inc *MACD) PushK(k types.KLine) { func (inc *MACDLegacy) PushK(k types.KLine) {
inc.Update(k.Close.Float64()) inc.Update(k.Close.Float64())
} }
func (inc *MACD) MACD() types.SeriesExtend { func (inc *MACDLegacy) MACD() types.SeriesExtend {
out := &MACDValues{MACD: inc} out := &MACDValues{MACDLegacy: inc}
out.SeriesBase.Series = out out.SeriesBase.Series = out
return out return out
} }
func (inc *MACD) Singals() types.SeriesExtend { func (inc *MACDLegacy) Singals() types.SeriesExtend {
return inc.signalLine return inc.signalLine
} }
type MACDValues struct { type MACDValues struct {
types.SeriesBase types.SeriesBase
*MACD *MACDLegacy
} }
func (inc *MACDValues) Last() float64 { func (inc *MACDValues) Last() float64 {

View File

@ -0,0 +1,15 @@
// Code generated by "callbackgen -type MACDLegacy"; DO NOT EDIT.
package indicator
import ()
func (inc *MACDLegacy) OnUpdate(cb func(macd float64, signal float64, histogram float64)) {
inc.updateCallbacks = append(inc.updateCallbacks, cb)
}
func (inc *MACDLegacy) EmitUpdate(macd float64, signal float64, histogram float64) {
for _, cb := range inc.updateCallbacks {
cb(macd, signal, histogram)
}
}

View File

@ -40,7 +40,7 @@ func Test_calculateMACD(t *testing.T) {
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
iw := types.IntervalWindow{Window: 9} iw := types.IntervalWindow{Window: 9}
macd := MACD{MACDConfig: MACDConfig{IntervalWindow: iw, ShortPeriod: 12, LongPeriod: 26}} macd := MACDLegacy{MACDConfig: MACDConfig{IntervalWindow: iw, ShortPeriod: 12, LongPeriod: 26}}
for _, k := range tt.kLines { for _, k := range tt.kLines {
macd.PushK(k) macd.PushK(k)
} }

47
pkg/indicator/price.go Normal file
View File

@ -0,0 +1,47 @@
package indicator
import (
"github.com/c9s/bbgo/pkg/datatype/floats"
"github.com/c9s/bbgo/pkg/types"
)
type KLineSource interface {
OnUpdate(f func(k types.KLine))
}
type PriceStream struct {
types.SeriesBase
Float64Updater
slice floats.Slice
mapper KLineValueMapper
}
func Price(source KLineSource, mapper KLineValueMapper) *PriceStream {
s := &PriceStream{
mapper: mapper,
}
s.SeriesBase.Series = s.slice
source.OnUpdate(func(k types.KLine) {
v := s.mapper(k)
s.slice.Push(v)
s.EmitUpdate(v)
})
return s
}
func ClosePrices(source KLineSource) *PriceStream {
return Price(source, KLineClosePriceMapper)
}
func LowPrices(source KLineSource) *PriceStream {
return Price(source, KLineLowPriceMapper)
}
func HighPrices(source KLineSource) *PriceStream {
return Price(source, KLineHighPriceMapper)
}
func OpenPrices(source KLineSource) *PriceStream {
return Price(source, KLineOpenPriceMapper)
}

View File

@ -47,7 +47,7 @@ type FailedBreakHigh struct {
MACDDivergence *MACDDivergence `json:"macdDivergence"` MACDDivergence *MACDDivergence `json:"macdDivergence"`
macd *indicator.MACD macd *indicator.MACDLegacy
macdTopDivergence bool macdTopDivergence bool