|
|
|
@ -53,11 +53,15 @@ func (b *SigStrategyBacktester) Backtest(ctx context.Context, |
|
|
|
sigStrategyInput types.Input, |
|
|
|
sigStrategyInput types.Input, |
|
|
|
sr *pb.SeriesRange, |
|
|
|
sr *pb.SeriesRange, |
|
|
|
iiks *types.InstanceIntervalKlineSeries, |
|
|
|
iiks *types.InstanceIntervalKlineSeries, |
|
|
|
|
|
|
|
intervalCandlePeriods *types.IntervalState[int16], |
|
|
|
recvSignal func(instId string, sigSide types.Side, k types.Kline) (err error), |
|
|
|
recvSignal func(instId string, sigSide types.Side, k types.Kline) (err error), |
|
|
|
) (err error) { |
|
|
|
) (err error) { |
|
|
|
if iiks == nil { |
|
|
|
if iiks == nil { |
|
|
|
iiks = types.NewInstanceIntervalKlineSeries() |
|
|
|
iiks = types.NewInstanceIntervalKlineSeries() |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if intervalCandlePeriods == nil { |
|
|
|
|
|
|
|
intervalCandlePeriods = types.NewIntervalState[int16]() |
|
|
|
|
|
|
|
} |
|
|
|
// init sig strategy
|
|
|
|
// init sig strategy
|
|
|
|
if err = b.sigStrategy.Init(sigStrategyInput); err != nil { |
|
|
|
if err = b.sigStrategy.Init(sigStrategyInput); err != nil { |
|
|
|
return |
|
|
|
return |
|
|
|
@ -65,11 +69,11 @@ func (b *SigStrategyBacktester) Backtest(ctx context.Context, |
|
|
|
|
|
|
|
|
|
|
|
switch b.sigStrategyType { |
|
|
|
switch b.sigStrategyType { |
|
|
|
case strategy.SigStrategyTypeSingle: |
|
|
|
case strategy.SigStrategyTypeSingle: |
|
|
|
err = b.singleStrategySeries(ctx, b.sigStrategy.(strategy.ISingleSigStrategy), sigStrategyInput, sr, iiks, recvSignal) |
|
|
|
err = b.singleStrategySeries(ctx, b.sigStrategy.(strategy.ISingleSigStrategy), sigStrategyInput, sr, iiks, intervalCandlePeriods, recvSignal) |
|
|
|
case strategy.SigStrategyTypeInterval: |
|
|
|
case strategy.SigStrategyTypeInterval: |
|
|
|
err = b.intervalStrategySeries(ctx, b.sigStrategy.(strategy.IIntervalSigStrategy), sigStrategyInput, sr, iiks, recvSignal) |
|
|
|
err = b.intervalStrategySeries(ctx, b.sigStrategy.(strategy.IIntervalSigStrategy), sigStrategyInput, sr, iiks, intervalCandlePeriods, recvSignal) |
|
|
|
case strategy.SigStrategyTypeInstanceInterval: |
|
|
|
case strategy.SigStrategyTypeInstanceInterval: |
|
|
|
err = b.instanceIntervalStrategySeries(ctx, b.sigStrategy.(strategy.IInstanceIntervalSigStrategy), sigStrategyInput, sr, iiks, recvSignal) |
|
|
|
err = b.instanceIntervalStrategySeries(ctx, b.sigStrategy.(strategy.IInstanceIntervalSigStrategy), sigStrategyInput, sr, iiks, intervalCandlePeriods, recvSignal) |
|
|
|
default: |
|
|
|
default: |
|
|
|
err = fmt.Errorf("unknown sig strategy type %v", b.sigStrategyType) |
|
|
|
err = fmt.Errorf("unknown sig strategy type %v", b.sigStrategyType) |
|
|
|
} |
|
|
|
} |
|
|
|
@ -82,16 +86,17 @@ func (b *SigStrategyBacktester) singleStrategySeries(ctx context.Context, |
|
|
|
sigStrategyInput types.Input, |
|
|
|
sigStrategyInput types.Input, |
|
|
|
sr *pb.SeriesRange, |
|
|
|
sr *pb.SeriesRange, |
|
|
|
iiks *types.InstanceIntervalKlineSeries, |
|
|
|
iiks *types.InstanceIntervalKlineSeries, |
|
|
|
|
|
|
|
intervalCandlePeriods *types.IntervalState[int16], |
|
|
|
recvSignal func(instId string, sigSide types.Side, k types.Kline) (err error), |
|
|
|
recvSignal func(instId string, sigSide types.Side, k types.Kline) (err error), |
|
|
|
) (err error) { |
|
|
|
) (err error) { |
|
|
|
driverInstId := sr.InstId |
|
|
|
driverInstId := sr.InstId |
|
|
|
driverInterval := types.Interval(sr.Interval) |
|
|
|
driverInterval := types.Interval(sr.Interval) |
|
|
|
driverSeries := iiks.Get(driverInstId, driverInterval) |
|
|
|
driverSeries := iiks.Get(driverInstId, driverInterval) |
|
|
|
strategyContext := sig.NewStrategyContext(sigStrategyInput, driverSeries, b.indicatorReg) |
|
|
|
strategyContext := sig.NewStrategyContext(sigStrategyInput, driverSeries, b.indicatorReg) |
|
|
|
requiredPeriods := int(sigStrategy.CandlePeriods(strategyContext)) |
|
|
|
requiredPeriods := max(1, int(sigStrategy.CandlePeriods(strategyContext))) |
|
|
|
|
|
|
|
intervalCandlePeriods.SetIf(driverInterval, int16(requiredPeriods), func(old int16) bool { |
|
|
|
intervalCandlePeriods := types.NewIntervalState[int16]() |
|
|
|
return old < int16(requiredPeriods) |
|
|
|
intervalCandlePeriods.Set(driverInterval, int16(max(1, requiredPeriods))) |
|
|
|
}) |
|
|
|
|
|
|
|
|
|
|
|
err = b.multiInstanceIntervalSeries(ctx, sr, []string{sr.InstId}, intervalCandlePeriods, iiks, func(driver bool, instId string, interval types.Interval, k *types.Kline) (err error) { |
|
|
|
err = b.multiInstanceIntervalSeries(ctx, sr, []string{sr.InstId}, intervalCandlePeriods, iiks, func(driver bool, instId string, interval types.Interval, k *types.Kline) (err error) { |
|
|
|
if !driver || instId != driverInstId || interval != driverInterval { |
|
|
|
if !driver || instId != driverInstId || interval != driverInterval { |
|
|
|
@ -117,6 +122,7 @@ func (b *SigStrategyBacktester) intervalStrategySeries(ctx context.Context, |
|
|
|
sigStrategyInput types.Input, |
|
|
|
sigStrategyInput types.Input, |
|
|
|
sr *pb.SeriesRange, |
|
|
|
sr *pb.SeriesRange, |
|
|
|
iiks *types.InstanceIntervalKlineSeries, |
|
|
|
iiks *types.InstanceIntervalKlineSeries, |
|
|
|
|
|
|
|
intervalCandlePeriods *types.IntervalState[int16], |
|
|
|
recvSignal func(instId string, sigSide types.Side, k types.Kline) (err error), |
|
|
|
recvSignal func(instId string, sigSide types.Side, k types.Kline) (err error), |
|
|
|
) (err error) { |
|
|
|
) (err error) { |
|
|
|
driverInstId := sr.InstId |
|
|
|
driverInstId := sr.InstId |
|
|
|
@ -125,7 +131,15 @@ func (b *SigStrategyBacktester) intervalStrategySeries(ctx context.Context, |
|
|
|
// 策略上下文
|
|
|
|
// 策略上下文
|
|
|
|
intervalStrategyContext := sig.NewIntervalStrategyContext(sigStrategyInput, intervalKlineSeries, b.indicatorReg) |
|
|
|
intervalStrategyContext := sig.NewIntervalStrategyContext(sigStrategyInput, intervalKlineSeries, b.indicatorReg) |
|
|
|
// 各周期所需k线数量
|
|
|
|
// 各周期所需k线数量
|
|
|
|
intervalCandlePeriods := intervalSigStrategy.CandlePeriods(intervalStrategyContext) |
|
|
|
strategyIntervalCandlePeriods := intervalSigStrategy.CandlePeriods(intervalStrategyContext) |
|
|
|
|
|
|
|
// 合并所有需加载周期
|
|
|
|
|
|
|
|
strategyIntervalCandlePeriods.Range(func(interval types.Interval, require int16) { |
|
|
|
|
|
|
|
if require > 0 { |
|
|
|
|
|
|
|
intervalCandlePeriods.SetIf(interval, require, func(old int16) bool { |
|
|
|
|
|
|
|
return old < require |
|
|
|
|
|
|
|
}) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
|
|
periodsChecked := false |
|
|
|
periodsChecked := false |
|
|
|
err = b.multiInstanceIntervalSeries(ctx, sr, []string{sr.InstId}, intervalCandlePeriods, iiks, func(driver bool, instId string, interval types.Interval, k *types.Kline) (err error) { |
|
|
|
err = b.multiInstanceIntervalSeries(ctx, sr, []string{sr.InstId}, intervalCandlePeriods, iiks, func(driver bool, instId string, interval types.Interval, k *types.Kline) (err error) { |
|
|
|
@ -163,6 +177,7 @@ func (b *SigStrategyBacktester) instanceIntervalStrategySeries(ctx context.Conte |
|
|
|
sigStrategyInput types.Input, |
|
|
|
sigStrategyInput types.Input, |
|
|
|
sr *pb.SeriesRange, |
|
|
|
sr *pb.SeriesRange, |
|
|
|
iiks *types.InstanceIntervalKlineSeries, |
|
|
|
iiks *types.InstanceIntervalKlineSeries, |
|
|
|
|
|
|
|
intervalCandlePeriods *types.IntervalState[int16], |
|
|
|
recvSignal func(instId string, sigSide types.Side, k types.Kline) (err error), |
|
|
|
recvSignal func(instId string, sigSide types.Side, k types.Kline) (err error), |
|
|
|
) (err error) { |
|
|
|
) (err error) { |
|
|
|
driverInstId := sr.InstId |
|
|
|
driverInstId := sr.InstId |
|
|
|
@ -171,7 +186,14 @@ func (b *SigStrategyBacktester) instanceIntervalStrategySeries(ctx context.Conte |
|
|
|
// 策略上下文
|
|
|
|
// 策略上下文
|
|
|
|
strategyContext := sig.NewInstanceIntervalSigStrategyContext(sigStrategyInput, iiks, b.indicatorReg) |
|
|
|
strategyContext := sig.NewInstanceIntervalSigStrategyContext(sigStrategyInput, iiks, b.indicatorReg) |
|
|
|
// 各周期所需k线数量
|
|
|
|
// 各周期所需k线数量
|
|
|
|
tradeInsts, intervalCandlePeriods := intervalSigStrategy.CandlePeriods(strategyContext) |
|
|
|
tradeInsts, strategyIntervalCandlePeriods := intervalSigStrategy.CandlePeriods(strategyContext) |
|
|
|
|
|
|
|
strategyIntervalCandlePeriods.Range(func(interval types.Interval, require int16) { |
|
|
|
|
|
|
|
if require > 0 { |
|
|
|
|
|
|
|
intervalCandlePeriods.SetIf(interval, require, func(old int16) bool { |
|
|
|
|
|
|
|
return old < require |
|
|
|
|
|
|
|
}) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
|
|
periodsChecked := false |
|
|
|
periodsChecked := false |
|
|
|
err = b.multiInstanceIntervalSeries(ctx, sr, tradeInsts, intervalCandlePeriods, iiks, func(driver bool, instId string, interval types.Interval, k *types.Kline) (err error) { |
|
|
|
err = b.multiInstanceIntervalSeries(ctx, sr, tradeInsts, intervalCandlePeriods, iiks, func(driver bool, instId string, interval types.Interval, k *types.Kline) (err error) { |
|
|
|
|