You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
231 lines
6.2 KiB
231 lines
6.2 KiB
package trading |
|
|
|
import ( |
|
"context" |
|
"fmt" |
|
"sig-pub/api/pb" |
|
"sig-pub/pkg/data" |
|
"sig-pub/pkg/types" |
|
"sig-pub/pkg/utils/collect" |
|
"sig-pub/pkg/utils/misc" |
|
"sig-pub/pkg/utils/times" |
|
"sig-pub/pkg/zlog" |
|
|
|
"github.com/bytedance/sonic" |
|
"google.golang.org/protobuf/types/known/structpb" |
|
) |
|
|
|
type TradingGrpcServer struct { |
|
pb.UnimplementedTradingServiceServer |
|
tradingService *TradingService |
|
} |
|
|
|
func NewTradingGrpcServer(tradingService *TradingService) *TradingGrpcServer { |
|
return &TradingGrpcServer{ |
|
tradingService: tradingService, |
|
} |
|
} |
|
|
|
func (svr *TradingGrpcServer) Init() (err error) { |
|
return |
|
} |
|
|
|
func (svr *TradingGrpcServer) Indicators(ctx context.Context, req *pb.ReqIndicators) (rsp *pb.RspIndicators, err error) { |
|
rsp = new(pb.RspIndicators) |
|
rsp.Indicators = svr.tradingService.Indicators() |
|
return |
|
} |
|
|
|
func (svr *TradingGrpcServer) IndicatorMetas(ctx context.Context, req *pb.ReqIndicatorMetas) (rsp *pb.RspIndicatorMetas, err error) { |
|
indMetas, err := svr.tradingService.IndicatorMeta(req.Indicators...) |
|
if err != nil { |
|
return |
|
} |
|
indPlots, err := svr.tradingService.IndicatorPlots(req.Indicators...) |
|
if err != nil { |
|
return |
|
} |
|
rsp = new(pb.RspIndicatorMetas) |
|
for _, indName := range req.Indicators { |
|
// 指标元数据 |
|
meta := indMetas[indName] |
|
p := &pb.IndicatorMeta{ |
|
Name: indName, |
|
Desc: meta.Desc, |
|
State: meta.State, |
|
} |
|
// 指标输入参数 |
|
for _, input := range meta.Input { |
|
p.Input = append(p.Input, &pb.InputArg{ |
|
Name: input.Name, |
|
Desc: input.Desc, |
|
Type: int32(input.Type), |
|
Default: misc.Ternary(input.Default == nil, "", fmt.Sprintf("%v", input.Default)), |
|
Options: collect.Mapping(input.Options, func(opt types.InputOption) *pb.InputOption { |
|
return &pb.InputOption{ |
|
Name: opt.Name, |
|
Desc: opt.Desc, |
|
} |
|
}), |
|
}) |
|
} |
|
// 指标绘图属性 |
|
for _, plot := range indPlots[indName] { |
|
ps := &pb.IndicatorPlotSeries{ |
|
Name: plot.Name, |
|
State: plot.State, |
|
Type: int32(plot.Type), |
|
} |
|
if ps.Props, err = structpb.NewStruct(plot.Props); err != nil { |
|
return |
|
} |
|
for _, exp := range plot.Exps { |
|
pe := &pb.IndicatorPlotExp{ |
|
Exp: exp.Exp, |
|
} |
|
if pe.Props, err = structpb.NewStruct(exp.Props); err != nil { |
|
return |
|
} |
|
ps.Exps = append(ps.Exps, pe) |
|
} |
|
p.Plots = append(p.Plots, ps) |
|
} |
|
rsp.Metas = append(rsp.Metas, p) |
|
} |
|
return |
|
} |
|
|
|
func (svr *TradingGrpcServer) IndicatorPlots(ctx context.Context, req *pb.ReqIndicatorPlots) (rsp *pb.RspIndicatorPlots, err error) { |
|
indPlots, err := svr.tradingService.IndicatorPlots(req.Indicators...) |
|
if err != nil { |
|
return |
|
} |
|
rsp = new(pb.RspIndicatorPlots) |
|
for _, indName := range req.Indicators { |
|
plots := indPlots[indName] |
|
p := &pb.IndicatorPlot{Indicator: indName} |
|
for _, plot := range plots { |
|
ps := &pb.IndicatorPlotSeries{ |
|
Name: plot.Name, |
|
State: plot.State, |
|
Type: int32(plot.Type), |
|
} |
|
if ps.Props, err = structpb.NewStruct(plot.Props); err != nil { |
|
return |
|
} |
|
for _, exp := range plot.Exps { |
|
pe := &pb.IndicatorPlotExp{ |
|
Exp: exp.Exp, |
|
} |
|
if pe.Props, err = structpb.NewStruct(exp.Props); err != nil { |
|
return |
|
} |
|
ps.Exps = append(ps.Exps, pe) |
|
} |
|
p.Plots = append(p.Plots, ps) |
|
} |
|
rsp.Plots = append(rsp.Plots, p) |
|
} |
|
return |
|
} |
|
|
|
func (svr *TradingGrpcServer) IndicatorSeries(ctx context.Context, req *pb.ReqIndicatorSeries) (rsp *pb.RspIndicatorSeries, err error) { |
|
// s, err := structpb.NewStruct(map[string]any{}) |
|
input := req.Input.AsMap() |
|
matrix, times, states, err := svr.tradingService.IndicatorSeries(ctx, req.Indicator, req.Digit, types.Input(input), req.Series) |
|
if err != nil { |
|
return |
|
} |
|
rsp = &pb.RspIndicatorSeries{} |
|
rsp.Matrix = matrix |
|
rsp.Times = times |
|
for state, value := range states { |
|
rsp.States = append(rsp.States, &pb.IndicatorState{ |
|
State: state, |
|
Matrix: value, |
|
}) |
|
} |
|
return |
|
} |
|
|
|
func (svr *TradingGrpcServer) IndicatorSummary(ctx context.Context, req *pb.ReqIndicatorSummary) (rsp *pb.RspIndicatorSummary, err error) { |
|
input := req.Input.AsMap() |
|
summary, err := svr.tradingService.IndicatorSummary(ctx, req.Indicator, req.Digit, types.Input(input), req.Series) |
|
if err != nil { |
|
return |
|
} |
|
summaryJson, err := sonic.Marshal(summary) |
|
if err != nil { |
|
err = fmt.Errorf("marshal indicator summary error: %w", err) |
|
return |
|
} |
|
rsp = &pb.RspIndicatorSummary{ |
|
Indicator: req.Indicator, |
|
Summary: summaryJson, |
|
} |
|
return |
|
} |
|
|
|
func (svr *TradingGrpcServer) StrategySeries(ctx context.Context, req *pb.ReqStrategySeries) (rsp *pb.RspStrategySeries, err error) { |
|
rsp = &pb.RspStrategySeries{} |
|
err = svr.tradingService.StrategySeries(ctx, req, rsp) |
|
return |
|
} |
|
|
|
func (svr *TradingGrpcServer) Backtest(ctx context.Context, req *pb.ReqBacktest) (rsp *pb.RspBacktest, err error) { |
|
stime, err := times.ParseFORMAT(req.Stime) |
|
if err != nil { |
|
return |
|
} |
|
etime, err := times.ParseFORMAT(req.Etime) |
|
if err != nil { |
|
return |
|
} |
|
taskId, err := svr.tradingService.Backtest(ctx, req.PlanId, stime.UnixMilli(), etime.UnixMilli()) |
|
if err != nil { |
|
return |
|
} |
|
rsp = &pb.RspBacktest{TaskId: taskId} |
|
return |
|
} |
|
|
|
// BacktestLog 回测记录查询 |
|
func (svr *TradingGrpcServer) BacktestLog(ctx context.Context, req *pb.ReqBacktestLog) (rsp *pb.RspBacktestLog, err error) { |
|
if req.Paging == nil { |
|
req.Paging = &pb.Paging{Page: 1, Size: 20, Asc: true, SortBy: "id"} |
|
} |
|
paging := data.PageArgs0(int(req.Paging.Page), int(req.Paging.Size), req.Paging.SortBy, req.Paging.Asc) |
|
logs, err := svr.tradingService.BacktestLog(ctx, 10001, paging, req.Running) |
|
if err != nil { |
|
return |
|
} |
|
rsp = new(pb.RspBacktestLog) |
|
for _, l := range logs { |
|
log := &pb.BacktestLog{ |
|
PlanId: l.PlanId, |
|
Stime: l.SeriesBefore, |
|
Etime: l.SeriesAfter, |
|
BacktestId: l.Id, |
|
Status: l.RunningStatus, |
|
Progress: l.RunningProgress, |
|
Total: l.RunningTotal, |
|
Pct: l.RunningPct, |
|
TaskId: l.RunningTaskId, |
|
} |
|
rsp.Logs = append(rsp.Logs, log) |
|
} |
|
return |
|
} |
|
|
|
// BacktestRace 交易计划参数调试回测 |
|
func (svr *TradingGrpcServer) BacktestRace(ctx context.Context, req *pb.ReqBacktestRace) (rsp *pb.RspBacktestRace, err error) { |
|
rsp = new(pb.RspBacktestRace) |
|
misc.SafeGo(func() { |
|
c := context.Background() |
|
err := svr.tradingService.BacktestRace(c, req) |
|
if err != nil { |
|
zlog.Error("BacktestRace error:", err) |
|
} |
|
}) |
|
return |
|
}
|
|
|