You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
81 lines
2.2 KiB
81 lines
2.2 KiB
package sig |
|
|
|
import ( |
|
"fmt" |
|
"sig-pub/pkg/indicator" |
|
"sig-pub/pkg/types" |
|
"sig-pub/pkg/types/series" |
|
) |
|
|
|
// IndicatorState |
|
// ema, obv 指标递归计算时的状态存储 |
|
type IndicatorState struct { |
|
indicator.IIndicatorState |
|
indicatorContext indicator.IIndicatorContext |
|
interval types.Interval |
|
intervalAdder types.IntervalAdder |
|
state map[string]*types.RingSeries[float64] |
|
lastTs map[string]int64 |
|
} |
|
|
|
func NewIndicatorState(interval types.Interval) *IndicatorState { |
|
intervalAdder, ok := types.SupportedIntervals[interval] |
|
if !ok { |
|
panic(fmt.Errorf("unsupport interval: %s", interval)) |
|
} |
|
return &IndicatorState{ |
|
interval: interval, |
|
intervalAdder: intervalAdder, |
|
state: make(map[string]*types.RingSeries[float64]), |
|
lastTs: make(map[string]int64), |
|
} |
|
} |
|
|
|
func (s *IndicatorState) SetIndicatorContext(indicatorContext indicator.IIndicatorContext) { |
|
s.indicatorContext = indicatorContext |
|
} |
|
|
|
func (s *IndicatorState) ring(k string) *types.RingSeries[float64] { |
|
ring, ok := s.state[k] |
|
if !ok { |
|
ring = types.NewRingSeries[float64](indicator.MaxWindow, 8) |
|
s.state[k] = ring |
|
} |
|
return ring |
|
} |
|
|
|
func (s *IndicatorState) Set(k string, v float64) { |
|
ts := s.indicatorContext.Get(0).Ts |
|
if s.lastTs[k] < ts { |
|
// panic可替换为丢失指标用前一个值填充类似vmtsdb |
|
if expectTs := s.intervalAdder(s.lastTs[k], 1); expectTs != ts && s.lastTs[k] != 0 { |
|
panic(fmt.Errorf("state 不连续: lastTs=%d, got=%d, expected=%d", s.lastTs[k], ts, expectTs)) |
|
} |
|
s.ring(k).Push(v) |
|
s.lastTs[k] = ts |
|
} |
|
} |
|
|
|
func (s *IndicatorState) Get(k string, offset int16) (v float64, ok bool) { |
|
ts := s.indicatorContext.Get(0).Ts |
|
target := s.intervalAdder(ts, -int64(offset)) |
|
ring := s.ring(k) |
|
for i := 0; i < ring.Length(); i++ { |
|
if s.intervalAdder(s.lastTs[k], -int64(i)) == target { |
|
return ring.Get(i) |
|
} |
|
} |
|
return |
|
} |
|
|
|
func (s *IndicatorState) Series(k string, offset, count int16) (v series.Floats, ok bool) { |
|
ts := s.indicatorContext.Get(0).Ts |
|
target := s.intervalAdder(ts, -int64(offset)) |
|
ring := s.ring(k) |
|
for i := 0; i < ring.Length(); i++ { |
|
if s.intervalAdder(s.lastTs[k], -int64(i)) == target { |
|
return ring.Series(i, int(count)) |
|
} |
|
} |
|
return |
|
}
|
|
|