|
|
|
@ -10,6 +10,7 @@ import ( |
|
|
|
"sig-pub/pkg/data" |
|
|
|
"sig-pub/pkg/data" |
|
|
|
"sig-pub/pkg/storage/kvrocks" |
|
|
|
"sig-pub/pkg/storage/kvrocks" |
|
|
|
"sig-pub/pkg/types" |
|
|
|
"sig-pub/pkg/types" |
|
|
|
|
|
|
|
"sig-pub/pkg/utils/collect" |
|
|
|
"sig-pub/pkg/utils/times" |
|
|
|
"sig-pub/pkg/utils/times" |
|
|
|
"sig-pub/pkg/zlog" |
|
|
|
"sig-pub/pkg/zlog" |
|
|
|
"sync" |
|
|
|
"sync" |
|
|
|
@ -85,7 +86,8 @@ func (svc *ExchangeGrpcServer) subscribeExchanges() { |
|
|
|
Inst: tradeInst, |
|
|
|
Inst: tradeInst, |
|
|
|
Status: 0, |
|
|
|
Status: 0, |
|
|
|
LiveMarkTs: 0, |
|
|
|
LiveMarkTs: 0, |
|
|
|
HistoryMarkTs: 0, |
|
|
|
LiveKMarkTs: make(map[types.Interval]int64), |
|
|
|
|
|
|
|
HistoryMarkTs: make(map[types.Interval]int64), |
|
|
|
}) |
|
|
|
}) |
|
|
|
// 待初始化币种数据
|
|
|
|
// 待初始化币种数据
|
|
|
|
if inst.Status == data.StatusProcessing { |
|
|
|
if inst.Status == data.StatusProcessing { |
|
|
|
@ -128,9 +130,14 @@ func (svc *ExchangeGrpcServer) consumerKline(exchange *Exchange, c <-chan *types |
|
|
|
if inst, ok := exchange.Insts.Load(channelK.ExgInstId); ok && inst != nil { |
|
|
|
if inst, ok := exchange.Insts.Load(channelK.ExgInstId); ok && inst != nil { |
|
|
|
exInst = inst.Inst |
|
|
|
exInst = inst.Inst |
|
|
|
// 标记交易产品开始订阅k线时间
|
|
|
|
// 标记交易产品开始订阅k线时间
|
|
|
|
if inst.LiveMarkTs == 0 && len(channelK.Klines) > 0 { |
|
|
|
if len(channelK.Klines) > 0 { |
|
|
|
inst.LiveMarkTs = channelK.Klines[0].Ts |
|
|
|
kline := collect.MustMax(channelK.Klines, func(k *types.Kline) int64 { return k.Ts }) |
|
|
|
|
|
|
|
if inst.GetLiveMarkTs(kline.Interval) == 0 { |
|
|
|
|
|
|
|
inst.SetLiveMarkTs(kline.Interval, kline.Ts) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
// confirmKlines := collect.Filter(channelK.Klines, func(_ int, k *types.Kline) bool { return k.Confirm })
|
|
|
|
|
|
|
|
|
|
|
|
} else { |
|
|
|
} else { |
|
|
|
zlog.Errorf("unknown exchange instId: %v, %s", channelK.Exchange, channelK.ExgInstId) |
|
|
|
zlog.Errorf("unknown exchange instId: %v, %s", channelK.Exchange, channelK.ExgInstId) |
|
|
|
continue |
|
|
|
continue |
|
|
|
@ -312,13 +319,13 @@ func (svc *ExchangeGrpcServer) initialKlines(exchange *Exchange, insts []types.T |
|
|
|
var success, failed []types.TradeInstance |
|
|
|
var success, failed []types.TradeInstance |
|
|
|
|
|
|
|
|
|
|
|
for _, inst := range insts { |
|
|
|
for _, inst := range insts { |
|
|
|
err := svc.initTradeInstanceKlines(exchange, inst) |
|
|
|
err := svc.initialTradeInstanceKlines(exchange, inst) |
|
|
|
if err != nil { |
|
|
|
if err != nil { |
|
|
|
|
|
|
|
zlog.Errorf("initial fetch trade instance error: %s(%s), err=%v", inst.InstId, inst.Exchange, err) |
|
|
|
failed = append(failed, inst) |
|
|
|
failed = append(failed, inst) |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
success = append(success, inst) |
|
|
|
success = append(success, inst) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
zlog.Infof("%d insts initial finished, success %d, failed %d", len(insts), len(success), len(failed)) |
|
|
|
zlog.Infof("%d insts initial finished, success %d, failed %d", len(insts), len(success), len(failed)) |
|
|
|
@ -329,7 +336,7 @@ var ( |
|
|
|
) |
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
// initTradeInstanceKlines 初始化交易产品历史k线数据
|
|
|
|
// initTradeInstanceKlines 初始化交易产品历史k线数据
|
|
|
|
func (svc *ExchangeGrpcServer) initTradeInstanceKlines(exchange *Exchange, inst types.TradeInstance) (err error) { |
|
|
|
func (svc *ExchangeGrpcServer) initialTradeInstanceKlines(exchange *Exchange, inst types.TradeInstance) (err error) { |
|
|
|
// 并发数
|
|
|
|
// 并发数
|
|
|
|
concurrent := max(8, runtime.NumCPU()*2) |
|
|
|
concurrent := max(8, runtime.NumCPU()*2) |
|
|
|
// 任务 channel
|
|
|
|
// 任务 channel
|
|
|
|
@ -338,18 +345,35 @@ func (svc *ExchangeGrpcServer) initTradeInstanceKlines(exchange *Exchange, inst |
|
|
|
|
|
|
|
|
|
|
|
// 发布任务数, 成功任务数, 失败任务次数
|
|
|
|
// 发布任务数, 成功任务数, 失败任务次数
|
|
|
|
var pubTasks, subTasks, failTasks atomic.Int32 |
|
|
|
var pubTasks, subTasks, failTasks atomic.Int32 |
|
|
|
|
|
|
|
var pubTaskDone atomic.Bool // 所有任务已发布
|
|
|
|
|
|
|
|
var historyMarkTs = make(map[types.Interval]int64) // 已初始化最后k线时间戳
|
|
|
|
|
|
|
|
var historyMarkTsMu sync.Mutex |
|
|
|
ctx, cancel := context.WithCancel(context.Background()) |
|
|
|
ctx, cancel := context.WithCancel(context.Background()) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
defer func() { |
|
|
|
|
|
|
|
if err != nil { |
|
|
|
|
|
|
|
return |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
for interval, ts := range historyMarkTs { |
|
|
|
|
|
|
|
tsKey := fmt.Sprintf(HistoryKlineTsKey, inst.Exchange, inst.InstId, interval) |
|
|
|
|
|
|
|
if ex := svc.kvdb.SetI64(context.Background(), tsKey, ts); ex != nil { |
|
|
|
|
|
|
|
zlog.Errorf("history mark inititaled ts error: key=%s, ts=%d", tsKey, ts) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}() |
|
|
|
|
|
|
|
|
|
|
|
go func() { |
|
|
|
go func() { |
|
|
|
defer func() { |
|
|
|
defer func() { |
|
|
|
close(taskCh) |
|
|
|
pubTaskDone.Store(true) |
|
|
|
taskCh = nil |
|
|
|
// 无任务处理
|
|
|
|
zlog.Infof("trade instance initial kline %s(%s), pub %d fetch tasks", pubTasks.Load(), inst.InstId, inst.Exchange) |
|
|
|
if subTasks.Load() == 0 { |
|
|
|
|
|
|
|
cancel() |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
zlog.Infof("trade instance initial kline %s(%s), pub %d fetch tasks", inst.InstId, inst.Exchange, pubTasks.Load()) |
|
|
|
}() |
|
|
|
}() |
|
|
|
|
|
|
|
|
|
|
|
// for interval, intervalAdder := range types.SupportedIntervals {
|
|
|
|
// for interval, intervalAdder := range types.SupportedIntervals {
|
|
|
|
interval := types.Interval1h |
|
|
|
interval := types.Interval1d |
|
|
|
intervalAdder := types.SupportedIntervals[interval] |
|
|
|
intervalAdder := types.SupportedIntervals[interval] |
|
|
|
// history 未补全前, history写 kvdb ts mark, 补全后 ws live 写 ts mark
|
|
|
|
// history 未补全前, history写 kvdb ts mark, 补全后 ws live 写 ts mark
|
|
|
|
tsKey := fmt.Sprintf(HistoryKlineTsKey, inst.Exchange, inst.InstId, interval) |
|
|
|
tsKey := fmt.Sprintf(HistoryKlineTsKey, inst.Exchange, inst.InstId, interval) |
|
|
|
@ -364,6 +388,27 @@ func (svc *ExchangeGrpcServer) initTradeInstanceKlines(exchange *Exchange, inst |
|
|
|
beforeTs = intervalAdder(KlineBefore0, -1) |
|
|
|
beforeTs = intervalAdder(KlineBefore0, -1) |
|
|
|
} |
|
|
|
} |
|
|
|
for { |
|
|
|
for { |
|
|
|
|
|
|
|
// 对比 ws 获取的实时k线
|
|
|
|
|
|
|
|
exchangeInst, ok := exchange.Insts.Load(inst.ExchangeInstId) |
|
|
|
|
|
|
|
if !ok { |
|
|
|
|
|
|
|
err = fmt.Errorf("not load exchange trade instance: %s", inst.ExchangeInstId) |
|
|
|
|
|
|
|
cancel() |
|
|
|
|
|
|
|
return |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
// 订阅完成
|
|
|
|
|
|
|
|
if exchangeInst.LiveMarkTs != 0 && beforeTs >= exchangeInst.LiveMarkTs { |
|
|
|
|
|
|
|
// history status -> ok
|
|
|
|
|
|
|
|
break |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if beforeTs > time.Now().UnixMilli() { |
|
|
|
|
|
|
|
if exchangeInst.LiveMarkTs != 0 { |
|
|
|
|
|
|
|
// history status -> ok
|
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
// live status -> not ok
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
break |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
afterTs := intervalAdder(beforeTs, 101) |
|
|
|
afterTs := intervalAdder(beforeTs, 101) |
|
|
|
task := fetchKlineTask{ |
|
|
|
task := fetchKlineTask{ |
|
|
|
inst: inst, |
|
|
|
inst: inst, |
|
|
|
@ -382,25 +427,6 @@ func (svc *ExchangeGrpcServer) initTradeInstanceKlines(exchange *Exchange, inst |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
beforeTs = intervalAdder(afterTs, -1) |
|
|
|
beforeTs = intervalAdder(afterTs, -1) |
|
|
|
|
|
|
|
|
|
|
|
// 对比 ws 获取的实时k线
|
|
|
|
|
|
|
|
inst, ok := exchange.Insts.Load(inst.ExchangeInstId) |
|
|
|
|
|
|
|
if !ok { |
|
|
|
|
|
|
|
break |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
// 订阅完成
|
|
|
|
|
|
|
|
if inst.LiveMarkTs != 0 && beforeTs > inst.LiveMarkTs { |
|
|
|
|
|
|
|
// history status -> ok
|
|
|
|
|
|
|
|
break |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if beforeTs > time.Now().UnixMilli() { |
|
|
|
|
|
|
|
if inst.LiveMarkTs != 0 { |
|
|
|
|
|
|
|
// history status -> ok
|
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
// live status -> not ok
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
break |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
}() |
|
|
|
}() |
|
|
|
|
|
|
|
|
|
|
|
@ -412,23 +438,19 @@ func (svc *ExchangeGrpcServer) initTradeInstanceKlines(exchange *Exchange, inst |
|
|
|
defer wg.Done() |
|
|
|
defer wg.Done() |
|
|
|
|
|
|
|
|
|
|
|
var task fetchKlineTask |
|
|
|
var task fetchKlineTask |
|
|
|
var ok bool |
|
|
|
|
|
|
|
for { |
|
|
|
for { |
|
|
|
select { |
|
|
|
select { |
|
|
|
case <-ctx.Done(): |
|
|
|
case <-ctx.Done(): |
|
|
|
return |
|
|
|
return |
|
|
|
case task, ok = <-taskCh: |
|
|
|
case task = <-taskCh: |
|
|
|
case task, ok = <-retryTaskCh: |
|
|
|
case task = <-retryTaskCh: |
|
|
|
} |
|
|
|
|
|
|
|
if !ok { |
|
|
|
|
|
|
|
continue |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if task.times > 0 { |
|
|
|
if task.times > 0 { |
|
|
|
zlog.Infof("retry fetch history kline task %d times: task -> %s", task.times, task.logKey()) |
|
|
|
zlog.Infof("retry fetch history kline task %d times: task -> %s", task.times, task.logKey()) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if ex := svc.fetchTaskKlines(exchange, task); ex != nil { |
|
|
|
if lastKlineTs, ex := svc.fetchTaskKlines(exchange, task); ex != nil { |
|
|
|
failTasks.Add(1) |
|
|
|
failTasks.Add(1) |
|
|
|
if task.times >= SingleTaskMaxFailTimes { |
|
|
|
if task.times >= SingleTaskMaxFailTimes { |
|
|
|
err = fmt.Errorf("task failed to many times %d, key: %s, err: %v", task.times, task.logKey(), ex) |
|
|
|
err = fmt.Errorf("task failed to many times %d, key: %s, err: %v", task.times, task.logKey(), ex) |
|
|
|
@ -443,8 +465,23 @@ func (svc *ExchangeGrpcServer) initTradeInstanceKlines(exchange *Exchange, inst |
|
|
|
return |
|
|
|
return |
|
|
|
} |
|
|
|
} |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
|
|
|
|
// 周期任务最后kline时间
|
|
|
|
|
|
|
|
if lastKlineTs != 0 { |
|
|
|
|
|
|
|
historyMarkTsMu.Lock() |
|
|
|
|
|
|
|
if ts, ok := historyMarkTs[task.interval]; ok { |
|
|
|
|
|
|
|
if lastKlineTs > ts { |
|
|
|
|
|
|
|
historyMarkTs[task.interval] = lastKlineTs |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
historyMarkTs[task.interval] = lastKlineTs |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
historyMarkTsMu.Unlock() |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
zlog.Debugf("trade instance initial kline tasks processing: %s(%s), pub %d, sub %d, fail %d", inst.InstId, inst.Exchange, pubTasks.Load(), subTasks.Load(), failTasks.Load()) |
|
|
|
// 任务都已执行成功结束
|
|
|
|
// 任务都已执行成功结束
|
|
|
|
if subTasks.Add(1) >= pubTasks.Load() { |
|
|
|
subs := subTasks.Add(1) |
|
|
|
|
|
|
|
if pubTaskDone.Load() && subs >= pubTasks.Load() { |
|
|
|
zlog.Infof("trade instance initial kline tasks success finished, %s(%s), pub %d, sub %d, fail %d", inst.InstId, inst.Exchange, pubTasks.Load(), subTasks.Load(), failTasks.Load()) |
|
|
|
zlog.Infof("trade instance initial kline tasks success finished, %s(%s), pub %d, sub %d, fail %d", inst.InstId, inst.Exchange, pubTasks.Load(), subTasks.Load(), failTasks.Load()) |
|
|
|
cancel() |
|
|
|
cancel() |
|
|
|
return |
|
|
|
return |
|
|
|
@ -457,7 +494,7 @@ func (svc *ExchangeGrpcServer) initTradeInstanceKlines(exchange *Exchange, inst |
|
|
|
return |
|
|
|
return |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func (svc *ExchangeGrpcServer) fetchTaskKlines(exchange *Exchange, task fetchKlineTask) (err error) { |
|
|
|
func (svc *ExchangeGrpcServer) fetchTaskKlines(exchange *Exchange, task fetchKlineTask) (lastKlineTs int64, err error) { |
|
|
|
interval, afterTs, beforeTs := task.interval, task.afterTs, task.beforeTs |
|
|
|
interval, afterTs, beforeTs := task.interval, task.afterTs, task.beforeTs |
|
|
|
klines, err := exchange.Fetcher.FetchHistoryKlines(context.Background(), task.inst.ExchangeInstId, interval, afterTs, beforeTs) |
|
|
|
klines, err := exchange.Fetcher.FetchHistoryKlines(context.Background(), task.inst.ExchangeInstId, interval, afterTs, beforeTs) |
|
|
|
if err != nil { |
|
|
|
if err != nil { |
|
|
|
@ -471,9 +508,10 @@ func (svc *ExchangeGrpcServer) fetchTaskKlines(exchange *Exchange, task fetchKli |
|
|
|
loc, _ := time.LoadLocation("Asia/Shanghai") |
|
|
|
loc, _ := time.LoadLocation("Asia/Shanghai") |
|
|
|
|
|
|
|
|
|
|
|
sts, ets := klines[0].Ts, klines[len(klines)-1].Ts |
|
|
|
sts, ets := klines[0].Ts, klines[len(klines)-1].Ts |
|
|
|
|
|
|
|
lastKlineTs = max(sts, ets) |
|
|
|
ss := time.UnixMilli(sts).In(loc).Format(times.FORMAT_DATE) |
|
|
|
ss := time.UnixMilli(sts).In(loc).Format(times.FORMAT_DATE) |
|
|
|
ee := time.UnixMilli(ets).In(loc).Format(times.FORMAT_DATE) |
|
|
|
ee := time.UnixMilli(ets).In(loc).Format(times.FORMAT_DATE) |
|
|
|
zlog.Infof("fetch interval %s %d~%d klines: ret=%d~%d, %d klines, %s~%s", interval, afterTs, beforeTs, sts, ets, len(klines), ss, ee) |
|
|
|
zlog.Infof("fetch interval %s %d~%d klines: ret=%d~%d, %d klines, %s~%s", interval, beforeTs, afterTs, ets, sts, len(klines), ee, ss) |
|
|
|
|
|
|
|
|
|
|
|
// store to tsdb
|
|
|
|
// store to tsdb
|
|
|
|
err = svc.exchangeDataService.SaveKlines(task.inst, klines) |
|
|
|
err = svc.exchangeDataService.SaveKlines(task.inst, klines) |
|
|
|
|