|
|
|
@ -6,6 +6,7 @@ import ( |
|
|
|
"io" |
|
|
|
"io" |
|
|
|
"math" |
|
|
|
"math" |
|
|
|
"sig-pub/api/pb" |
|
|
|
"sig-pub/api/pb" |
|
|
|
|
|
|
|
"sig-pub/internal/trading/sig" |
|
|
|
"sig-pub/pkg/data" |
|
|
|
"sig-pub/pkg/data" |
|
|
|
"sig-pub/pkg/mq" |
|
|
|
"sig-pub/pkg/mq" |
|
|
|
"sig-pub/pkg/strategy" |
|
|
|
"sig-pub/pkg/strategy" |
|
|
|
@ -18,20 +19,20 @@ import ( |
|
|
|
"google.golang.org/grpc" |
|
|
|
"google.golang.org/grpc" |
|
|
|
) |
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
type KlineStore struct { |
|
|
|
type KlineSeriesStore struct { |
|
|
|
exchangeClient pb.ExchangeServiceClient |
|
|
|
exchangeClient pb.ExchangeServiceClient |
|
|
|
|
|
|
|
|
|
|
|
store *types.ExchangeState[*collect.ConcurrentMap[string, *TradeInstanceKlineSeries]] // K线列表: []exchange<instId, interval, klines>
|
|
|
|
store *types.ExchangeState[*collect.ConcurrentMap[string, *sig.TradeInstanceKlineSeries]] // K线列表: []exchange<instId, interval, klines>
|
|
|
|
subKlineIntervals []string // 订阅的k线的周期列表
|
|
|
|
subKlineIntervals []string // 订阅的k线的周期列表
|
|
|
|
subKlineInsts *types.ExchangeState[*collect.SyncMap[string, bool]] // 订阅k线中的交易产品列表
|
|
|
|
subKlineInsts *types.ExchangeState[*collect.SyncMap[string, bool]] // 订阅k线中的交易产品列表
|
|
|
|
subKlineStream grpc.BidiStreamingClient[pb.ReqStreamSubscribeKline, pb.RspStreamSubscribeKline] // 订阅k线的stream
|
|
|
|
subKlineStream grpc.BidiStreamingClient[pb.ReqStreamSubscribeKline, pb.RspStreamSubscribeKline] // 订阅k线的stream
|
|
|
|
klineSignalChan chan string |
|
|
|
klineSignalChan chan string |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func NewKlineSeriesStore(exchangeClient pb.ExchangeServiceClient) (kss *KlineStore) { |
|
|
|
func NewKlineSeriesStore(exchangeClient pb.ExchangeServiceClient) (kss *KlineSeriesStore) { |
|
|
|
kss = &KlineStore{ |
|
|
|
kss = &KlineSeriesStore{ |
|
|
|
exchangeClient: exchangeClient, |
|
|
|
exchangeClient: exchangeClient, |
|
|
|
klineSignalChan: make(chan string, 128), |
|
|
|
klineSignalChan: make(chan string, 1024), |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 周期列表
|
|
|
|
// 周期列表
|
|
|
|
@ -43,15 +44,15 @@ func NewKlineSeriesStore(exchangeClient pb.ExchangeServiceClient) (kss *KlineSto |
|
|
|
return collect.NewSyncMap[string, bool]() |
|
|
|
return collect.NewSyncMap[string, bool]() |
|
|
|
}) |
|
|
|
}) |
|
|
|
// 各交易所 store 初始化
|
|
|
|
// 各交易所 store 初始化
|
|
|
|
kss.store = types.NewExchangeStateInit(func() *collect.ConcurrentMap[string, *TradeInstanceKlineSeries] { |
|
|
|
kss.store = types.NewExchangeStateInit(func() *collect.ConcurrentMap[string, *sig.TradeInstanceKlineSeries] { |
|
|
|
return collect.NewConcurrentMap[string, *TradeInstanceKlineSeries](64, func(s string) string { |
|
|
|
return collect.NewConcurrentMap[string, *sig.TradeInstanceKlineSeries](64, func(s string) string { |
|
|
|
return s |
|
|
|
return s |
|
|
|
}) |
|
|
|
}) |
|
|
|
}) |
|
|
|
}) |
|
|
|
return |
|
|
|
return |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func (s *KlineStore) Init() (err error) { |
|
|
|
func (s *KlineSeriesStore) Init() (err error) { |
|
|
|
// 连接 exchange kline stream
|
|
|
|
// 连接 exchange kline stream
|
|
|
|
go s.connectSubscribeKline(false) |
|
|
|
go s.connectSubscribeKline(false) |
|
|
|
|
|
|
|
|
|
|
|
@ -85,7 +86,7 @@ func (s *KlineStore) Init() (err error) { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// connectSubscribeKline 连接exchange订阅实时k线
|
|
|
|
// connectSubscribeKline 连接exchange订阅实时k线
|
|
|
|
func (s *KlineStore) connectSubscribeKline(reconnect bool) { |
|
|
|
func (s *KlineSeriesStore) connectSubscribeKline(reconnect bool) { |
|
|
|
defer func() { |
|
|
|
defer func() { |
|
|
|
if s.subKlineStream != nil { |
|
|
|
if s.subKlineStream != nil { |
|
|
|
s.subKlineStream.CloseSend() |
|
|
|
s.subKlineStream.CloseSend() |
|
|
|
@ -145,7 +146,7 @@ func (s *KlineStore) connectSubscribeKline(reconnect bool) { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// subscribeKline 发送订阅消息
|
|
|
|
// subscribeKline 发送订阅消息
|
|
|
|
func (s *KlineStore) sendSubscribeKline(save bool, exchange pb.ExchangeType, instIds ...string) { |
|
|
|
func (s *KlineSeriesStore) sendSubscribeKline(save bool, exchange pb.ExchangeType, instIds ...string) { |
|
|
|
if len(instIds) == 0 { |
|
|
|
if len(instIds) == 0 { |
|
|
|
return |
|
|
|
return |
|
|
|
} |
|
|
|
} |
|
|
|
@ -182,13 +183,13 @@ func (s *KlineStore) sendSubscribeKline(save bool, exchange pb.ExchangeType, ins |
|
|
|
go retry.DoWithFixDelay(math.MaxInt32, time.Second, doSend) |
|
|
|
go retry.DoWithFixDelay(math.MaxInt32, time.Second, doSend) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func (s *KlineStore) inititalKlineSeries(exchange pb.ExchangeType, instId string) { |
|
|
|
func (s *KlineSeriesStore) inititalKlineSeries(exchange pb.ExchangeType, instId string) { |
|
|
|
if !s.store.IsSupport(exchange) { |
|
|
|
if !s.store.IsSupport(exchange) { |
|
|
|
zlog.Errorf("unsupport exchange %s", exchange) |
|
|
|
zlog.Errorf("unsupport exchange %s", exchange) |
|
|
|
return |
|
|
|
return |
|
|
|
} |
|
|
|
} |
|
|
|
storeInst := s.store.Get(exchange).ComputeIfAbsent(instId, func(k string) *TradeInstanceKlineSeries { |
|
|
|
storeInst := s.store.Get(exchange).ComputeIfAbsent(instId, func(k string) *sig.TradeInstanceKlineSeries { |
|
|
|
return NewTradeInstanceKlineSeries(exchange, k) |
|
|
|
return sig.NewTradeInstanceKlineSeries(exchange, k) |
|
|
|
}) |
|
|
|
}) |
|
|
|
// 交易产品已初始化过
|
|
|
|
// 交易产品已初始化过
|
|
|
|
if !storeInst.Status.CompareAndSwap(int32(data.StatusNone), int32(data.StatusProcessing)) { |
|
|
|
if !storeInst.Status.CompareAndSwap(int32(data.StatusNone), int32(data.StatusProcessing)) { |
|
|
|
@ -199,7 +200,7 @@ func (s *KlineStore) inititalKlineSeries(exchange pb.ExchangeType, instId string |
|
|
|
// 初始化最新的 klineSeries
|
|
|
|
// 初始化最新的 klineSeries
|
|
|
|
for _, interval := range s.subKlineIntervals { |
|
|
|
for _, interval := range s.subKlineIntervals { |
|
|
|
retry.DoWithFixDelay(math.MaxInt32, 2*time.Second, func(retryTimes uint32) (_ struct{}, err error) { |
|
|
|
retry.DoWithFixDelay(math.MaxInt32, 2*time.Second, func(retryTimes uint32) (_ struct{}, err error) { |
|
|
|
_, err = s.fetchHistoryKlineToSeries(exchange, instId, interval, 0, 0, MaxSeriesKlines) |
|
|
|
_, err = s.fetchHistoryKlineToSeries(exchange, instId, interval, 0, 0, sig.MaxSeriesKlines) |
|
|
|
return |
|
|
|
return |
|
|
|
}) |
|
|
|
}) |
|
|
|
} |
|
|
|
} |
|
|
|
@ -210,7 +211,7 @@ func (s *KlineStore) inititalKlineSeries(exchange pb.ExchangeType, instId string |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// fetchHistoryKlineToSeries 拉去历史k线数据更新series
|
|
|
|
// fetchHistoryKlineToSeries 拉去历史k线数据更新series
|
|
|
|
func (s *KlineStore) fetchHistoryKlineToSeries(exchange pb.ExchangeType, instId, interval string, before, after int64, count uint32) (total int, err error) { |
|
|
|
func (s *KlineSeriesStore) fetchHistoryKlineToSeries(exchange pb.ExchangeType, instId, interval string, before, after int64, count uint32) (total int, err error) { |
|
|
|
// 拉取最新的1000条k线
|
|
|
|
// 拉取最新的1000条k线
|
|
|
|
req := &pb.ReqHistoryKlineStream{ |
|
|
|
req := &pb.ReqHistoryKlineStream{ |
|
|
|
Series: &pb.SeriesRange{ |
|
|
|
Series: &pb.SeriesRange{ |
|
|
|
@ -253,13 +254,13 @@ func (s *KlineStore) fetchHistoryKlineToSeries(exchange pb.ExchangeType, instId, |
|
|
|
return |
|
|
|
return |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func (s *KlineStore) ConsumerKlineSignel() <-chan string { |
|
|
|
func (s *KlineSeriesStore) ConsumerKlineSignel() <-chan string { |
|
|
|
return s.klineSignalChan |
|
|
|
return s.klineSignalChan |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Update
|
|
|
|
// Update
|
|
|
|
// kline klineStore -> klineSeries -> strategy -> indicator -> klineSeries.Series
|
|
|
|
// kline klineStore -> klineSeries -> strategy -> indicator -> klineSeries.Series
|
|
|
|
func (s *KlineStore) Update(exchange pb.ExchangeType, instId string, kline *types.Kline) { |
|
|
|
func (s *KlineSeriesStore) Update(exchange pb.ExchangeType, instId string, kline *types.Kline) { |
|
|
|
if _, ok := types.SupportedIntervals[kline.Interval]; !ok { |
|
|
|
if _, ok := types.SupportedIntervals[kline.Interval]; !ok { |
|
|
|
zlog.Warningf("unsupport interval: %s", kline.Interval) |
|
|
|
zlog.Warningf("unsupport interval: %s", kline.Interval) |
|
|
|
return |
|
|
|
return |
|
|
|
@ -269,8 +270,8 @@ func (s *KlineStore) Update(exchange pb.ExchangeType, instId string, kline *type |
|
|
|
return |
|
|
|
return |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
instSeries := s.store.Get(exchange).ComputeIfAbsent(instId, func(k string) *TradeInstanceKlineSeries { |
|
|
|
instSeries := s.store.Get(exchange).ComputeIfAbsent(instId, func(k string) *sig.TradeInstanceKlineSeries { |
|
|
|
return NewTradeInstanceKlineSeries(exchange, k) |
|
|
|
return sig.NewTradeInstanceKlineSeries(exchange, k) |
|
|
|
}) |
|
|
|
}) |
|
|
|
|
|
|
|
|
|
|
|
before, serial := instSeries.IntervalKlines.Get(kline.Interval).Update(kline) |
|
|
|
before, serial := instSeries.IntervalKlines.Get(kline.Interval).Update(kline) |
|
|
|
@ -303,27 +304,55 @@ func (s *KlineStore) Update(exchange pb.ExchangeType, instId string, kline *type |
|
|
|
return |
|
|
|
return |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
// 判断同一时刻k线
|
|
|
|
|
|
|
|
|
|
|
|
// 判断同一时刻其它k线
|
|
|
|
var intervals []types.Interval |
|
|
|
var intervals []types.Interval |
|
|
|
endTs := kline.Interval.MustAddMul(kline.Ts, 1) |
|
|
|
currentTs := kline.Interval.MustAddMul(kline.Ts, 1) |
|
|
|
instSeries.IntervalKlines.Range(func(interval types.Interval, v *KlineSeries) { |
|
|
|
completed := true |
|
|
|
if endTs == interval.MustAddMul(v.LastTs(), 1) { |
|
|
|
instSeries.IntervalKlines.Range(func(interval types.Interval, v *sig.KlineSeries) { |
|
|
|
|
|
|
|
lastTs := v.LastTs() |
|
|
|
|
|
|
|
if currentTs == interval.MustAddMul(lastTs, 1) { |
|
|
|
intervals = append(intervals, interval) |
|
|
|
intervals = append(intervals, interval) |
|
|
|
|
|
|
|
} else if completed { |
|
|
|
|
|
|
|
// 同一时刻其它k线是否未接收完成
|
|
|
|
|
|
|
|
for i := range int64(100) { |
|
|
|
|
|
|
|
nextTs := interval.MustAddMul(lastTs, i+2) |
|
|
|
|
|
|
|
if currentTs == nextTs { |
|
|
|
|
|
|
|
completed = false |
|
|
|
|
|
|
|
} else if nextTs > currentTs { |
|
|
|
|
|
|
|
break |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
}) |
|
|
|
}) |
|
|
|
// zlog.Debugf("confirm kline intervals: instId=%s(%s), interval=%s, ts=%d, %v", instId, exchange, kline.Interval, kline.Ts, intervals)
|
|
|
|
zlog.Debugf("confirm kline intervals: instId=%s(%s), interval=%s, ts=%d, competed=%v, intervals=%v", instId, exchange, kline.Interval, kline.Ts, completed, intervals) |
|
|
|
|
|
|
|
|
|
|
|
// publish kline update signal
|
|
|
|
// publish kline update signal
|
|
|
|
pubKey := strategy.DriverIntervalKey(instId, intervals, exchange) |
|
|
|
pubKeys := []string{ |
|
|
|
select { |
|
|
|
strategy.DriverIntervalKey(instId, exchange, false, kline.Interval), |
|
|
|
case s.klineSignalChan <- pubKey: |
|
|
|
} |
|
|
|
default: |
|
|
|
if completed { |
|
|
|
zlog.Warningf("publish kline update signal fail: instId=%s(%s), interval=%s, ts=%d, %v", instId, exchange, kline.Interval, kline.Ts, intervals) |
|
|
|
for _, interval := range intervals { |
|
|
|
|
|
|
|
k := strategy.DriverIntervalKey(instId, exchange, true, interval) |
|
|
|
|
|
|
|
pubKeys = append(pubKeys, k) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
// if len(intervals) > 1 {
|
|
|
|
|
|
|
|
// k := strategy.DriverIntervalKey(instId, exchange, false, intervals...)
|
|
|
|
|
|
|
|
// pubKeys = append(pubKeys, k)
|
|
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for _, pubKey := range pubKeys { |
|
|
|
|
|
|
|
select { |
|
|
|
|
|
|
|
case s.klineSignalChan <- pubKey: |
|
|
|
|
|
|
|
default: |
|
|
|
|
|
|
|
zlog.Warningf("publish kline update signal fail: instId=%s(%s), interval=%s, ts=%d, %v", instId, exchange, kline.Interval, kline.Ts, intervals) |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// GetKlineSeires 获取k线序列
|
|
|
|
// GetKlineSeires 获取k线序列
|
|
|
|
func (s *KlineStore) GetKlineSeires(exchange pb.ExchangeType, instId string, interval types.Interval) (klineSeries *KlineSeries, err error) { |
|
|
|
func (s *KlineSeriesStore) GetKlineSeires(exchange pb.ExchangeType, instId string, interval types.Interval) (klineSeries *sig.KlineSeries, err error) { |
|
|
|
if _, ok := types.SupportedIntervals[interval]; !ok { |
|
|
|
if _, ok := types.SupportedIntervals[interval]; !ok { |
|
|
|
err = fmt.Errorf("unsupport interval: %s", interval) |
|
|
|
err = fmt.Errorf("unsupport interval: %s", interval) |
|
|
|
return |
|
|
|
return |