|
|
|
@ -213,7 +213,7 @@ func (svc *TradingService) IndicatorSeries(ctx context.Context, indicatorName st |
|
|
|
|
|
|
|
|
|
|
|
// 查询历史指标数据
|
|
|
|
// 查询历史指标数据
|
|
|
|
requiredSeries := int(indicator.RequiredSeries(int16(window))) |
|
|
|
requiredSeries := int(indicator.RequiredSeries(int16(window))) |
|
|
|
sr.WindowExtra = uint32(requiredSeries) |
|
|
|
sr.WindowExtra = uint32(requiredSeries - 1) |
|
|
|
kSeries := sig.NewKlineSeries(sr.Exchange, sr.InstId, types.Interval(sr.Interval)) |
|
|
|
kSeries := sig.NewKlineSeries(sr.Exchange, sr.InstId, types.Interval(sr.Interval)) |
|
|
|
indicatorContext := sig.NewIndicatorContext(kSeries) |
|
|
|
indicatorContext := sig.NewIndicatorContext(kSeries) |
|
|
|
|
|
|
|
|
|
|
|
@ -263,6 +263,38 @@ func (svc *TradingService) StrategySeries(ctx context.Context, req *pb.ReqStrate |
|
|
|
rsp.Signal, rsp.Times, err = svc.singleStrategySeries(ctx, sigStrategy.(strategy.ISingleSigStrategy), req.Series) |
|
|
|
rsp.Signal, rsp.Times, err = svc.singleStrategySeries(ctx, sigStrategy.(strategy.ISingleSigStrategy), req.Series) |
|
|
|
case strategy.SigStrategyTypeInterval: |
|
|
|
case strategy.SigStrategyTypeInterval: |
|
|
|
rsp.Signal, rsp.Times, err = svc.intervalStrategySeries(ctx, sigStrategy.(strategy.IIntervalSigStrategy), req.Series) |
|
|
|
rsp.Signal, rsp.Times, err = svc.intervalStrategySeries(ctx, sigStrategy.(strategy.IIntervalSigStrategy), req.Series) |
|
|
|
|
|
|
|
default: |
|
|
|
|
|
|
|
err = fmt.Errorf("unknown sig strategy type %v", sigStrategyType) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// singleStrategySeries 单周期策略
|
|
|
|
|
|
|
|
func (svc *TradingService) singleStrategySeries(ctx context.Context, sigStrategy strategy.ISingleSigStrategy, sr *pb.SeriesRange) (signals []pb.Side, times []int64, err error) { |
|
|
|
|
|
|
|
interval := types.Interval(sr.Interval) |
|
|
|
|
|
|
|
requiredSeries := int(sigStrategy.RequiredSeries()) |
|
|
|
|
|
|
|
sr.WindowExtra = uint32(requiredSeries - 1) |
|
|
|
|
|
|
|
kSeries := sig.NewKlineSeries(sr.Exchange, sr.InstId, interval) |
|
|
|
|
|
|
|
indicatorContext := sig.NewIndicatorContext(kSeries) |
|
|
|
|
|
|
|
strategyContext := sig.NewStrategyContext(indicatorContext, svc.indicatorReg) |
|
|
|
|
|
|
|
err = svc.fetchHistoryKlineSeries(ctx, sr, func(k *types.Kline) (err error) { |
|
|
|
|
|
|
|
if lastTs, serial := kSeries.Update(k); !serial { |
|
|
|
|
|
|
|
err = fmt.Errorf("kline not series: %s(%s), interval=%s, lastTs=%d", sr.InstId, sr.Exchange, interval, lastTs) |
|
|
|
|
|
|
|
return |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if kSeries.Length() < requiredSeries { |
|
|
|
|
|
|
|
return |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
sigSide := sigStrategy.Update(strategyContext) |
|
|
|
|
|
|
|
if sigSide.IsValid() { |
|
|
|
|
|
|
|
side := lang.Ternary(sigSide == types.SideLong, pb.Side_BUY, pb.Side_SELL) |
|
|
|
|
|
|
|
signals = append(signals, side) |
|
|
|
|
|
|
|
times = append(times, k.Ts) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return |
|
|
|
|
|
|
|
}) |
|
|
|
|
|
|
|
if err != nil { |
|
|
|
|
|
|
|
return |
|
|
|
} |
|
|
|
} |
|
|
|
return |
|
|
|
return |
|
|
|
} |
|
|
|
} |
|
|
|
@ -295,32 +327,30 @@ func (svc *TradingService) intervalStrategySeries(ctx context.Context, intervalS |
|
|
|
for _, interval := range otherIntervals { |
|
|
|
for _, interval := range otherIntervals { |
|
|
|
kSeries := sig.NewKlineSeries(sr.Exchange, sr.InstId, interval) |
|
|
|
kSeries := sig.NewKlineSeries(sr.Exchange, sr.InstId, interval) |
|
|
|
intervalKlineSeries.Set(interval, kSeries) |
|
|
|
intervalKlineSeries.Set(interval, kSeries) |
|
|
|
|
|
|
|
|
|
|
|
go func(interval types.Interval, kSeries *sig.KlineSeries) { |
|
|
|
go func(interval types.Interval, kSeries *sig.KlineSeries) { |
|
|
|
ch := otherIntervalCh.Get(interval) |
|
|
|
ch := otherIntervalCh.Get(interval) |
|
|
|
srcCh := ch[0] |
|
|
|
srcCh := ch[0] |
|
|
|
dstCh := ch[1] |
|
|
|
dstCh := ch[1] |
|
|
|
intervalAdder := types.SupportedIntervals[interval] |
|
|
|
intervalAdder := types.SupportedIntervals[interval] |
|
|
|
driverTs := int64(0) |
|
|
|
driverTs := int64(0) |
|
|
|
isr := &pb.SeriesRange{Exchange: sr.Exchange, InstId: sr.InstId, Before: sr.Before, After: sr.After, Count: sr.Count, Open: sr.Open, Live: sr.Live, Desc: sr.Desc, WindowExtra: sr.WindowExtra, Limit: sr.Limit, |
|
|
|
isr := &pb.SeriesRange{Exchange: sr.Exchange, InstId: sr.InstId, Before: sr.Before, After: sr.After, Count: sr.Count, Open: sr.Open, Live: sr.Live, Desc: sr.Desc, Limit: sr.Limit} |
|
|
|
Interval: string(interval)} |
|
|
|
isr.Interval = string(interval) |
|
|
|
|
|
|
|
isr.WindowExtra = uint32(requiredIntervalSeries.Get(interval) - 1) |
|
|
|
err1 := svc.fetchHistoryKlineSeries(ctx, isr, func(k *types.Kline) (err error) { |
|
|
|
err1 := svc.fetchHistoryKlineSeries(ctx, isr, func(k *types.Kline) (err error) { |
|
|
|
closeTs := intervalAdder(k.Ts, 1) |
|
|
|
closeTs := intervalAdder(k.Ts, 1) |
|
|
|
// 与驱动周期series保持同步更新
|
|
|
|
// 与驱动周期series保持同步更新
|
|
|
|
if closeTs > driverTs { |
|
|
|
if closeTs > driverTs { |
|
|
|
|
|
|
|
waitLoop: |
|
|
|
|
|
|
|
for { |
|
|
|
if driverTs != 0 { |
|
|
|
if driverTs != 0 { |
|
|
|
dstCh <- 0 // 通知更新完毕
|
|
|
|
dstCh <- 0 // 通知更新完毕
|
|
|
|
} |
|
|
|
} |
|
|
|
waitLoop: |
|
|
|
|
|
|
|
for { |
|
|
|
|
|
|
|
select { |
|
|
|
select { |
|
|
|
case <-stopCh: |
|
|
|
case <-stopCh: |
|
|
|
return io.EOF |
|
|
|
return io.EOF |
|
|
|
case driverTs = <-srcCh: |
|
|
|
case driverTs = <-srcCh: |
|
|
|
if closeTs <= driverTs { |
|
|
|
if closeTs <= driverTs { |
|
|
|
break waitLoop |
|
|
|
break waitLoop |
|
|
|
} else { |
|
|
|
|
|
|
|
dstCh <- 0 // 通知更新完毕
|
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
@ -331,9 +361,9 @@ func (svc *TradingService) intervalStrategySeries(ctx context.Context, intervalS |
|
|
|
} |
|
|
|
} |
|
|
|
return |
|
|
|
return |
|
|
|
}) |
|
|
|
}) |
|
|
|
|
|
|
|
|
|
|
|
if err1 == nil { |
|
|
|
if err1 == nil { |
|
|
|
otherIntervalCh.Set(interval, nil) |
|
|
|
otherIntervalCh.Set(interval, nil) // 该周期数据拉取结束
|
|
|
|
|
|
|
|
dstCh <- 0 // 通知更新完毕
|
|
|
|
} else if err1 != io.EOF { |
|
|
|
} else if err1 != io.EOF { |
|
|
|
zlog.Errorf("fetch history interval error: inst=%s(%s) interval=%s, err=%v", sr.InstId, sr.Exchange, interval, err1) |
|
|
|
zlog.Errorf("fetch history interval error: inst=%s(%s) interval=%s, err=%v", sr.InstId, sr.Exchange, interval, err1) |
|
|
|
err = err1 |
|
|
|
err = err1 |
|
|
|
@ -348,17 +378,24 @@ func (svc *TradingService) intervalStrategySeries(ctx context.Context, intervalS |
|
|
|
// 驱动周期数据拉取
|
|
|
|
// 驱动周期数据拉取
|
|
|
|
driverSeries := sig.NewKlineSeries(sr.Exchange, sr.InstId, driverInterval) |
|
|
|
driverSeries := sig.NewKlineSeries(sr.Exchange, sr.InstId, driverInterval) |
|
|
|
intervalKlineSeries.Set(driverInterval, driverSeries) |
|
|
|
intervalKlineSeries.Set(driverInterval, driverSeries) |
|
|
|
|
|
|
|
sr.WindowExtra = uint32(requiredIntervalSeries.Get(driverInterval) - 1) |
|
|
|
err = svc.fetchHistoryKlineSeries(ctx, sr, func(k *types.Kline) (err error) { |
|
|
|
err = svc.fetchHistoryKlineSeries(ctx, sr, func(k *types.Kline) (err error) { |
|
|
|
driverTS := driverIntervalAdder(k.Ts, 1) |
|
|
|
driverTS := driverIntervalAdder(k.Ts, 1) |
|
|
|
// 通知其他周期先更新
|
|
|
|
|
|
|
|
otherIntervalCh.Range(func(interval types.Interval, ch []chan int64) { |
|
|
|
otherIntervalCh.Range(func(interval types.Interval, ch []chan int64) { |
|
|
|
if len(ch) == 2 { |
|
|
|
if len(ch) == 2 { |
|
|
|
|
|
|
|
// 通知其它周期先更新
|
|
|
|
select { |
|
|
|
select { |
|
|
|
case <-stopCh: |
|
|
|
case <-stopCh: |
|
|
|
err = io.EOF |
|
|
|
err = io.EOF |
|
|
|
return |
|
|
|
return |
|
|
|
case ch[0] <- driverTS: |
|
|
|
case ch[0] <- driverTS: |
|
|
|
<-ch[1] // 等待更新完毕
|
|
|
|
// 等待其它周期更新完毕
|
|
|
|
|
|
|
|
select { |
|
|
|
|
|
|
|
case <-stopCh: |
|
|
|
|
|
|
|
err = io.EOF |
|
|
|
|
|
|
|
return |
|
|
|
|
|
|
|
case <-ch[1]: |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
}) |
|
|
|
}) |
|
|
|
@ -366,6 +403,7 @@ func (svc *TradingService) intervalStrategySeries(ctx context.Context, intervalS |
|
|
|
return |
|
|
|
return |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
zlog.Debugf("driver series update: %s, %d", driverInterval, driverTS) |
|
|
|
if lastTs, serial := driverSeries.Update(k); !serial { |
|
|
|
if lastTs, serial := driverSeries.Update(k); !serial { |
|
|
|
err = fmt.Errorf("kline not series: %s(%s), interval=%s, lastTs=%d", sr.InstId, sr.Exchange, driverInterval, lastTs) |
|
|
|
err = fmt.Errorf("kline not series: %s(%s), interval=%s, lastTs=%d", sr.InstId, sr.Exchange, driverInterval, lastTs) |
|
|
|
return |
|
|
|
return |
|
|
|
@ -392,7 +430,6 @@ func (svc *TradingService) intervalStrategySeries(ctx context.Context, intervalS |
|
|
|
signals = append(signals, side) |
|
|
|
signals = append(signals, side) |
|
|
|
times = append(times, k.Ts) |
|
|
|
times = append(times, k.Ts) |
|
|
|
} |
|
|
|
} |
|
|
|
zlog.Debugf("strategy update finish ------------------------------------") |
|
|
|
|
|
|
|
return |
|
|
|
return |
|
|
|
}) |
|
|
|
}) |
|
|
|
if err != io.EOF { |
|
|
|
if err != io.EOF { |
|
|
|
@ -401,36 +438,6 @@ func (svc *TradingService) intervalStrategySeries(ctx context.Context, intervalS |
|
|
|
return |
|
|
|
return |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// singleStrategySeries 单周期策略
|
|
|
|
|
|
|
|
func (svc *TradingService) singleStrategySeries(ctx context.Context, sigStrategy strategy.ISingleSigStrategy, sr *pb.SeriesRange) (signals []pb.Side, times []int64, err error) { |
|
|
|
|
|
|
|
interval := types.Interval(sr.Interval) |
|
|
|
|
|
|
|
requiredSeries := int(sigStrategy.RequiredSeries()) |
|
|
|
|
|
|
|
sr.WindowExtra = uint32(requiredSeries) |
|
|
|
|
|
|
|
kSeries := sig.NewKlineSeries(sr.Exchange, sr.InstId, interval) |
|
|
|
|
|
|
|
indicatorContext := sig.NewIndicatorContext(kSeries) |
|
|
|
|
|
|
|
strategyContext := sig.NewStrategyContext(indicatorContext, svc.indicatorReg) |
|
|
|
|
|
|
|
err = svc.fetchHistoryKlineSeries(ctx, sr, func(k *types.Kline) (err error) { |
|
|
|
|
|
|
|
if lastTs, serial := kSeries.Update(k); !serial { |
|
|
|
|
|
|
|
err = fmt.Errorf("kline not series: %s(%s), interval=%s, lastTs=%d", sr.InstId, sr.Exchange, interval, lastTs) |
|
|
|
|
|
|
|
return |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if kSeries.Length() < requiredSeries { |
|
|
|
|
|
|
|
return |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
sigSide := sigStrategy.Update(strategyContext) |
|
|
|
|
|
|
|
if sigSide.IsValid() { |
|
|
|
|
|
|
|
side := lang.Ternary(sigSide == types.SideLong, pb.Side_BUY, pb.Side_SELL) |
|
|
|
|
|
|
|
signals = append(signals, side) |
|
|
|
|
|
|
|
times = append(times, k.Ts) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return |
|
|
|
|
|
|
|
}) |
|
|
|
|
|
|
|
if err != nil { |
|
|
|
|
|
|
|
return |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Backtest 回测交易计划
|
|
|
|
// Backtest 回测交易计划
|
|
|
|
func (svc *TradingService) Backtest(planId, stime, etime int64) (err error) { |
|
|
|
func (svc *TradingService) Backtest(planId, stime, etime int64) (err error) { |
|
|
|
plan, err := svc.tradingDataPersist.GetTradePlanById(planId) |
|
|
|
plan, err := svc.tradingDataPersist.GetTradePlanById(planId) |
|
|
|
|