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
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) |
|
}
|
|
|