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.
 
 

78 lines
2.2 KiB

package backtest
import (
"sig-pub/pkg/indicator"
"sig-pub/pkg/types"
"sig-pub/pkg/types/series"
)
// SigStrategyContext 是一个轻量的策略上下文,用于回测时把历史k线提供给策略
type SigStrategyContext struct {
klines []types.Kline // 时间升序: oldest ... newest
offset int16 // offset applied when indicators request
indReg *indicator.IndicatorRegistry
}
func NewSigStrategyContext(klines []types.Kline, indReg *indicator.IndicatorRegistry) *SigStrategyContext {
return &SigStrategyContext{klines: klines, indReg: indReg}
}
func (c *SigStrategyContext) Get(offset int16) (k types.Kline) {
// offset relative to current (0 = latest)
idx := len(c.klines) - 1 - int(offset+c.offset)
if idx < 0 {
// return zero kline if out of range
return types.Kline{}
}
return c.klines[idx]
}
func (c *SigStrategyContext) Series(offset, count int16) (klines series.Klines) {
// return slice in descending time order as expected by series.Klines
var ret series.Klines
for i := int16(0); i < count; i++ {
k := c.Get(offset + i)
ret = append(ret, k)
}
return ret
}
// WindowIndicatorSeriesLocal 实现 indicator.IIndicatorSeries
type WindowIndicatorSeriesLocal struct {
window int16
ind indicator.IWindowIndicator
ctx *SigStrategyContext
}
func NewWindowIndicatorSeriesLocal(window int16, ind indicator.IWindowIndicator, ctx *SigStrategyContext) *WindowIndicatorSeriesLocal {
return &WindowIndicatorSeriesLocal{window: window, ind: ind, ctx: ctx}
}
func (w *WindowIndicatorSeriesLocal) Get(offset int16) (vector float64) {
// tell indicator to use offset by shifting internal offset then restore
prev := w.ctx.offset
w.ctx.offset += offset
vector = w.ind.Calculate(w.ctx, w.window)
w.ctx.offset = prev
return
}
func (w *WindowIndicatorSeriesLocal) Series(offset, count int16) (matrix series.Floats) {
prev := w.ctx.offset
w.ctx.offset += offset
for i := int16(0); i < count; i++ {
v := w.ind.Calculate(w.ctx, w.window)
matrix.Push(v)
w.ctx.offset++
}
w.ctx.offset = prev
return
}
func (c *SigStrategyContext) IndicatorW(name string, window int16) indicator.IIndicatorSeries {
ind, ok := c.indReg.IndicatorW(name)
if !ok {
panic("indicator not found: " + name)
}
return NewWindowIndicatorSeriesLocal(window, ind, c)
}