|
|
|
@ -49,10 +49,11 @@ func (b *SigStrategyBacktester) SubKline(instId string, interval types.Interval, |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Backtest 基于历史数据回测信号策略
|
|
|
|
// Backtest 基于历史数据回测信号策略
|
|
|
|
func (b *SigStrategyBacktester) Backtest(ctx context.Context, sigStrategyInput types.Input, sr *pb.SeriesRange, |
|
|
|
func (b *SigStrategyBacktester) Backtest(ctx context.Context, |
|
|
|
// cleanIntervalSeries *types.IntervalState[*types.KlineSeries],
|
|
|
|
sigStrategyInput types.Input, |
|
|
|
|
|
|
|
sr *pb.SeriesRange, |
|
|
|
iiks *types.InstanceIntervalKlineSeries, |
|
|
|
iiks *types.InstanceIntervalKlineSeries, |
|
|
|
recvSignal func(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() |
|
|
|
@ -68,7 +69,7 @@ func (b *SigStrategyBacktester) Backtest(ctx context.Context, sigStrategyInput t |
|
|
|
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, recvSignal) |
|
|
|
case strategy.SigStrategyTypeInstanceInterval: |
|
|
|
case strategy.SigStrategyTypeInstanceInterval: |
|
|
|
// todo
|
|
|
|
err = b.instanceIntervalStrategySeries(ctx, b.sigStrategy.(strategy.IInstanceIntervalSigStrategy), sigStrategyInput, sr, iiks, recvSignal) |
|
|
|
default: |
|
|
|
default: |
|
|
|
err = fmt.Errorf("unknown sig strategy type %v", b.sigStrategyType) |
|
|
|
err = fmt.Errorf("unknown sig strategy type %v", b.sigStrategyType) |
|
|
|
} |
|
|
|
} |
|
|
|
@ -76,7 +77,13 @@ func (b *SigStrategyBacktester) Backtest(ctx context.Context, sigStrategyInput t |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// singleStrategySeries 单周期策略
|
|
|
|
// singleStrategySeries 单周期策略
|
|
|
|
func (b *SigStrategyBacktester) singleStrategySeries(ctx context.Context, sigStrategy strategy.ISingleSigStrategy, sigStrategyInput types.Input, sr *pb.SeriesRange, iiks *types.InstanceIntervalKlineSeries, recvSignal func(sigSide types.Side, k types.Kline) (err error)) (err error) { |
|
|
|
func (b *SigStrategyBacktester) singleStrategySeries(ctx context.Context, |
|
|
|
|
|
|
|
sigStrategy strategy.ISingleSigStrategy, |
|
|
|
|
|
|
|
sigStrategyInput types.Input, |
|
|
|
|
|
|
|
sr *pb.SeriesRange, |
|
|
|
|
|
|
|
iiks *types.InstanceIntervalKlineSeries, |
|
|
|
|
|
|
|
recvSignal func(instId string, sigSide types.Side, k types.Kline) (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) |
|
|
|
@ -95,7 +102,7 @@ func (b *SigStrategyBacktester) singleStrategySeries(ctx context.Context, sigStr |
|
|
|
} |
|
|
|
} |
|
|
|
sigSide := sigStrategy.Update(strategyContext) |
|
|
|
sigSide := sigStrategy.Update(strategyContext) |
|
|
|
if sigSide.IsValid() { |
|
|
|
if sigSide.IsValid() { |
|
|
|
if err = recvSignal(sigSide, *k); err != nil { |
|
|
|
if err = recvSignal(driverInstId, sigSide, *k); err != nil { |
|
|
|
return |
|
|
|
return |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
@ -105,7 +112,13 @@ func (b *SigStrategyBacktester) singleStrategySeries(ctx context.Context, sigStr |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// intervalStrategySeries 多周期策略
|
|
|
|
// intervalStrategySeries 多周期策略
|
|
|
|
func (b *SigStrategyBacktester) intervalStrategySeries(ctx context.Context, intervalSigStrategy strategy.IIntervalSigStrategy, sigStrategyInput types.Input, sr *pb.SeriesRange, iiks *types.InstanceIntervalKlineSeries, recvSignal func(sigSide types.Side, k types.Kline) (err error)) (err error) { |
|
|
|
func (b *SigStrategyBacktester) intervalStrategySeries(ctx context.Context, |
|
|
|
|
|
|
|
intervalSigStrategy strategy.IIntervalSigStrategy, |
|
|
|
|
|
|
|
sigStrategyInput types.Input, |
|
|
|
|
|
|
|
sr *pb.SeriesRange, |
|
|
|
|
|
|
|
iiks *types.InstanceIntervalKlineSeries, |
|
|
|
|
|
|
|
recvSignal func(instId string, sigSide types.Side, k types.Kline) (err error), |
|
|
|
|
|
|
|
) (err error) { |
|
|
|
driverInstId := sr.InstId |
|
|
|
driverInstId := sr.InstId |
|
|
|
driverInterval := types.Interval(sr.Interval) |
|
|
|
driverInterval := types.Interval(sr.Interval) |
|
|
|
intervalKlineSeries := iiks.GetIntervalKlineSeries(driverInstId) |
|
|
|
intervalKlineSeries := iiks.GetIntervalKlineSeries(driverInstId) |
|
|
|
@ -114,10 +127,13 @@ func (b *SigStrategyBacktester) intervalStrategySeries(ctx context.Context, inte |
|
|
|
// 各周期所需k线数量
|
|
|
|
// 各周期所需k线数量
|
|
|
|
intervalCandlePeriods := intervalSigStrategy.CandlePeriods(intervalStrategyContext) |
|
|
|
intervalCandlePeriods := intervalSigStrategy.CandlePeriods(intervalStrategyContext) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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) { |
|
|
|
if !driver || instId != driverInstId || interval != driverInterval { |
|
|
|
if !driver || instId != driverInstId || interval != driverInterval { |
|
|
|
return |
|
|
|
return |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// 策略所需周期窗口是否满足检查
|
|
|
|
|
|
|
|
if !periodsChecked { |
|
|
|
update := true |
|
|
|
update := true |
|
|
|
intervalCandlePeriods.Range(func(interval types.Interval, require int16) { |
|
|
|
intervalCandlePeriods.Range(func(interval types.Interval, require int16) { |
|
|
|
if update && require > 0 { |
|
|
|
if update && require > 0 { |
|
|
|
@ -128,37 +144,64 @@ func (b *SigStrategyBacktester) intervalStrategySeries(ctx context.Context, inte |
|
|
|
if !update { |
|
|
|
if !update { |
|
|
|
return |
|
|
|
return |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
periodsChecked = true |
|
|
|
|
|
|
|
} |
|
|
|
sigSide := intervalSigStrategy.Update(intervalStrategyContext) |
|
|
|
sigSide := intervalSigStrategy.Update(intervalStrategyContext) |
|
|
|
if sigSide.IsValid() { |
|
|
|
if sigSide.IsValid() { |
|
|
|
if err = recvSignal(sigSide, *k); err != nil { |
|
|
|
if err = recvSignal(driverInstId, sigSide, *k); err != nil { |
|
|
|
return |
|
|
|
return |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
return |
|
|
|
return |
|
|
|
}) |
|
|
|
}) |
|
|
|
|
|
|
|
return |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// instanceIntervalStrategySeries 多币种多周期策略
|
|
|
|
|
|
|
|
func (b *SigStrategyBacktester) instanceIntervalStrategySeries(ctx context.Context, |
|
|
|
|
|
|
|
intervalSigStrategy strategy.IInstanceIntervalSigStrategy, |
|
|
|
|
|
|
|
sigStrategyInput types.Input, |
|
|
|
|
|
|
|
sr *pb.SeriesRange, |
|
|
|
|
|
|
|
iiks *types.InstanceIntervalKlineSeries, |
|
|
|
|
|
|
|
recvSignal func(instId string, sigSide types.Side, k types.Kline) (err error), |
|
|
|
|
|
|
|
) (err error) { |
|
|
|
|
|
|
|
driverInstId := sr.InstId |
|
|
|
|
|
|
|
driverInterval := types.Interval(sr.Interval) |
|
|
|
|
|
|
|
|
|
|
|
// err = b.multiIntervalSeries(ctx, sr, intervalCandlePeriods, intervalKlineSeries, func(driver bool, interval types.Interval, k *types.Kline) (err error) {
|
|
|
|
// 策略上下文
|
|
|
|
// if !driver {
|
|
|
|
strategyContext := sig.NewInstanceIntervalSigStrategyContext(sigStrategyInput, iiks, b.indicatorReg) |
|
|
|
// return
|
|
|
|
// 各周期所需k线数量
|
|
|
|
// }
|
|
|
|
tradeInsts, intervalCandlePeriods := intervalSigStrategy.CandlePeriods(strategyContext) |
|
|
|
// update := true
|
|
|
|
|
|
|
|
// intervalCandlePeriods.Range(func(interval types.Interval, require int16) {
|
|
|
|
periodsChecked := false |
|
|
|
// if update && require > 0 {
|
|
|
|
err = b.multiInstanceIntervalSeries(ctx, sr, tradeInsts, intervalCandlePeriods, iiks, func(driver bool, instId string, interval types.Interval, k *types.Kline) (err error) { |
|
|
|
// series := intervalKlineSeries.Get(interval)
|
|
|
|
if !driver || instId != driverInstId || interval != driverInterval { |
|
|
|
// update = series.Length() >= int(require)
|
|
|
|
return |
|
|
|
// }
|
|
|
|
} |
|
|
|
// })
|
|
|
|
// 策略所需周期窗口是否满足检查
|
|
|
|
// if !update {
|
|
|
|
if !periodsChecked { |
|
|
|
// return
|
|
|
|
update := true |
|
|
|
// }
|
|
|
|
for _, instId := range tradeInsts { |
|
|
|
// sigSide := intervalSigStrategy.Update(intervalStrategyContext)
|
|
|
|
intervalCandlePeriods.Range(func(interval types.Interval, periods int16) { |
|
|
|
// if sigSide.IsValid() {
|
|
|
|
if update && periods > 0 { |
|
|
|
// if err = recvSignal(sigSide, *k); err != nil {
|
|
|
|
series := iiks.Get(instId, interval) |
|
|
|
// return
|
|
|
|
update = series.Length() >= int(periods) |
|
|
|
// }
|
|
|
|
} |
|
|
|
// }
|
|
|
|
}) |
|
|
|
// return
|
|
|
|
if !update { |
|
|
|
// })
|
|
|
|
return |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
periodsChecked = true |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
sigSideInsts := intervalSigStrategy.Update(strategyContext) |
|
|
|
|
|
|
|
for _, si := range sigSideInsts { |
|
|
|
|
|
|
|
if err = recvSignal(si.InstId, si.Side, *k); err != nil { |
|
|
|
|
|
|
|
return |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return |
|
|
|
|
|
|
|
}) |
|
|
|
return |
|
|
|
return |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@ -266,7 +309,7 @@ func (b *SigStrategyBacktester) multiInstanceIntervalSeries(ctx context.Context, |
|
|
|
} |
|
|
|
} |
|
|
|
return |
|
|
|
return |
|
|
|
}) |
|
|
|
}) |
|
|
|
zlog.Debugf("other sr finish with: %s(%s), %v", isr.InstId, isr.Interval, err1) |
|
|
|
zlog.Debugf("other sr finish with: %s(%s), %v, last=%d", isr.InstId, isr.Interval, err1, intervalAdder(kSeries.MustGet(0).Ts, 1)) |
|
|
|
if err1 == nil { |
|
|
|
if err1 == nil { |
|
|
|
syncCh <- -1 // 通知更新完毕, 后续不再更新
|
|
|
|
syncCh <- -1 // 通知更新完毕, 后续不再更新
|
|
|
|
} else if err1 != errStop { |
|
|
|
} else if err1 != errStop { |
|
|
|
@ -317,7 +360,7 @@ func (b *SigStrategyBacktester) multiInstanceIntervalSeries(ctx context.Context, |
|
|
|
} |
|
|
|
} |
|
|
|
return recvFn(true, driverInstId, driverInterval, k) |
|
|
|
return recvFn(true, driverInstId, driverInterval, k) |
|
|
|
}) |
|
|
|
}) |
|
|
|
zlog.Debugf("driver sr finish with: %s(%s), %v,", sr.InstId, sr.Interval, err0) |
|
|
|
zlog.Debugf("driver sr finish with: %s(%s), %v, last=%d", sr.InstId, sr.Interval, err0, driverIntervalAdder(driverSeries.MustGet(0).Ts, 1)) |
|
|
|
if err0 == nil { |
|
|
|
if err0 == nil { |
|
|
|
close(stopCh) |
|
|
|
close(stopCh) |
|
|
|
} else if err0 != errStop { |
|
|
|
} else if err0 != errStop { |
|
|
|
|