@ -113,7 +113,7 @@ func (svc *TradingService) getTradingPlan(plan *entity.TradePlan, sigKlineSeries
if err = sonic . UnmarshalString ( plan . SigStrategyParam , & sigStrategyParam ) ; err != nil {
return
}
sigStrategy , ok := svc . strategyReg . NewSigStrategy ( plan . SigStrategy )
sigStrategyType , sigStrategy , ok := svc . strategyReg . NewSigStrategy ( plan . SigStrategy )
if ! ok {
err = fmt . Errorf ( "strategy %s not exists" , plan . SigStrategy )
return
@ -132,7 +132,7 @@ func (svc *TradingService) getTradingPlan(plan *entity.TradePlan, sigKlineSeries
}
sigIndicatorCtx := sig . NewIndicatorContext ( sigKlineSeries )
sigStrategyCtx := sig . NewStrategyContext ( sigIndicatorCtx , svc . indicatorReg )
if err = tradingPlan . InitSigStrategy ( sigStrategy , sigStrategyParam , sigStrategyCtx ) ; err != nil {
if err = tradingPlan . InitSigStrategy ( sigStrategyType , sigStrategy , sigStrategyParam , sigStrategyCtx ) ; err != nil {
return
}
return
@ -192,7 +192,7 @@ func (svc *TradingService) fetchHistoryKlineSeries(ctx context.Context, sr *pb.S
}
}
}
zlog . Debugf ( "fetch history kline series: recv=%d, total=%d, use %s" , recvTimes , recvTotal , watch . ElapsedFmt ( "." ) )
zlog . Debugf ( "fetch history kline series: inst=%s(%s), interval=%s, recv=%d, total=%d, use %s" , sr . InstId , sr . Exchange , sr . Interval , recvTimes , recvTotal , watch . ElapsedFmt ( "." ) )
return
}
@ -241,7 +241,7 @@ func (svc *TradingService) IndicatorSeries(ctx context.Context, indicatorName st
// StrategySeries 简单策略信号测试
func ( svc * TradingService ) StrategySeries ( ctx context . Context , req * pb . ReqStrategySeries , rsp * pb . RspStrategySeries ) ( err error ) {
// sigStrategy
sigStrategy , ok := svc . strategyReg . NewSigStrategy ( req . SigStrategy )
sigStrategyType , sigStrategy , ok := svc . strategyReg . NewSigStrategy ( req . SigStrategy )
if ! ok {
err = fmt . Errorf ( "strategy %s not exists" , req . SigStrategy )
return
@ -258,8 +258,153 @@ func (svc *TradingService) StrategySeries(ctx context.Context, req *pb.ReqStrate
return
}
switch sigStrategyType {
case strategy . SigStrategyTypeSingle :
rsp . Signal , rsp . Times , err = svc . singleStrategySeries ( ctx , sigStrategy . ( strategy . ISingleSigStrategy ) , req . Series )
case strategy . SigStrategyTypeInterval :
rsp . Signal , rsp . Times , err = svc . intervalStrategySeries ( ctx , sigStrategy . ( strategy . IIntervalSigStrategy ) , req . Series )
}
return
}
// intervalStrategySeries 多周期策略
func ( svc * TradingService ) intervalStrategySeries ( ctx context . Context , intervalSigStrategy strategy . IIntervalSigStrategy , sr * pb . SeriesRange ) ( signals [ ] pb . Side , times [ ] int64 , err error ) {
driverInterval := types . Interval ( sr . Interval )
driverIntervalAdder := types . SupportedIntervals [ driverInterval ]
// 各周期所需k线数量
requiredIntervalSeries := intervalSigStrategy . RequiredIntervalSeries ( )
// 驱动周期外其他周期
otherIntervals := make ( [ ] types . Interval , 0 , 3 )
requiredIntervalSeries . Range ( func ( interval types . Interval , series int16 ) {
if series > 0 {
otherIntervals = append ( otherIntervals , interval )
}
} )
otherIntervals = collect . Filter ( otherIntervals , func ( _ int , interval types . Interval ) bool { return interval != driverInterval } )
// 通知其他周期更新的channel
otherIntervalCh := types . NewIntervalState [ [ ] chan int64 ] ( )
// otherIntervalDstCh := types.NewIntervalState[chan int64]()
for _ , interval := range otherIntervals {
otherIntervalCh . Set ( interval , [ ] chan int64 { make ( chan int64 ) , make ( chan int64 ) } )
}
// 各周期 series
intervalKlineSeries := types . NewIntervalState [ * sig . KlineSeries ] ( )
// 其他周期数据拉取
stopCh := make ( chan struct { } )
for _ , interval := range otherIntervals {
kSeries := sig . NewKlineSeries ( sr . Exchange , sr . InstId , interval )
intervalKlineSeries . Set ( interval , kSeries )
go func ( interval types . Interval , kSeries * sig . KlineSeries ) {
ch := otherIntervalCh . Get ( interval )
srcCh := ch [ 0 ]
dstCh := ch [ 1 ]
intervalAdder := types . SupportedIntervals [ interval ]
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 ,
Interval : string ( interval ) }
err1 := svc . fetchHistoryKlineSeries ( ctx , isr , func ( k * types . Kline ) ( err error ) {
closeTs := intervalAdder ( k . Ts , 1 )
// 与驱动周期series保持同步更新
if closeTs > driverTs {
if driverTs != 0 {
dstCh <- 0 // 通知更新完毕
}
waitLoop :
for {
select {
case <- stopCh :
return io . EOF
case driverTs = <- srcCh :
if closeTs <= driverTs {
break waitLoop
} else {
dstCh <- 0 // 通知更新完毕
}
}
}
}
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
}
return
} )
if err1 == nil {
otherIntervalCh . Set ( interval , nil )
} else if err1 != io . EOF {
zlog . Errorf ( "fetch history interval error: inst=%s(%s) interval=%s, err=%v" , sr . InstId , sr . Exchange , interval , err1 )
err = err1
close ( stopCh )
}
} ( interval , kSeries )
}
// 策略上下文
intervalStrategyContext := sig . NewIntervalStrategyContext ( intervalKlineSeries , svc . indicatorReg )
// 驱动周期数据拉取
driverSeries := sig . NewKlineSeries ( sr . Exchange , sr . InstId , driverInterval )
intervalKlineSeries . Set ( driverInterval , driverSeries )
err = svc . fetchHistoryKlineSeries ( ctx , sr , func ( k * types . Kline ) ( err error ) {
driverTS := driverIntervalAdder ( k . Ts , 1 )
// 通知其他周期先更新
otherIntervalCh . Range ( func ( interval types . Interval , ch [ ] chan int64 ) {
if len ( ch ) == 2 {
select {
case <- stopCh :
err = io . EOF
return
case ch [ 0 ] <- driverTS :
<- ch [ 1 ] // 等待更新完毕
}
}
} )
if err != nil {
return
}
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 )
return
}
// 检查满足策略执行条件
update := true
requiredIntervalSeries . Range ( func ( interval types . Interval , require int16 ) {
if update && require > 0 {
series := intervalKlineSeries . Get ( interval )
update = series . Length ( ) >= int ( require )
}
} )
if ! update {
return
}
intervalKlineSeries . Range ( func ( interval types . Interval , v * sig . KlineSeries ) {
if v != nil {
zlog . Debugf ( "strategy update: interval series %s, %d" , interval , v . Length ( ) )
}
} )
sigSide := intervalSigStrategy . Update ( intervalStrategyContext )
if sigSide . IsValid ( ) {
side := lang . Ternary ( sigSide == types . SideLong , pb . Side_BUY , pb . Side_SELL )
signals = append ( signals , side )
times = append ( times , k . Ts )
}
zlog . Debugf ( "strategy update finish ------------------------------------" )
return
} )
if err != io . EOF {
close ( stopCh )
}
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 := req . Series
sr . WindowExtra = uint32 ( requiredSeries )
kSeries := sig . NewKlineSeries ( sr . Exchange , sr . InstId , interval )
indicatorContext := sig . NewIndicatorContext ( kSeries )
@ -275,8 +420,8 @@ func (svc *TradingService) StrategySeries(ctx context.Context, req *pb.ReqStrate
sigSide := sigStrategy . Update ( strategyContext )
if sigSide . IsValid ( ) {
side := lang . Ternary ( sigSide == types . SideLong , pb . Side_BUY , pb . Side_SELL )
r sp . S ignal = append ( r sp . S ignal, side )
rsp . T imes = append ( rsp . T imes, k . Ts )
signals = append ( signals , side )
t imes = append ( t imes, k . Ts )
}
return
} )