mirror of
https://github.com/c9s/bbgo.git
synced 2024-11-21 22:43:52 +00:00
bbgo: refactor standard indicator
This commit is contained in:
parent
4300e00580
commit
9f937f529e
|
@ -5,7 +5,7 @@ import "github.com/c9s/bbgo/pkg/types"
|
|||
const MaxNumOfKLines = 5_000
|
||||
const MaxNumOfKLinesTruncate = 100
|
||||
|
||||
// MarketDataStore receives and maintain the public market data
|
||||
// MarketDataStore receives and maintain the public market data of a single symbol
|
||||
//go:generate callbackgen -type MarketDataStore
|
||||
type MarketDataStore struct {
|
||||
Symbol string
|
||||
|
@ -14,6 +14,7 @@ type MarketDataStore struct {
|
|||
KLineWindows map[types.Interval]*types.KLineWindow `json:"-"`
|
||||
|
||||
kLineWindowUpdateCallbacks []func(interval types.Interval, klines types.KLineWindow)
|
||||
kLineClosedCallbacks []func(k types.KLine)
|
||||
}
|
||||
|
||||
func NewMarketDataStore(symbol string) *MarketDataStore {
|
||||
|
@ -47,18 +48,19 @@ func (store *MarketDataStore) handleKLineClosed(kline types.KLine) {
|
|||
store.AddKLine(kline)
|
||||
}
|
||||
|
||||
func (store *MarketDataStore) AddKLine(kline types.KLine) {
|
||||
window, ok := store.KLineWindows[kline.Interval]
|
||||
func (store *MarketDataStore) AddKLine(k types.KLine) {
|
||||
window, ok := store.KLineWindows[k.Interval]
|
||||
if !ok {
|
||||
var tmp = make(types.KLineWindow, 0, 1000)
|
||||
store.KLineWindows[kline.Interval] = &tmp
|
||||
store.KLineWindows[k.Interval] = &tmp
|
||||
window = &tmp
|
||||
}
|
||||
window.Add(kline)
|
||||
window.Add(k)
|
||||
|
||||
if len(*window) > MaxNumOfKLines {
|
||||
*window = (*window)[MaxNumOfKLinesTruncate-1:]
|
||||
}
|
||||
|
||||
store.EmitKLineWindowUpdate(kline.Interval, *window)
|
||||
store.EmitKLineClosed(k)
|
||||
store.EmitKLineWindowUpdate(k.Interval, *window)
|
||||
}
|
||||
|
|
|
@ -15,3 +15,13 @@ func (store *MarketDataStore) EmitKLineWindowUpdate(interval types.Interval, kli
|
|||
cb(interval, klines)
|
||||
}
|
||||
}
|
||||
|
||||
func (store *MarketDataStore) OnKLineClosed(cb func(k types.KLine)) {
|
||||
store.kLineClosedCallbacks = append(store.kLineClosedCallbacks, cb)
|
||||
}
|
||||
|
||||
func (store *MarketDataStore) EmitKLineClosed(k types.KLine) {
|
||||
for _, cb := range store.kLineClosedCallbacks {
|
||||
cb(k)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,146 +17,11 @@ import (
|
|||
|
||||
exchange2 "github.com/c9s/bbgo/pkg/exchange"
|
||||
"github.com/c9s/bbgo/pkg/fixedpoint"
|
||||
"github.com/c9s/bbgo/pkg/indicator"
|
||||
"github.com/c9s/bbgo/pkg/service"
|
||||
"github.com/c9s/bbgo/pkg/types"
|
||||
"github.com/c9s/bbgo/pkg/util"
|
||||
)
|
||||
|
||||
var (
|
||||
debugEWMA = false
|
||||
debugSMA = false
|
||||
)
|
||||
|
||||
func init() {
|
||||
// when using --dotenv option, the dotenv is loaded from command.PersistentPreRunE, not init.
|
||||
// hence here the env var won't enable the debug flag
|
||||
util.SetEnvVarBool("DEBUG_EWMA", &debugEWMA)
|
||||
util.SetEnvVarBool("DEBUG_SMA", &debugSMA)
|
||||
}
|
||||
|
||||
type StandardIndicatorSet struct {
|
||||
Symbol string
|
||||
// Standard indicators
|
||||
// interval -> window
|
||||
sma map[types.IntervalWindow]*indicator.SMA
|
||||
ewma map[types.IntervalWindow]*indicator.EWMA
|
||||
boll map[types.IntervalWindowBandWidth]*indicator.BOLL
|
||||
stoch map[types.IntervalWindow]*indicator.STOCH
|
||||
volatility map[types.IntervalWindow]*indicator.Volatility
|
||||
|
||||
store *MarketDataStore
|
||||
}
|
||||
|
||||
func NewStandardIndicatorSet(symbol string, store *MarketDataStore) *StandardIndicatorSet {
|
||||
set := &StandardIndicatorSet{
|
||||
Symbol: symbol,
|
||||
sma: make(map[types.IntervalWindow]*indicator.SMA),
|
||||
ewma: make(map[types.IntervalWindow]*indicator.EWMA),
|
||||
boll: make(map[types.IntervalWindowBandWidth]*indicator.BOLL),
|
||||
stoch: make(map[types.IntervalWindow]*indicator.STOCH),
|
||||
volatility: make(map[types.IntervalWindow]*indicator.Volatility),
|
||||
store: store,
|
||||
}
|
||||
|
||||
// let us pre-defined commonly used intervals
|
||||
for interval := range types.SupportedIntervals {
|
||||
for _, window := range []int{7, 25, 99} {
|
||||
iw := types.IntervalWindow{Interval: interval, Window: window}
|
||||
set.sma[iw] = &indicator.SMA{IntervalWindow: iw}
|
||||
set.sma[iw].Bind(store)
|
||||
if debugSMA {
|
||||
set.sma[iw].OnUpdate(func(value float64) {
|
||||
log.Infof("%s SMA %s: %f", symbol, iw.String(), value)
|
||||
})
|
||||
}
|
||||
|
||||
set.ewma[iw] = &indicator.EWMA{IntervalWindow: iw}
|
||||
set.ewma[iw].Bind(store)
|
||||
|
||||
// if debug EWMA is enabled, we add the debug handler
|
||||
if debugEWMA {
|
||||
set.ewma[iw].OnUpdate(func(value float64) {
|
||||
log.Infof("%s EWMA %s: %f", symbol, iw.String(), value)
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// setup boll indicator, we may refactor boll indicator by subscribing SMA indicator,
|
||||
// however, since general used BOLLINGER band use window 21, which is not in the existing SMA indicator sets.
|
||||
// Pull out the bandwidth configuration as the boll Key
|
||||
iw := types.IntervalWindow{Interval: interval, Window: 21}
|
||||
|
||||
// set efault band width to 2.0
|
||||
iwb := types.IntervalWindowBandWidth{IntervalWindow: iw, BandWidth: 2.0}
|
||||
set.boll[iwb] = &indicator.BOLL{IntervalWindow: iw, K: iwb.BandWidth}
|
||||
set.boll[iwb].Bind(store)
|
||||
}
|
||||
|
||||
return set
|
||||
}
|
||||
|
||||
// BOLL returns the bollinger band indicator of the given interval, the window and bandwidth
|
||||
func (set *StandardIndicatorSet) BOLL(iw types.IntervalWindow, bandWidth float64) *indicator.BOLL {
|
||||
iwb := types.IntervalWindowBandWidth{IntervalWindow: iw, BandWidth: bandWidth}
|
||||
inc, ok := set.boll[iwb]
|
||||
if !ok {
|
||||
inc = &indicator.BOLL{IntervalWindow: iw, K: bandWidth}
|
||||
inc.Bind(set.store)
|
||||
set.boll[iwb] = inc
|
||||
}
|
||||
|
||||
return inc
|
||||
}
|
||||
|
||||
// SMA returns the simple moving average indicator of the given interval and the window size.
|
||||
func (set *StandardIndicatorSet) SMA(iw types.IntervalWindow) *indicator.SMA {
|
||||
inc, ok := set.sma[iw]
|
||||
if !ok {
|
||||
inc = &indicator.SMA{IntervalWindow: iw}
|
||||
inc.Bind(set.store)
|
||||
set.sma[iw] = inc
|
||||
}
|
||||
|
||||
return inc
|
||||
}
|
||||
|
||||
// EWMA returns the exponential weighed moving average indicator of the given interval and the window size.
|
||||
func (set *StandardIndicatorSet) EWMA(iw types.IntervalWindow) *indicator.EWMA {
|
||||
inc, ok := set.ewma[iw]
|
||||
if !ok {
|
||||
inc = &indicator.EWMA{IntervalWindow: iw}
|
||||
inc.Bind(set.store)
|
||||
set.ewma[iw] = inc
|
||||
}
|
||||
|
||||
return inc
|
||||
}
|
||||
|
||||
func (set *StandardIndicatorSet) STOCH(iw types.IntervalWindow) *indicator.STOCH {
|
||||
inc, ok := set.stoch[iw]
|
||||
if !ok {
|
||||
inc = &indicator.STOCH{IntervalWindow: iw}
|
||||
inc.Bind(set.store)
|
||||
set.stoch[iw] = inc
|
||||
}
|
||||
|
||||
return inc
|
||||
}
|
||||
|
||||
// VOLATILITY returns the volatility(stddev) indicator of the given interval and the window size.
|
||||
func (set *StandardIndicatorSet) VOLATILITY(iw types.IntervalWindow) *indicator.Volatility {
|
||||
inc, ok := set.volatility[iw]
|
||||
if !ok {
|
||||
inc = &indicator.Volatility{IntervalWindow: iw}
|
||||
inc.Bind(set.store)
|
||||
set.volatility[iw] = inc
|
||||
}
|
||||
|
||||
return inc
|
||||
}
|
||||
|
||||
// ExchangeSession presents the exchange connection Session
|
||||
// It also maintains and collects the data returned from the stream.
|
||||
type ExchangeSession struct {
|
||||
|
@ -504,7 +369,7 @@ func (session *ExchangeSession) initSymbol(ctx context.Context, environ *Environ
|
|||
marketDataStore.BindStream(session.MarketDataStream)
|
||||
session.marketDataStores[symbol] = marketDataStore
|
||||
|
||||
standardIndicatorSet := NewStandardIndicatorSet(symbol, marketDataStore)
|
||||
standardIndicatorSet := NewStandardIndicatorSet(symbol, session.MarketDataStream, marketDataStore)
|
||||
session.standardIndicatorSets[symbol] = standardIndicatorSet
|
||||
|
||||
// used kline intervals by the given symbol
|
||||
|
|
135
pkg/bbgo/standard_indicator_set.go
Normal file
135
pkg/bbgo/standard_indicator_set.go
Normal file
|
@ -0,0 +1,135 @@
|
|||
package bbgo
|
||||
|
||||
import (
|
||||
"github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/c9s/bbgo/pkg/indicator"
|
||||
"github.com/c9s/bbgo/pkg/types"
|
||||
"github.com/c9s/bbgo/pkg/util"
|
||||
)
|
||||
|
||||
var (
|
||||
debugEWMA = false
|
||||
debugSMA = false
|
||||
debugBOLL = false
|
||||
)
|
||||
|
||||
func init() {
|
||||
// when using --dotenv option, the dotenv is loaded from command.PersistentPreRunE, not init.
|
||||
// hence here the env var won't enable the debug flag
|
||||
util.SetEnvVarBool("DEBUG_EWMA", &debugEWMA)
|
||||
util.SetEnvVarBool("DEBUG_SMA", &debugSMA)
|
||||
util.SetEnvVarBool("DEBUG_BOLL", &debugBOLL)
|
||||
}
|
||||
|
||||
type StandardIndicatorSet struct {
|
||||
Symbol string
|
||||
// Standard indicators
|
||||
// interval -> window
|
||||
sma map[types.IntervalWindow]*indicator.SMA
|
||||
ewma map[types.IntervalWindow]*indicator.EWMA
|
||||
boll map[types.IntervalWindowBandWidth]*indicator.BOLL
|
||||
stoch map[types.IntervalWindow]*indicator.STOCH
|
||||
volatility map[types.IntervalWindow]*indicator.Volatility
|
||||
|
||||
stream types.Stream
|
||||
store *MarketDataStore
|
||||
}
|
||||
|
||||
func NewStandardIndicatorSet(symbol string, stream types.Stream, store *MarketDataStore) *StandardIndicatorSet {
|
||||
return &StandardIndicatorSet{
|
||||
Symbol: symbol,
|
||||
sma: make(map[types.IntervalWindow]*indicator.SMA),
|
||||
ewma: make(map[types.IntervalWindow]*indicator.EWMA),
|
||||
boll: make(map[types.IntervalWindowBandWidth]*indicator.BOLL),
|
||||
stoch: make(map[types.IntervalWindow]*indicator.STOCH),
|
||||
store: store,
|
||||
stream: stream,
|
||||
}
|
||||
}
|
||||
|
||||
// BOLL returns the bollinger band indicator of the given interval, the window and bandwidth
|
||||
func (set *StandardIndicatorSet) BOLL(iw types.IntervalWindow, bandWidth float64) *indicator.BOLL {
|
||||
iwb := types.IntervalWindowBandWidth{IntervalWindow: iw, BandWidth: bandWidth}
|
||||
inc, ok := set.boll[iwb]
|
||||
if !ok {
|
||||
inc = &indicator.BOLL{IntervalWindow: iw, K: bandWidth}
|
||||
|
||||
if klines, ok := set.store.KLinesOfInterval(iw.Interval); ok {
|
||||
inc.LoadK(*klines)
|
||||
}
|
||||
|
||||
if debugBOLL {
|
||||
inc.OnUpdate(func(sma float64, upBand float64, downBand float64) {
|
||||
logrus.Infof("%s BOLL %s: sma=%f up=%f down=%f", set.Symbol, iw.String(), sma, upBand, downBand)
|
||||
})
|
||||
}
|
||||
|
||||
inc.BindK(set.stream, set.Symbol, iw.Interval)
|
||||
set.boll[iwb] = inc
|
||||
}
|
||||
|
||||
return inc
|
||||
}
|
||||
|
||||
// SMA returns the simple moving average indicator of the given interval and the window size.
|
||||
func (set *StandardIndicatorSet) SMA(iw types.IntervalWindow) *indicator.SMA {
|
||||
inc, ok := set.sma[iw]
|
||||
if !ok {
|
||||
inc = &indicator.SMA{IntervalWindow: iw}
|
||||
|
||||
if klines, ok := set.store.KLinesOfInterval(iw.Interval); ok {
|
||||
inc.LoadK(*klines)
|
||||
}
|
||||
|
||||
if debugSMA {
|
||||
inc.OnUpdate(func(value float64) {
|
||||
logrus.Infof("%s SMA %s: %f", set.Symbol, iw.String(), value)
|
||||
})
|
||||
}
|
||||
|
||||
inc.BindK(set.stream, set.Symbol, iw.Interval)
|
||||
set.sma[iw] = inc
|
||||
}
|
||||
|
||||
return inc
|
||||
}
|
||||
|
||||
// EWMA returns the exponential weighed moving average indicator of the given interval and the window size.
|
||||
func (set *StandardIndicatorSet) EWMA(iw types.IntervalWindow) *indicator.EWMA {
|
||||
inc, ok := set.ewma[iw]
|
||||
if !ok {
|
||||
inc = &indicator.EWMA{IntervalWindow: iw}
|
||||
|
||||
if klines, ok := set.store.KLinesOfInterval(iw.Interval); ok {
|
||||
inc.LoadK(*klines)
|
||||
}
|
||||
|
||||
if debugEWMA {
|
||||
inc.OnUpdate(func(value float64) {
|
||||
logrus.Infof("%s EWMA %s: value=%f", set.Symbol, iw.String(), value)
|
||||
})
|
||||
}
|
||||
|
||||
inc.BindK(set.stream, set.Symbol, iw.Interval)
|
||||
set.ewma[iw] = inc
|
||||
}
|
||||
|
||||
return inc
|
||||
}
|
||||
|
||||
func (set *StandardIndicatorSet) STOCH(iw types.IntervalWindow) *indicator.STOCH {
|
||||
inc, ok := set.stoch[iw]
|
||||
if !ok {
|
||||
inc = &indicator.STOCH{IntervalWindow: iw}
|
||||
|
||||
if klines, ok := set.store.KLinesOfInterval(iw.Interval); ok {
|
||||
inc.LoadK(*klines)
|
||||
}
|
||||
|
||||
inc.BindK(set.stream, set.Symbol, iw.Interval)
|
||||
set.stoch[iw] = inc
|
||||
}
|
||||
|
||||
return inc
|
||||
}
|
|
@ -96,27 +96,37 @@ func (inc *BOLL) Update(value float64) {
|
|||
inc.DownBand.Push(downBand)
|
||||
}
|
||||
|
||||
func (inc *BOLL) BindK(target KLineClosedEmitter, symbol string, interval types.Interval) {
|
||||
target.OnKLineClosed(types.KLineWith(symbol, interval, inc.PushK))
|
||||
}
|
||||
|
||||
func (inc *BOLL) PushK(k types.KLine) {
|
||||
inc.Update(k.Close.Float64())
|
||||
}
|
||||
|
||||
func (inc *BOLL) CalculateAndUpdate(allKLines []types.KLine) {
|
||||
var last = allKLines[len(allKLines)-1]
|
||||
|
||||
if inc.SMA == nil {
|
||||
for _, k := range allKLines {
|
||||
if inc.EndTime != zeroTime && k.EndTime.Before(inc.EndTime) {
|
||||
continue
|
||||
return
|
||||
}
|
||||
inc.Update(k.Close.Float64())
|
||||
inc.EndTime = k.EndTime.Time()
|
||||
inc.EmitUpdate(inc.SMA.Last(), inc.UpBand.Last(), inc.DownBand.Last())
|
||||
}
|
||||
|
||||
func (inc *BOLL) LoadK(allKLines []types.KLine) {
|
||||
for _, k := range allKLines {
|
||||
inc.PushK(k)
|
||||
}
|
||||
} else {
|
||||
inc.PushK(last)
|
||||
}
|
||||
|
||||
inc.EmitUpdate(inc.SMA.Last(), inc.UpBand.Last(), inc.DownBand.Last())
|
||||
}
|
||||
|
||||
func (inc *BOLL) CalculateAndUpdate(allKLines []types.KLine) {
|
||||
if inc.SMA == nil {
|
||||
inc.LoadK(allKLines)
|
||||
return
|
||||
}
|
||||
|
||||
var last = allKLines[len(allKLines)-1]
|
||||
inc.PushK(last)
|
||||
}
|
||||
|
||||
func (inc *BOLL) handleKLineWindowUpdate(interval types.Interval, window types.KLineWindow) {
|
||||
if inc.Interval != interval {
|
||||
return
|
||||
|
|
|
@ -16,7 +16,7 @@ type EWMA struct {
|
|||
types.SeriesBase
|
||||
|
||||
Values types.Float64Slice
|
||||
LastOpenTime time.Time
|
||||
EndTime time.Time
|
||||
|
||||
updateCallbacks []func(value float64)
|
||||
}
|
||||
|
@ -58,17 +58,11 @@ func (inc *EWMA) Length() int {
|
|||
return len(inc.Values)
|
||||
}
|
||||
|
||||
func (inc *EWMA) PushK(k types.KLine) {
|
||||
inc.Update(k.Close.Float64())
|
||||
inc.LastOpenTime = k.StartTime.Time()
|
||||
}
|
||||
|
||||
func (inc *EWMA) CalculateAndUpdate(allKLines []types.KLine) {
|
||||
if len(inc.Values) == 0 {
|
||||
for _, k := range allKLines {
|
||||
inc.PushK(k)
|
||||
}
|
||||
|
||||
inc.EmitUpdate(inc.Last())
|
||||
} else {
|
||||
k := allKLines[len(allKLines)-1]
|
||||
|
@ -89,6 +83,27 @@ func (inc *EWMA) Bind(updater KLineWindowUpdater) {
|
|||
updater.OnKLineWindowUpdate(inc.handleKLineWindowUpdate)
|
||||
}
|
||||
|
||||
func (inc *EWMA) BindK(target KLineClosedEmitter, symbol string, interval types.Interval) {
|
||||
target.OnKLineClosed(types.KLineWith(symbol, interval, inc.PushK))
|
||||
}
|
||||
|
||||
func (inc *EWMA) PushK(k types.KLine) {
|
||||
if inc.EndTime != zeroTime && k.EndTime.Before(inc.EndTime) {
|
||||
return
|
||||
}
|
||||
|
||||
inc.Update(k.Close.Float64())
|
||||
inc.EndTime = k.EndTime.Time()
|
||||
inc.EmitUpdate(inc.Last())
|
||||
}
|
||||
|
||||
func (inc *EWMA) LoadK(allKLines []types.KLine) {
|
||||
for _, k := range allKLines {
|
||||
inc.PushK(k)
|
||||
}
|
||||
inc.EmitUpdate(inc.Last())
|
||||
}
|
||||
|
||||
func CalculateKLinesEMA(allKLines []types.KLine, priceF KLinePriceMapper, window int) float64 {
|
||||
var multiplier = 2.0 / (float64(window) + 1)
|
||||
return ewma(MapKLinePrice(allKLines, priceF), multiplier)
|
||||
|
|
|
@ -61,7 +61,7 @@ func (inc *HULL) CalculateAndUpdate(allKLines []types.KLine) {
|
|||
doable = true
|
||||
}
|
||||
for _, k := range allKLines {
|
||||
if !doable && k.StartTime.After(inc.ma1.LastOpenTime) {
|
||||
if !doable && k.EndTime.After(inc.ma1.EndTime) {
|
||||
doable = true
|
||||
}
|
||||
if doable {
|
||||
|
|
|
@ -56,26 +56,34 @@ func (inc *SMA) Update(value float64) {
|
|||
inc.Values.Push(types.Mean(inc.rawValues))
|
||||
}
|
||||
|
||||
func (inc *SMA) BindK(target KLineClosedEmitter, symbol string, interval types.Interval) {
|
||||
target.OnKLineClosed(types.KLineWith(symbol, interval, inc.PushK))
|
||||
}
|
||||
|
||||
func (inc *SMA) PushK(k types.KLine) {
|
||||
if inc.EndTime != zeroTime && k.EndTime.Before(inc.EndTime) {
|
||||
return
|
||||
}
|
||||
|
||||
inc.Update(k.Close.Float64())
|
||||
inc.EndTime = k.EndTime.Time()
|
||||
inc.EmitUpdate(inc.Values.Last())
|
||||
}
|
||||
|
||||
func (inc *SMA) LoadK(allKLines []types.KLine) {
|
||||
for _, k := range allKLines {
|
||||
inc.PushK(k)
|
||||
}
|
||||
}
|
||||
|
||||
func (inc *SMA) CalculateAndUpdate(allKLines []types.KLine) {
|
||||
var last = allKLines[len(allKLines)-1]
|
||||
|
||||
if inc.rawValues == nil {
|
||||
for _, k := range allKLines {
|
||||
if inc.EndTime != zeroTime && k.EndTime.Before(inc.EndTime) {
|
||||
continue
|
||||
}
|
||||
inc.PushK(k)
|
||||
}
|
||||
inc.LoadK(allKLines)
|
||||
} else {
|
||||
var last = allKLines[len(allKLines)-1]
|
||||
inc.PushK(last)
|
||||
}
|
||||
|
||||
inc.EmitUpdate(inc.Values.Last())
|
||||
}
|
||||
|
||||
func (inc *SMA) handleKLineWindowUpdate(interval types.Interval, window types.KLineWindow) {
|
||||
|
@ -86,10 +94,6 @@ func (inc *SMA) handleKLineWindowUpdate(interval types.Interval, window types.KL
|
|||
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) {
|
||||
updater.OnKLineWindowUpdate(inc.handleKLineWindowUpdate)
|
||||
}
|
||||
|
|
|
@ -61,6 +61,22 @@ func (inc *STOCH) LastD() float64 {
|
|||
|
||||
func (inc *STOCH) PushK(k types.KLine) {
|
||||
inc.Update(k.High.Float64(), k.Low.Float64(), k.Close.Float64())
|
||||
inc.EndTime = k.EndTime.Time()
|
||||
}
|
||||
|
||||
func (inc *STOCH) BindK(target KLineClosedEmitter, symbol string, interval types.Interval) {
|
||||
target.OnKLineClosed(types.KLineWith(symbol, interval, inc.PushK))
|
||||
}
|
||||
|
||||
func (inc *STOCH) LoadK(allKLines []types.KLine) {
|
||||
for _, k := range allKLines {
|
||||
if inc.EndTime != zeroTime && !k.EndTime.After(inc.EndTime) {
|
||||
continue
|
||||
}
|
||||
|
||||
inc.PushK(k)
|
||||
}
|
||||
inc.EmitUpdate(inc.LastK(), inc.LastD())
|
||||
}
|
||||
|
||||
func (inc *STOCH) CalculateAndUpdate(kLines []types.KLine) {
|
||||
|
@ -77,7 +93,6 @@ func (inc *STOCH) CalculateAndUpdate(kLines []types.KLine) {
|
|||
}
|
||||
|
||||
inc.EmitUpdate(inc.LastK(), inc.LastD())
|
||||
inc.EndTime = kLines[len(kLines)-1].EndTime.Time()
|
||||
}
|
||||
|
||||
func (inc *STOCH) handleKLineWindowUpdate(interval types.Interval, window types.KLineWindow) {
|
||||
|
|
|
@ -96,7 +96,7 @@ func (inc *TILL) CalculateAndUpdate(allKLines []types.KLine) {
|
|||
doable = true
|
||||
}
|
||||
for _, k := range allKLines {
|
||||
if !doable && k.StartTime.After(inc.e1.LastOpenTime) {
|
||||
if !doable && k.EndTime.After(inc.e1.EndTime) {
|
||||
doable = true
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user