bbgo_origin/pkg/strategy/supertrend/lingre.go

74 lines
1.8 KiB
Go

package supertrend
import (
"github.com/c9s/bbgo/pkg/bbgo"
"github.com/c9s/bbgo/pkg/indicator"
"github.com/c9s/bbgo/pkg/types"
)
// LinGre is Linear Regression baseline
type LinGre struct {
types.IntervalWindow
baseLineSlope float64
}
// Update Linear Regression baseline slope
func (lg *LinGre) Update(klines []types.KLine) {
if len(klines) < lg.Window {
lg.baseLineSlope = 0
return
}
var sumX, sumY, sumXSqr, sumXY float64 = 0, 0, 0, 0
end := len(klines) - 1 // The last kline
for i := end; i >= end-lg.Window+1; i-- {
val := klines[i].GetClose().Float64()
per := float64(end - i + 1)
sumX += per
sumY += val
sumXSqr += per * per
sumXY += val * per
}
length := float64(lg.Window)
slope := (length*sumXY - sumX*sumY) / (length*sumXSqr - sumX*sumX)
average := sumY / length
endPrice := average - slope*sumX/length + slope
startPrice := endPrice + slope*(length-1)
lg.baseLineSlope = (length - 1) / (endPrice - startPrice)
log.Debugf("linear regression baseline slope: %f", lg.baseLineSlope)
}
func (lg *LinGre) handleKLineWindowUpdate(interval types.Interval, window types.KLineWindow) {
if lg.Interval != interval {
return
}
lg.Update(window)
}
func (lg *LinGre) Bind(updater indicator.KLineWindowUpdater) {
updater.OnKLineWindowUpdate(lg.handleKLineWindowUpdate)
}
// GetSignal get linear regression signal
func (lg *LinGre) GetSignal() types.Direction {
var lgSignal types.Direction = types.DirectionNone
switch {
case lg.baseLineSlope > 0:
lgSignal = types.DirectionUp
case lg.baseLineSlope < 0:
lgSignal = types.DirectionDown
}
return lgSignal
}
// preloadLinGre preloads linear regression indicator
func (lg *LinGre) preload(kLineStore *bbgo.MarketDataStore) {
if klines, ok := kLineStore.KLinesOfInterval(lg.Interval); ok {
lg.Update((*klines)[0:])
}
}