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