@ -12,6 +12,7 @@ import (
"sig-pub/pkg/types"
"sig-pub/pkg/utils/collect"
"sig-pub/pkg/utils/conver"
"sig-pub/pkg/utils/retry"
"sig-pub/pkg/utils/times"
"sig-pub/pkg/zlog"
"sync"
@ -142,10 +143,7 @@ func (svc *ExchangeService) consumerKline(exchange *Exchange, c <-chan *types.Ch
if len ( channelK . Klines ) == 0 {
continue
}
// 排序后取出头尾k线
collect . SortAsc ( channelK . Klines , func ( k * types . Kline ) int64 { return k . Ts } )
firstKline , lastKline := channelK . Klines [ 0 ] , channelK . Klines [ len ( channelK . Klines ) - 1 ]
receivedTs := time . Now ( ) . UnixMilli ( )
// 交易所 instid 转 sig-instid
var tradeInst * types . TradeInstance
exchangeInst , ok := exchange . ExchangeInsts . Load ( channelK . ExgInstId )
@ -155,15 +153,47 @@ func (svc *ExchangeService) consumerKline(exchange *Exchange, c <-chan *types.Ch
}
tradeInst = exchangeInst . Inst
// 升序排序
collect . SortAsc ( channelK . Klines , func ( k * types . Kline ) int64 { return k . Ts } )
// 检查已确认k线是否连续并补齐
for _ , kline := range channelK . Klines {
if kline . Confirm {
if kms , ok := kline . Interval . AddMul ( kline . Ts , 1 ) ; ok {
delay := time . Now ( ) . UnixMilli ( ) - kms
zlog . Debugf ( "recv confirm kline: delay=%dms, inst=%s(%s), interval=%s" , delay , channelK . ExgInstId , channelK . Exchange , kline . Interval )
if lastConfirmK := exchangeInst . LastKline . Get ( kline . Interval ) ; lastConfirmK . Ts != 0 {
if expectTs , ok := lastConfirmK . Interval . AddMul ( lastConfirmK . Ts , 1 ) ; ok && expectTs != kline . Ts {
zlog . Warningf ( "fetching padding klines: inst=%s(%s), interval=%s, ts=%d~%d" , tradeInst . InstId , tradeInst . Exchange , kline . Interval , kline . Ts , lastConfirmK . Ts )
if err := svc . initialTradeInstanceKlines ( exchange , * tradeInst ) ; err != nil {
zlog . Errorf ( "fetch padding kline error: inst=%s(%s), interval=%s, ts=%d~%d, error=%v" , tradeInst . InstId , tradeInst . Exchange , kline . Interval , kline . Ts , lastConfirmK . Ts , err )
}
// zlog.Warningf("fetching padding klines: inst=%s(%s), interval=%s, ts=%d~%d", tradeInst.InstId, tradeInst.Exchange, kline.Interval, kline.Ts, lastConfirmK.Ts)
// paddingKlines, err := exchange.Fetcher.FetchHistoryKlines(context.Background(), tradeInst.ExchangeInstId, kline.Interval, kline.Ts, lastConfirmK.Ts)
// if err != nil {
// zlog.Errorf("fetch padding kline error: inst=%s(%s), interval=%s, ts=%d~%d, error=%v", tradeInst.InstId, tradeInst.Exchange, kline.Interval, kline.Ts, lastConfirmK.Ts, err)
// } else {
// zlog.Debugf("fetched padding klines: inst=%s(%s), interval=%s, ts=%d~%d, %#v", tradeInst.InstId, tradeInst.Exchange, kline.Interval, kline.Ts, lastConfirmK.Ts, paddingKlines)
// channelK.Klines = append(paddingKlines, channelK.Klines...)
// collect.SortAsc(channelK.Klines, func(k *types.Kline) int64 { return k.Ts })
// }
}
}
}
break
}
}
// 取出头尾k线
lastKline := channelK . Klines [ len ( channelK . Klines ) - 1 ]
// 标记交易产品开始订阅k线时间
exchangeInst . LiveKStartTs . SetIf ( firstKline . Interval , firstKline . Ts , func ( old int64 ) bool { return old == 0 } )
// exchangeInst.LiveKStartTs.SetIf(lastKline.Interval, lastKline.Ts, func(old int64) bool { return old == 0 })
// 记录实时k线
exchangeInst . LiveKline . Set ( lastKline . Interval , * lastKline )
// 记录最后确认k线
if lastKline . Confirm {
exchangeInst . LastKline . Set ( lastKline . Interval , * lastKline )
}
// 记录实时价格
exchangeInst . Last = lastKline . Close
@ -172,6 +202,8 @@ func (svc *ExchangeService) consumerKline(exchange *Exchange, c <-chan *types.Ch
// zlog.Infof("recv kline: %#v", kline)
confirm := 0
if kline . Confirm {
// 记录最后确认k线
exchangeInst . LastKline . Set ( kline . Interval , * kline )
confirm = 1
confirmKlines = append ( confirmKlines , kline )
}
@ -188,7 +220,7 @@ func (svc *ExchangeService) consumerKline(exchange *Exchange, c <-chan *types.Ch
}
// 存储到 tsdb
if _ , ok := types . SupportedIntervals [ fir stKline. Interval ] ; ok && len ( confirmKlines ) > 0 {
if _ , ok := types . SupportedIntervals [ la stKline. Interval ] ; ok && len ( confirmKlines ) > 0 {
// tsdb storage todo 异步处理
err := svc . exchangeDataPersist . SaveKline ( * tradeInst , confirmKlines )
// zlog.Infof("save confirm klines: instId=%s(%s), interval=%s, ts=%d", tradeInst.InstId, tradeInst.Exchange, firstKline.Interval, firstKline.Ts)
@ -221,6 +253,10 @@ func (svc *ExchangeService) consumerKline(exchange *Exchange, c <-chan *types.Ch
}
}
}
if useMs := time . Now ( ) . UnixMilli ( ) - receivedTs ; useMs > 10 {
zlog . Debugf ( "handle consume kline use: %dms" , useMs )
}
}
}
@ -304,7 +340,15 @@ func (svc *ExchangeService) initialTradeInstanceKlines(exchange *Exchange, trade
}
} )
exchangeInst . Status . Store ( int32 ( data . StatusOk ) )
zlog . Infof ( "initial history kline finish: instId=%s(%s), pub=%d, sub=%d, fail=%d, use %s" , tradeInst . InstId , tradeInst . Exchange , pubTasks . Load ( ) , subTasks . Load ( ) , failTimes . Load ( ) , conver . TimeMilliFormat ( time . Now ( ) . UnixMilli ( ) - startTs , "/" ) )
zlog . Infof ( "initial history kline finish: instId=%s(%s), pub=%d, sub=%d, fail=%d, use %s" , tradeInst . InstId , tradeInst . Exchange , pubTasks . Load ( ) , subTasks . Load ( ) , failTimes . Load ( ) , conver . TimeMilliFormat ( time . Now ( ) . UnixMilli ( ) - startTs , "." ) )
// flush vmtsdb to disk
retry . DoWithFixDelay ( 5 , time . Second , func ( retryTimes uint32 ) ( _ struct { } , err error ) {
if err = svc . exchangeDataPersist . vmtsdb . ForceFlush ( ) ; err != nil {
zlog . Errorf ( "flush vmts db error: " , err )
}
return
} )
} ( )
// progress monitor
@ -345,15 +389,21 @@ func (svc *ExchangeService) initialTradeInstanceKlines(exchange *Exchange, trade
}
if beforeTs == 0 {
beforeTs = intervalAdder ( KlineBefore0 , - 1 )
} else {
// 不足100根,向前补齐100根一次拉取过来
total := ( time . Now ( ) . UnixMilli ( ) - beforeTs ) / intervalAdder ( 0 , 1 )
if total < 100 {
beforeTs = max ( intervalAdder ( beforeTs , - 100 ) , KlineBefore0 )
}
}
exchangeInst . HistoryMarkTs . Set ( interval , beforeTs )
for {
// 判定订阅任务发布完成
liveStartTs := exchangeInst . LiveKStartTs . Get ( interval )
if liveStartTs != 0 && beforeTs >= liveStartTs {
break
}
// liveStartTs := exchangeInst.LiveKStartTs.Get(interval)
// if liveStartTs != 0 && beforeTs >= liveStartTs {
// break
// }
if beforeTs > time . Now ( ) . UnixMilli ( ) {
break
}
@ -478,14 +528,14 @@ func (svc *ExchangeService) Exchanges() (exchanges []pb.ExchangeType, err error)
}
// ExchangeInstanceState 交易所交易产品状态
func ( svc * ExchangeService ) ExchangeInstanceState ( allExchange bool , exchangeTypes [ ] pb . ExchangeType , instIds [ ] string ) ( states [ ] * pb . TradeInstanceState , err error ) {
func ( svc * ExchangeService ) ExchangeInstanceState ( req * pb . ReqExchangeInstanceState ) ( states [ ] * pb . TradeInstanceState , err error ) {
var exchanges [ ] * Exchange
if a llExchange {
if req . A llExchange {
svc . exchanges . Range ( func ( _ pb . ExchangeType , exchange * Exchange ) {
exchanges = append ( exchanges , exchange )
} )
} else {
for _ , exchangeType := range exchangeTyp es {
for _ , exchangeType := range r eq . E xchanges {
if ! svc . exchanges . IsSupport ( exchangeType ) {
err = fmt . Errorf ( "not support exchange: %v" , exchangeType )
return
@ -499,20 +549,34 @@ func (svc *ExchangeService) ExchangeInstanceState(allExchange bool, exchangeType
}
for _ , exchange := range exchanges {
for _ , instId := range instIds {
// trade instId to exchangeInstId
exchangeInstId , ok := exchange . TradeInstIds . Load ( instId )
if ! ok {
continue
}
exchangeInst , ok := exchange . ExchangeInsts . Load ( exchangeInstId )
if ! ok {
continue
insts := make ( [ ] * ExchangeTradeInstance , 0 , 8 )
if req . AllInsts {
exchange . ExchangeInsts . Range ( func ( _ string , inst * ExchangeTradeInstance ) bool {
if req . AllStatus || collect . In ( inst . Status . Load ( ) , req . Status ... ) {
insts = append ( insts , inst )
}
return true
} )
} else {
for _ , instId := range req . Insts {
// trade instId 转 exchangeInstId
exchangeInstId , ok := exchange . TradeInstIds . Load ( instId )
if ! ok {
continue
}
inst , ok := exchange . ExchangeInsts . Load ( exchangeInstId )
if ! ok {
continue
}
if req . AllStatus || collect . In ( inst . Status . Load ( ) , req . Status ... ) {
insts = append ( insts , inst )
}
}
}
for _ , exchangeInst := range insts {
state := & pb . TradeInstanceState {
Exchange : exchange . ExchangeType ,
InstId : instId ,
InstId : exchangeInst . Inst . I nstId,
Status : exchangeInst . Status . Load ( ) ,
Last : exchangeInst . Last . String ( ) ,
}
@ -522,6 +586,10 @@ func (svc *ExchangeService) ExchangeInstanceState(allExchange bool, exchangeType
return
}
const (
MaxHistoryKlines = 100
)
// HistoryKline 获取交易产品历史k线 (before < klines... < after)
func ( svc * ExchangeService ) HistoryKline ( ctx context . Context , req * pb . ReqHistoryKline , rsp * pb . RspHistoryKline ) ( klines [ ] * types . Kline , err error ) {
// 交易产品参数检查
@ -548,59 +616,56 @@ func (svc *ExchangeService) HistoryKline(ctx context.Context, req *pb.ReqHistory
// k线长度检查
afterTs , beforeTs , count := int64 ( req . After ) , int64 ( req . Before ) , int64 ( req . Count )
if count == 0 {
count = 100
count = MaxHistoryKlines
}
nowTime := time . Now ( ) . UnixMilli ( )
if afterTs == 0 && beforeTs == 0 {
// 拉取最新的
// 拉取最新的
lastTs := int64 ( 0 )
if afterTs == 0 {
liveK := exchangeInst . LiveKline . Get ( interval )
lastTs : = liveK . Ts
lastTs = liveK . Ts
if ! liveK . Confirm {
lastTs = intervalAdder ( liveK . Ts , - 1 )
}
if ! req . Asc {
afterTs = lastTs
} else {
// 从低到高拉取
beforeTs = max ( intervalAdder ( lastTs , - count + 1 ) , KlineBefore0 )
}
}
if afterTs == 0 && beforeTs == 0 {
afterTs = lastTs
}
if afterTs == 0 {
afterTs = min ( intervalAdder ( beforeTs , count ) , nowTime )
afterTs = min ( intervalAdder ( beforeTs , count - 1 ) , lastTs )
}
if beforeTs == 0 {
beforeTs = max ( intervalAdder ( afterTs , - count ) , KlineBefore0 )
beforeTs = max ( intervalAdder ( afterTs , - count + 1 ) , KlineBefore0 )
}
if beforeTs > afterTs {
err = fmt . Errorf ( "time range invalid: before must less then after" )
return
}
// 限制最大时间范围
total := ( afterTs - beforeTs ) / intervalAdder ( 0 , 1 )
if total > 100 {
// err = fmt.Errorf("time range too large max 100")
if req . Asc {
afterTs = min ( intervalAdder ( beforeTs , 100 ) , nowTime )
} else {
beforeTs = max ( intervalAdder ( afterTs , - 100 ) , KlineBefore0 )
}
rsp . Next = true
total := ( afterTs - beforeTs ) / intervalAdder ( 0 , 1 ) + 1
if total > MaxHistoryKlines {
err = fmt . Errorf ( "time range too large max %d" , MaxHistoryKlines )
return
}
klines , err = svc . exchangeDataPersist . ListKline ( * exchangeInst . Inst , interval , beforeTs , afterTs )
if err != nil || len ( klines ) == 0 {
rsp . Next = false
if err != nil {
zlog . Error ( "list vmtsdb kline error: " , err )
return
}
if len ( klines ) < int ( count ) {
rsp . Next = false
if len ( klines ) == 0 {
return
}
lastK := klines [ len ( klines ) - 1 ]
lastK := klines [ len ( klines ) - 1 ]
// vmtsdb 数据刷盘30s延迟, 使用内存数据替代第一根k线
if lastConfirmK := exchangeInst . LastKline . Get ( interval ) ; lastConfirmK . Ts == lastK . Ts {
klines [ len ( klines ) - 1 ] = & lastConfirmK
lastConfirmK := exchangeInst . LastKline . Get ( interval )
if lastConfirmK . Ts == lastK . Ts {
lastK = & lastConfirmK
klines [ len ( klines ) - 1 ] = lastK
}
if lastConfirmK . Ts == afterTs && intervalAdder ( lastK . Ts , 1 ) == afterTs {
lastK = & lastConfirmK
klines = append ( klines , & lastConfirmK )
}
// 降序排序
@ -624,7 +689,7 @@ func (svc *ExchangeService) HistoryKline(ctx context.Context, req *pb.ReqHistory
}
// 查询历史k线(流式返回)
func ( svc * ExchangeService ) HistoryKlineStream ( req * pb . ReqHistoryKline , stream grpc . ServerStreamingServer [ pb . RspHistoryKlineStream ] ) ( err error ) {
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 )
@ -674,34 +739,39 @@ func (svc *ExchangeService) HistoryKlineStream(req *pb.ReqHistoryKline, stream g
return
}
branch := 100
curBeforeTs , curAfterTs := beforeTs , intervalAdder ( beforeTs , int64 ( branch ) - 1 )
for i := 0 ; curAfterTs <= afterTs ; i ++ {
if i > 0 {
curBeforeTs = intervalAdder ( curAfterTs , 1 )
curAfterTs = min ( intervalAdder ( curBeforeTs , int64 ( branch ) - 1 ) , afterTs )
}
klines , err := svc . exchangeDataPersist . ListKline ( * exchangeInst . Inst , interval , beforeTs , afterTs )
if err != nil {
zlog . Error ( "fetch history kline stream error: " , err )
return
}
if len ( klines ) == 0 {
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 )
}
klines , kerr := svc . exchangeDataPersist . ListKline ( * exchangeInst . Inst , interval , curBeforeTs , curAfterTs )
if kerr != nil {
err = kerr
return
}
if len ( klines ) == 0 {
break
branch := 100
length := len ( klines )
kBuffer := make ( [ ] * pb . Kline , 0 , branch )
for i , kline := range klines {
kBuffer = append ( kBuffer , kline . ToPBKline ( ) )
if len ( kBuffer ) < branch && i < length - 1 {
continue
}
resp := new ( pb . RspHistoryKlineStream )
resp . Klines = collect . Mapping ( klines , func ( _ int , k * types . Kline ) * pb . Kline { return k . ToPBKline ( ) } )
// 是否还有更多
resp . Next = len ( klines ) == int ( count )
if sendErr := stream . Send ( resp ) ; sendErr != nil {
rsp := & pb . RspHistoryKlineStream { Klines : kBuffer }
if sendErr := stream . Send ( rsp ) ; sendErr != nil {
err = sendErr
return
}
if ! resp . Next {
break
}
kBuffer = kBuffer [ : 0 ]
}
return
}