indicator: make parameters of update method consistent

This commit is contained in:
なるみ 2022-04-18 12:08:21 +08:00
parent b9c40b63ac
commit 167f9d3eaf
7 changed files with 49 additions and 72 deletions

View File

@ -22,12 +22,7 @@ type AD struct {
UpdateCallbacks []func(value float64) UpdateCallbacks []func(value float64)
} }
func (inc *AD) Update(kLine types.KLine) { func (inc *AD) Update(high, low, cloze, volume float64) {
cloze := kLine.Close.Float64()
high := kLine.High.Float64()
low := kLine.Low.Float64()
volume := kLine.Volume.Float64()
var moneyFlowVolume float64 var moneyFlowVolume float64
if high == low { if high == low {
moneyFlowVolume = 0 moneyFlowVolume = 0
@ -65,7 +60,7 @@ func (inc *AD) calculateAndUpdate(kLines []types.KLine) {
if inc.EndTime != zeroTime && !k.EndTime.After(inc.EndTime) { if inc.EndTime != zeroTime && !k.EndTime.After(inc.EndTime) {
continue continue
} }
inc.Update(k) inc.Update(k.High.Float64(), k.Low.Float64(), k.Close.Float64(), k.Volume.Float64())
} }
inc.EmitUpdate(inc.Last()) inc.EmitUpdate(inc.Last())

View File

@ -19,17 +19,13 @@ type ATR struct {
UpdateCallbacks []func(value float64) UpdateCallbacks []func(value float64)
} }
func (inc *ATR) Update(kLine types.KLine) { func (inc *ATR) Update(high, low, cloze float64) {
if inc.Window <= 0 { if inc.Window <= 0 {
panic("window must be greater than 0") panic("window must be greater than 0")
} }
cloze := kLine.Close.Float64()
high := kLine.High.Float64()
low := kLine.Low.Float64()
if inc.PriviousClose == 0 { if inc.PriviousClose == 0 {
inc.PriviousClose = kLine.Close.Float64() inc.PriviousClose = cloze
return return
} }
@ -87,7 +83,7 @@ func (inc *ATR) calculateAndUpdate(kLines []types.KLine) {
if inc.EndTime != zeroTime && !k.EndTime.After(inc.EndTime) { if inc.EndTime != zeroTime && !k.EndTime.After(inc.EndTime) {
continue continue
} }
inc.Update(k) inc.Update(k.High.Float64(), k.Low.Float64(), k.Close.Float64())
} }
inc.EmitUpdate(inc.Last()) inc.EmitUpdate(inc.Last())

View File

@ -29,25 +29,16 @@ type MACD struct {
UpdateCallbacks []func(value float64) UpdateCallbacks []func(value float64)
} }
func (inc *MACD) calculateMACD(kLines []types.KLine, priceF KLinePriceMapper) float64 { func (inc *MACD) Update(x float64) {
for _, kline := range kLines {
inc.Update(kline, priceF)
}
return inc.Values[len(inc.Values)-1]
}
func (inc *MACD) Update(kLine types.KLine, priceF KLinePriceMapper) {
if len(inc.Values) == 0 { if len(inc.Values) == 0 {
inc.FastEWMA = EWMA{IntervalWindow: types.IntervalWindow{Window: inc.ShortPeriod}} inc.FastEWMA = EWMA{IntervalWindow: types.IntervalWindow{Window: inc.ShortPeriod}}
inc.SlowEWMA = EWMA{IntervalWindow: types.IntervalWindow{Window: inc.LongPeriod}} inc.SlowEWMA = EWMA{IntervalWindow: types.IntervalWindow{Window: inc.LongPeriod}}
inc.SignalLine = EWMA{IntervalWindow: types.IntervalWindow{Window: inc.Window}} inc.SignalLine = EWMA{IntervalWindow: types.IntervalWindow{Window: inc.Window}}
} }
price := priceF(kLine)
// update fast and slow ema // update fast and slow ema
inc.FastEWMA.Update(price) inc.FastEWMA.Update(x)
inc.SlowEWMA.Update(price) inc.SlowEWMA.Update(x)
// update macd // update macd
macd := inc.FastEWMA.Last() - inc.SlowEWMA.Last() macd := inc.FastEWMA.Last() - inc.SlowEWMA.Last()
@ -60,18 +51,23 @@ func (inc *MACD) Update(kLine types.KLine, priceF KLinePriceMapper) {
inc.Histogram.Push(macd - inc.SignalLine.Last()) inc.Histogram.Push(macd - inc.SignalLine.Last())
} }
func (inc *MACD) calculateMACD(kLines []types.KLine, priceF KLinePriceMapper) float64 {
for _, kline := range kLines {
inc.Update(kline.Close.Float64())
}
return inc.Values[len(inc.Values)-1]
}
func (inc *MACD) calculateAndUpdate(kLines []types.KLine) { func (inc *MACD) calculateAndUpdate(kLines []types.KLine) {
if len(kLines) == 0 { if len(kLines) == 0 {
return return
} }
var priceF = KLineClosePriceMapper
for _, k := range kLines { for _, k := range kLines {
if inc.EndTime != zeroTime && !k.EndTime.After(inc.EndTime) { if inc.EndTime != zeroTime && !k.EndTime.After(inc.EndTime) {
continue continue
} }
inc.Update(k, priceF) inc.Update(k.Close.Float64())
} }
inc.EmitUpdate(inc.Values[len(inc.Values)-1]) inc.EmitUpdate(inc.Values[len(inc.Values)-1])

View File

@ -22,10 +22,7 @@ type OBV struct {
UpdateCallbacks []func(value float64) UpdateCallbacks []func(value float64)
} }
func (inc *OBV) Update(kLine types.KLine, priceF KLinePriceMapper) { func (inc *OBV) Update(price, volume float64) {
price := priceF(kLine)
volume := kLine.Volume.Float64()
if len(inc.Values) == 0 { if len(inc.Values) == 0 {
inc.PrePrice = price inc.PrePrice = price
inc.Values.Push(volume) inc.Values.Push(volume)
@ -47,17 +44,16 @@ func (inc *OBV) Last() float64 {
} }
func (inc *OBV) calculateAndUpdate(kLines []types.KLine) { func (inc *OBV) calculateAndUpdate(kLines []types.KLine) {
var priceF = KLineClosePriceMapper
for _, k := range kLines { for _, k := range kLines {
if inc.EndTime != zeroTime && !k.EndTime.After(inc.EndTime) { if inc.EndTime != zeroTime && !k.EndTime.After(inc.EndTime) {
continue continue
} }
inc.Update(k, priceF) inc.Update(k.Close.Float64(), k.Volume.Float64())
} }
inc.EmitUpdate(inc.Last()) inc.EmitUpdate(inc.Last())
inc.EndTime = kLines[len(kLines)-1].EndTime.Time() inc.EndTime = kLines[len(kLines)-1].EndTime.Time()
} }
func (inc *OBV) handleKLineWindowUpdate(interval types.Interval, window types.KLineWindow) { func (inc *OBV) handleKLineWindowUpdate(interval types.Interval, window types.KLineWindow) {
if inc.Interval != interval { if inc.Interval != interval {
return return

View File

@ -24,8 +24,7 @@ type RSI struct {
UpdateCallbacks []func(value float64) UpdateCallbacks []func(value float64)
} }
func (inc *RSI) Update(kline types.KLine, priceF KLinePriceMapper) { func (inc *RSI) Update(price float64) {
price := priceF(kline)
inc.Prices.Push(price) inc.Prices.Push(price)
if len(inc.Prices) < inc.Window+1 { if len(inc.Prices) < inc.Window+1 {
@ -78,13 +77,11 @@ func (inc *RSI) Length() int {
var _ types.Series = &RSI{} var _ types.Series = &RSI{}
func (inc *RSI) calculateAndUpdate(kLines []types.KLine) { func (inc *RSI) calculateAndUpdate(kLines []types.KLine) {
var priceF = KLineClosePriceMapper
for _, k := range kLines { for _, k := range kLines {
if inc.EndTime != zeroTime && !k.EndTime.After(inc.EndTime) { if inc.EndTime != zeroTime && !k.EndTime.After(inc.EndTime) {
continue continue
} }
inc.Update(k, priceF) inc.Update(k.Close.Float64())
} }
inc.EmitUpdate(inc.Last()) inc.EmitUpdate(inc.Last())

View File

@ -20,21 +20,21 @@ type STOCH struct {
K types.Float64Slice K types.Float64Slice
D types.Float64Slice D types.Float64Slice
KLineWindow types.KLineWindow HighValues types.Float64Slice
LowValues types.Float64Slice
EndTime time.Time EndTime time.Time
UpdateCallbacks []func(k float64, d float64) UpdateCallbacks []func(k float64, d float64)
} }
func (inc *STOCH) update(kLine types.KLine) { func (inc *STOCH) Update(high, low, cloze float64) {
inc.KLineWindow.Add(kLine) inc.HighValues.Push(high)
inc.KLineWindow.Truncate(inc.Window) inc.LowValues.Push(low)
lowest := inc.KLineWindow.GetLow().Float64() lowest := inc.LowValues.Tail(inc.Window).Min()
highest := inc.KLineWindow.GetHigh().Float64() highest := inc.HighValues.Tail(inc.Window).Max()
clos := kLine.Close.Float64()
k := 100.0 * (clos - lowest) / (highest - lowest) k := 100.0 * (cloze - lowest) / (highest - lowest)
inc.K.Push(k) inc.K.Push(k)
d := inc.K.Tail(DPeriod).Mean() d := inc.K.Tail(DPeriod).Mean()
@ -64,7 +64,7 @@ func (inc *STOCH) calculateAndUpdate(kLines []types.KLine) {
if inc.EndTime != zeroTime && !k.EndTime.After(inc.EndTime) { if inc.EndTime != zeroTime && !k.EndTime.After(inc.EndTime) {
continue continue
} }
inc.update(k) inc.Update(k.High.Float64(), k.Low.Float64(), k.Close.Float64())
} }
inc.EmitUpdate(inc.LastK(), inc.LastD()) inc.EmitUpdate(inc.LastK(), inc.LastD())

View File

@ -28,6 +28,23 @@ type VWAP struct {
UpdateCallbacks []func(value float64) UpdateCallbacks []func(value float64)
} }
func (inc *VWAP) Update(price, volume float64) {
inc.Prices.Push(price)
inc.Volumes.Push(volume)
if inc.Window != 0 && len(inc.Prices) > inc.Window {
popIndex := len(inc.Prices) - inc.Window - 1
inc.WeightedSum -= inc.Prices[popIndex] * inc.Volumes[popIndex]
inc.VolumeSum -= inc.Volumes[popIndex]
}
inc.WeightedSum += price * volume
inc.VolumeSum += volume
vwap := inc.WeightedSum / inc.VolumeSum
inc.Values.Push(vwap)
}
func (inc *VWAP) Last() float64 { func (inc *VWAP) Last() float64 {
if len(inc.Values) == 0 { if len(inc.Values) == 0 {
return 0.0 return 0.0
@ -50,26 +67,6 @@ func (inc *VWAP) Length() int {
var _ types.Series = &VWAP{} var _ types.Series = &VWAP{}
func (inc *VWAP) Update(kLine types.KLine, priceF KLinePriceMapper) {
price := priceF(kLine)
volume := kLine.Volume.Float64()
inc.Prices.Push(price)
inc.Volumes.Push(volume)
if inc.Window != 0 && len(inc.Prices) > inc.Window {
popIndex := len(inc.Prices) - inc.Window - 1
inc.WeightedSum -= inc.Prices[popIndex] * inc.Volumes[popIndex]
inc.VolumeSum -= inc.Volumes[popIndex]
}
inc.WeightedSum += price * volume
inc.VolumeSum += volume
vwap := inc.WeightedSum / inc.VolumeSum
inc.Values.Push(vwap)
}
func (inc *VWAP) calculateAndUpdate(kLines []types.KLine) { func (inc *VWAP) calculateAndUpdate(kLines []types.KLine) {
var priceF = KLineTypicalPriceMapper var priceF = KLineTypicalPriceMapper
@ -77,7 +74,7 @@ func (inc *VWAP) calculateAndUpdate(kLines []types.KLine) {
if inc.EndTime != zeroTime && !k.EndTime.After(inc.EndTime) { if inc.EndTime != zeroTime && !k.EndTime.After(inc.EndTime) {
continue continue
} }
inc.Update(k, priceF) inc.Update(priceF(k), k.Volume.Float64())
} }
inc.EmitUpdate(inc.Last()) inc.EmitUpdate(inc.Last())
@ -99,7 +96,7 @@ func (inc *VWAP) Bind(updater KLineWindowUpdater) {
func CalculateVWAP(klines []types.KLine, priceF KLinePriceMapper, window int) float64 { func CalculateVWAP(klines []types.KLine, priceF KLinePriceMapper, window int) float64 {
vwap := VWAP{IntervalWindow: types.IntervalWindow{Window: window}} vwap := VWAP{IntervalWindow: types.IntervalWindow{Window: window}}
for _, k := range klines { for _, k := range klines {
vwap.Update(k, priceF) vwap.Update(priceF(k), k.Volume.Float64())
} }
return vwap.Last() return vwap.Last()
} }