|
|
|
|
@ -658,80 +658,115 @@ func (svc *ExchangeService) ExchangeInstanceState(req *pb.ReqExchangeInstanceSta
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
const ( |
|
|
|
|
MaxHistoryKlines = 200 |
|
|
|
|
DefaultHistoryKlines = 200 |
|
|
|
|
MaxHistoryKlines = 4096 |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
// HistoryKline 获取交易产品历史k线 (before < klines... < after)
|
|
|
|
|
func (svc *ExchangeService) HistoryKline(ctx context.Context, req *pb.ReqHistoryKline, rsp *pb.RspHistoryKline) (klines []*types.Kline, err error) { |
|
|
|
|
func (svc *ExchangeService) CalcSeriesRange(arg *pb.SeriesRange) (after, before, total int64, err error) { |
|
|
|
|
// 交易产品参数检查
|
|
|
|
|
exchange := svc.exchanges.Get(req.Exchange) |
|
|
|
|
exchangeInstId, ok := exchange.TradeInstIds.Load(req.InstId) |
|
|
|
|
exchange := svc.exchanges.Get(arg.Exchange) |
|
|
|
|
exchangeInstId, ok := exchange.TradeInstIds.Load(arg.InstId) |
|
|
|
|
if !ok { |
|
|
|
|
err = fmt.Errorf("trade instance not support: %s", req.InstId) |
|
|
|
|
err = fmt.Errorf("trade instance not support: %s", arg.InstId) |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
interval := types.Interval(req.Interval) |
|
|
|
|
intervalAdder, ok := types.SupportedIntervals[interval] |
|
|
|
|
exchangeInst, ok := exchange.ExchangeInsts.Load(exchangeInstId) |
|
|
|
|
if !ok { |
|
|
|
|
err = fmt.Errorf("interval not support: %s", req.Interval) |
|
|
|
|
err = fmt.Errorf("trade instance not support for exchange: %s for %s", arg.InstId, arg.Exchange) |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// todo 交易产品初始化完成检查
|
|
|
|
|
exchangeInst, ok := exchange.ExchangeInsts.Load(exchangeInstId) |
|
|
|
|
interval := types.Interval(arg.Interval) |
|
|
|
|
intervalAdder, ok := types.SupportedIntervals[interval] |
|
|
|
|
if !ok { |
|
|
|
|
err = fmt.Errorf("trade instance not support for exchange: %s for %s", req.InstId, req.Exchange) |
|
|
|
|
err = fmt.Errorf("interval not support: %s", arg.Interval) |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// k线长度检查
|
|
|
|
|
afterTs, beforeTs, count := int64(req.After), int64(req.Before), int64(req.Count) |
|
|
|
|
after, before, count := int64(arg.After), int64(arg.Before), int64(arg.Count) |
|
|
|
|
if count == 0 { |
|
|
|
|
count = MaxHistoryKlines |
|
|
|
|
count = DefaultHistoryKlines |
|
|
|
|
} |
|
|
|
|
// 拉取最新的
|
|
|
|
|
lastTs := int64(0) |
|
|
|
|
if req.After == 0 { |
|
|
|
|
if arg.After == 0 { |
|
|
|
|
liveK := exchangeInst.LiveKline.Get(interval) |
|
|
|
|
lastTs = liveK.Ts |
|
|
|
|
if !liveK.Confirm { |
|
|
|
|
lastTs = intervalAdder(liveK.Ts, -1) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
if afterTs == 0 && beforeTs == 0 { |
|
|
|
|
afterTs = lastTs |
|
|
|
|
if after == 0 && before == 0 { |
|
|
|
|
after = lastTs |
|
|
|
|
} |
|
|
|
|
if afterTs == 0 { |
|
|
|
|
afterTs = min(intervalAdder(beforeTs, count-1), lastTs) |
|
|
|
|
if after == 0 { |
|
|
|
|
after = min(intervalAdder(before, count-1), lastTs) |
|
|
|
|
} |
|
|
|
|
if beforeTs == 0 { |
|
|
|
|
beforeTs = max(intervalAdder(afterTs, -count+1), KlineBefore0) |
|
|
|
|
if before == 0 { |
|
|
|
|
before = max(intervalAdder(after, -count+1), KlineBefore0) |
|
|
|
|
} |
|
|
|
|
// 开区间
|
|
|
|
|
if req.Open { |
|
|
|
|
if req.After != 0 { |
|
|
|
|
afterTs = max(intervalAdder(afterTs, -1), beforeTs) |
|
|
|
|
if req.Before == 0 { |
|
|
|
|
beforeTs = max(intervalAdder(beforeTs, -1), KlineBefore0) |
|
|
|
|
if arg.Open { |
|
|
|
|
if arg.After != 0 { |
|
|
|
|
after = max(intervalAdder(after, -1), before) |
|
|
|
|
if arg.Before == 0 { |
|
|
|
|
before = max(intervalAdder(before, -1), KlineBefore0) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
if arg.Before != 0 { |
|
|
|
|
before = min(intervalAdder(before, 1), after) |
|
|
|
|
if arg.After == 0 { |
|
|
|
|
after = min(intervalAdder(before, 1), lastTs) |
|
|
|
|
} |
|
|
|
|
if req.Before != 0 { |
|
|
|
|
beforeTs = min(intervalAdder(beforeTs, 1), afterTs) |
|
|
|
|
if req.After == 0 { |
|
|
|
|
afterTs = min(intervalAdder(beforeTs, 1), lastTs) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
// 额外拉取
|
|
|
|
|
if arg.Window > 0 { |
|
|
|
|
before = max(intervalAdder(before, -int64(arg.Window)), KlineBefore0) |
|
|
|
|
} |
|
|
|
|
if beforeTs > afterTs { |
|
|
|
|
if before > after { |
|
|
|
|
err = fmt.Errorf("time range invalid: before must less then after") |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
// 拉取范围总条数
|
|
|
|
|
total = (after-before)/intervalAdder(0, 1) + 1 |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// HistoryKline 获取交易产品历史k线 (before < klines... < after)
|
|
|
|
|
func (svc *ExchangeService) HistoryKline(ctx context.Context, arg *pb.SeriesRange) (live bool, klines []*types.Kline, err error) { |
|
|
|
|
// 交易产品参数检查
|
|
|
|
|
exchange := svc.exchanges.Get(arg.Exchange) |
|
|
|
|
exchangeInstId, ok := exchange.TradeInstIds.Load(arg.InstId) |
|
|
|
|
if !ok { |
|
|
|
|
err = fmt.Errorf("trade instance not support: %s", arg.InstId) |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
interval := types.Interval(arg.Interval) |
|
|
|
|
intervalAdder, ok := types.SupportedIntervals[interval] |
|
|
|
|
if !ok { |
|
|
|
|
err = fmt.Errorf("interval not support: %s", arg.Interval) |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// todo 交易产品初始化完成检查
|
|
|
|
|
exchangeInst, ok := exchange.ExchangeInsts.Load(exchangeInstId) |
|
|
|
|
if !ok { |
|
|
|
|
err = fmt.Errorf("trade instance not support for exchange: %s for %s", arg.InstId, arg.Exchange) |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
// 限制最大时间范围
|
|
|
|
|
total := (afterTs-beforeTs)/intervalAdder(0, 1) + 1 |
|
|
|
|
afterTs, beforeTs, total, err := svc.CalcSeriesRange(arg) |
|
|
|
|
if err != nil { |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
if total > MaxHistoryKlines { |
|
|
|
|
err = fmt.Errorf("time range too large max %d", MaxHistoryKlines) |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
if arg.Limit > 0 && total > int64(arg.Limit) { |
|
|
|
|
err = fmt.Errorf("time range %d out of limit %d", total, arg.Limit) |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
klines, err = svc.exchangeDataPersist.ListKline(*exchangeInst.Inst, interval, beforeTs, afterTs) |
|
|
|
|
if err != nil { |
|
|
|
|
@ -742,7 +777,7 @@ func (svc *ExchangeService) HistoryKline(ctx context.Context, req *pb.ReqHistory
|
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
// 检查k线是否连续进行补齐
|
|
|
|
|
if err = svc.paddingKlinesIfNotSeries(exchange, req.InstId, interval, klines); err != nil { |
|
|
|
|
if err = svc.paddingKlinesIfNotSeries(exchange, arg.InstId, interval, klines); err != nil { |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@ -759,101 +794,46 @@ func (svc *ExchangeService) HistoryKline(ctx context.Context, req *pb.ReqHistory
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 降序排序
|
|
|
|
|
if req.Desc { |
|
|
|
|
if arg.Desc { |
|
|
|
|
collect.Reverse(klines) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 实时k线
|
|
|
|
|
if req.Live && len(klines) > 0 { |
|
|
|
|
if arg.Live && len(klines) > 0 { |
|
|
|
|
liveK := exchangeInst.LiveKline.Get(interval) |
|
|
|
|
if latest := intervalAdder(lastK.Ts, 1) == liveK.Ts; latest { |
|
|
|
|
if req.Desc { |
|
|
|
|
if arg.Desc { |
|
|
|
|
klines = append([]*types.Kline{&liveK}, klines...) |
|
|
|
|
} else { |
|
|
|
|
klines = append(klines, &liveK) |
|
|
|
|
} |
|
|
|
|
rsp.Live = true |
|
|
|
|
live = true |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 查询历史k线(按时间升序流式返回)
|
|
|
|
|
func (svc *ExchangeService) HistoryKlineStream(req *pb.ReqHistoryKlineStream, stream grpc.ServerStreamingServer[pb.RspHistoryKlineStream]) (err error) { |
|
|
|
|
// 交易产品参数检查
|
|
|
|
|
if !svc.exchanges.IsSupport(req.Exchange) { |
|
|
|
|
err = fmt.Errorf("exchange not support: %s", req.Exchange) |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
exchange := svc.exchanges.Get(req.Exchange) |
|
|
|
|
exchangeInstId, ok := exchange.TradeInstIds.Load(req.InstId) |
|
|
|
|
if !ok { |
|
|
|
|
err = fmt.Errorf("trade instance not support: %s", req.InstId) |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
interval := types.Interval(req.Interval) |
|
|
|
|
intervalAdder, ok := types.SupportedIntervals[interval] |
|
|
|
|
if !ok { |
|
|
|
|
err = fmt.Errorf("interval not support: %s", req.Interval) |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
// todo 交易产品初始化完成检查
|
|
|
|
|
exchangeInst, ok := exchange.ExchangeInsts.Load(exchangeInstId) |
|
|
|
|
if !ok { |
|
|
|
|
err = fmt.Errorf("trade instance not support for exchange: %s for %s", req.InstId, req.Exchange) |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// k线长度检查
|
|
|
|
|
afterTs, beforeTs, count := int64(req.After), int64(req.Before), int64(req.Count) |
|
|
|
|
if count == 0 { |
|
|
|
|
count = 100 |
|
|
|
|
} |
|
|
|
|
liveK := exchangeInst.LiveKline.Get(interval) |
|
|
|
|
lastTs := liveK.Ts |
|
|
|
|
if !liveK.Confirm { |
|
|
|
|
lastTs = intervalAdder(liveK.Ts, -1) |
|
|
|
|
} |
|
|
|
|
if afterTs == 0 && beforeTs == 0 { |
|
|
|
|
beforeTs = max(intervalAdder(lastTs, -count+1), KlineBefore0) |
|
|
|
|
afterTs = lastTs |
|
|
|
|
} |
|
|
|
|
if afterTs == 0 { |
|
|
|
|
afterTs = min(intervalAdder(beforeTs, count-1), lastTs) |
|
|
|
|
} |
|
|
|
|
if beforeTs == 0 { |
|
|
|
|
beforeTs = max(intervalAdder(afterTs, -count+1), KlineBefore0) |
|
|
|
|
} |
|
|
|
|
if beforeTs > afterTs { |
|
|
|
|
err = fmt.Errorf("time range invalid: before must less then after") |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
klines, err := svc.exchangeDataPersist.ListKline(*exchangeInst.Inst, interval, beforeTs, afterTs) |
|
|
|
|
func (svc *ExchangeService) HistoryKlineStream(arg *pb.SeriesRange, stream grpc.ServerStreamingServer[pb.RspHistoryKlineStream]) (err error) { |
|
|
|
|
ctx := context.Background() |
|
|
|
|
_, klines, err := svc.HistoryKline(ctx, arg) |
|
|
|
|
if err != nil { |
|
|
|
|
zlog.Error("fetch history kline stream error: ", err) |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
if len(klines) == 0 { |
|
|
|
|
|
|
|
|
|
// 交易产品参数检查
|
|
|
|
|
if !svc.exchanges.IsSupport(arg.Exchange) { |
|
|
|
|
err = fmt.Errorf("exchange not support: %s", arg.Exchange) |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
exchange := svc.exchanges.Get(arg.Exchange) |
|
|
|
|
interval := types.Interval(arg.Interval) |
|
|
|
|
|
|
|
|
|
// 检查k线是否连续进行补齐
|
|
|
|
|
if err = svc.paddingKlinesIfNotSeries(exchange, req.InstId, interval, klines); err != nil { |
|
|
|
|
if err = svc.paddingKlinesIfNotSeries(exchange, arg.InstId, interval, klines); err != nil { |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
lastK := klines[len(klines)-1] |
|
|
|
|
// vmtsdb 数据刷盘30s延迟, 使用内存数据替代第一根k线
|
|
|
|
|
lastConfirmK := exchangeInst.LastKline.Get(interval) |
|
|
|
|
if lastConfirmK.Ts == lastK.Ts { |
|
|
|
|
klines[len(klines)-1] = &lastConfirmK |
|
|
|
|
lastK = klines[len(klines)-1] |
|
|
|
|
} |
|
|
|
|
if lastConfirmK.Ts == afterTs && intervalAdder(lastK.Ts, 1) == afterTs { |
|
|
|
|
klines = append(klines, &lastConfirmK) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
branch := 100 |
|
|
|
|
length := len(klines) |
|
|
|
|
kBuffer := make([]*pb.Kline, 0, branch) |
|
|
|
|
|