mirror of
https://github.com/c9s/bbgo.git
synced 2024-11-26 16:55:15 +00:00
Merge pull request #824 from c9s/refactor/indicator-api
refactor: indicator: rewrite VWMA calculator
This commit is contained in:
commit
5eb60df70d
|
@ -6,6 +6,12 @@ type KLineWindowUpdater interface {
|
||||||
OnKLineWindowUpdate(func(interval types.Interval, window types.KLineWindow))
|
OnKLineWindowUpdate(func(interval types.Interval, window types.KLineWindow))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type KLineClosedBinder interface {
|
||||||
|
BindK(target KLineClosedEmitter, symbol string, interval types.Interval)
|
||||||
|
}
|
||||||
|
|
||||||
|
// KLineClosedEmitter is currently applied to the market data stream
|
||||||
|
// the market data stream emits the KLine closed event to the listeners.
|
||||||
type KLineClosedEmitter interface {
|
type KLineClosedEmitter interface {
|
||||||
OnKLineClosed(func(k types.KLine))
|
OnKLineClosed(func(k types.KLine))
|
||||||
}
|
}
|
||||||
|
|
|
@ -86,6 +86,10 @@ func (inc *SMA) handleKLineWindowUpdate(interval types.Interval, window types.KL
|
||||||
inc.CalculateAndUpdate(window)
|
inc.CalculateAndUpdate(window)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (inc *SMA) BindK(target KLineClosedEmitter, symbol string, interval types.Interval) {
|
||||||
|
target.OnKLineClosed(types.KLineWith(symbol, interval, inc.PushK))
|
||||||
|
}
|
||||||
|
|
||||||
func (inc *SMA) Bind(updater KLineWindowUpdater) {
|
func (inc *SMA) Bind(updater KLineWindowUpdater) {
|
||||||
updater.OnKLineWindowUpdate(inc.handleKLineWindowUpdate)
|
updater.OnKLineWindowUpdate(inc.handleKLineWindowUpdate)
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,8 +3,6 @@ package indicator
|
||||||
import (
|
import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
log "github.com/sirupsen/logrus"
|
|
||||||
|
|
||||||
"github.com/c9s/bbgo/pkg/types"
|
"github.com/c9s/bbgo/pkg/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -22,10 +20,14 @@ Volume Weighted Moving Average
|
||||||
type VWMA struct {
|
type VWMA struct {
|
||||||
types.SeriesBase
|
types.SeriesBase
|
||||||
types.IntervalWindow
|
types.IntervalWindow
|
||||||
|
|
||||||
Values types.Float64Slice
|
Values types.Float64Slice
|
||||||
|
PriceVolumeSMA *SMA
|
||||||
|
VolumeSMA *SMA
|
||||||
|
|
||||||
EndTime time.Time
|
EndTime time.Time
|
||||||
|
|
||||||
UpdateCallbacks []func(value float64)
|
updateCallbacks []func(value float64)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (inc *VWMA) Last() float64 {
|
func (inc *VWMA) Last() float64 {
|
||||||
|
@ -49,46 +51,46 @@ func (inc *VWMA) Length() int {
|
||||||
|
|
||||||
var _ types.SeriesExtend = &VWMA{}
|
var _ types.SeriesExtend = &VWMA{}
|
||||||
|
|
||||||
|
func (inc *VWMA) Update(price, volume float64) {
|
||||||
|
if inc.PriceVolumeSMA == nil {
|
||||||
|
inc.PriceVolumeSMA = &SMA{IntervalWindow: inc.IntervalWindow}
|
||||||
|
inc.SeriesBase.Series = inc
|
||||||
|
}
|
||||||
|
|
||||||
|
if inc.VolumeSMA == nil {
|
||||||
|
inc.VolumeSMA = &SMA{IntervalWindow: inc.IntervalWindow}
|
||||||
|
}
|
||||||
|
|
||||||
|
inc.PriceVolumeSMA.Update(price * volume)
|
||||||
|
inc.VolumeSMA.Update(volume)
|
||||||
|
|
||||||
|
pv := inc.PriceVolumeSMA.Last()
|
||||||
|
v := inc.VolumeSMA.Last()
|
||||||
|
vwma := pv / v
|
||||||
|
inc.Values.Push(vwma)
|
||||||
|
}
|
||||||
|
|
||||||
func (inc *VWMA) CalculateAndUpdate(allKLines []types.KLine) {
|
func (inc *VWMA) CalculateAndUpdate(allKLines []types.KLine) {
|
||||||
if len(allKLines) < inc.Window {
|
if len(allKLines) < inc.Window {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var index = len(allKLines) - 1
|
var last = allKLines[len(allKLines)-1]
|
||||||
var kline = allKLines[index]
|
|
||||||
|
|
||||||
if inc.EndTime != zeroTime && kline.EndTime.Before(inc.EndTime) {
|
if inc.VolumeSMA == nil {
|
||||||
|
for _, k := range allKLines {
|
||||||
|
if inc.EndTime != zeroTime && k.EndTime.Before(inc.EndTime) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var recentK = allKLines[index-(inc.Window-1) : index+1]
|
inc.Update(k.Close.Float64(), k.Volume.Float64())
|
||||||
|
|
||||||
pv, err := calculateSMA(recentK, inc.Window, KLinePriceVolumeMapper)
|
|
||||||
if err != nil {
|
|
||||||
log.WithError(err).Error("price x volume SMA error")
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
v, err := calculateSMA(recentK, inc.Window, KLineVolumeMapper)
|
} else {
|
||||||
if err != nil {
|
inc.Update(last.Close.Float64(), last.Volume.Float64())
|
||||||
log.WithError(err).Error("volume SMA error")
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(inc.Values) == 0 {
|
inc.EndTime = last.EndTime.Time()
|
||||||
inc.SeriesBase.Series = inc
|
inc.EmitUpdate(inc.Values.Last())
|
||||||
}
|
|
||||||
|
|
||||||
vwma := pv / v
|
|
||||||
inc.Values.Push(vwma)
|
|
||||||
|
|
||||||
if len(inc.Values) > MaxNumOfSMA {
|
|
||||||
inc.Values = inc.Values[MaxNumOfSMATruncateSize-1:]
|
|
||||||
}
|
|
||||||
|
|
||||||
inc.EndTime = allKLines[index].EndTime.Time()
|
|
||||||
|
|
||||||
inc.EmitUpdate(vwma)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (inc *VWMA) handleKLineWindowUpdate(interval types.Interval, window types.KLineWindow) {
|
func (inc *VWMA) handleKLineWindowUpdate(interval types.Interval, window types.KLineWindow) {
|
||||||
|
|
|
@ -5,11 +5,11 @@ package indicator
|
||||||
import ()
|
import ()
|
||||||
|
|
||||||
func (inc *VWMA) OnUpdate(cb func(value float64)) {
|
func (inc *VWMA) OnUpdate(cb func(value float64)) {
|
||||||
inc.UpdateCallbacks = append(inc.UpdateCallbacks, cb)
|
inc.updateCallbacks = append(inc.updateCallbacks, cb)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (inc *VWMA) EmitUpdate(value float64) {
|
func (inc *VWMA) EmitUpdate(value float64) {
|
||||||
for _, cb := range inc.UpdateCallbacks {
|
for _, cb := range inc.updateCallbacks {
|
||||||
cb(value)
|
cb(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user