package trading import ( "context" "io" "sig-pub/api/pb" "sig-pub/pkg/client" "sig-pub/pkg/types" "sig-pub/pkg/utils/collect" "sig-pub/pkg/zlog" "time" "google.golang.org/grpc" ) type TradingService struct { marketClientAside *client.TradeInstanceAside exchangeClient pb.ExchangeServiceClient klineStore *KlineStore subscribeKlineIntervals []string subKlineInsts [3][]string subKlineStream grpc.BidiStreamingClient[pb.ReqStreamSubscribeKline, pb.RspStreamSubscribeKline] } func NewTradingService( marketClientAside *client.TradeInstanceAside, exchangeClient pb.ExchangeServiceClient, ) *TradingService { // 订阅实时k线周期列表 subscribeKlineIntervals := collect.Map2Slice(types.SupportedIntervals, func(interval types.Interval, _ types.IntervalAdder) string { return string(interval) }) return &TradingService{ marketClientAside: marketClientAside, exchangeClient: exchangeClient, klineStore: NewKlineSeriesStore(exchangeClient), subscribeKlineIntervals: subscribeKlineIntervals, } } // 初始化历史k线, 订阅实时k线 func (svr *TradingService) Init() (err error) { if err = svr.klineStore.Init(); err != nil { return } // get instance exchangeTradeInsts, err := svr.marketClientAside.ListExchangeTradeInstance(context.Background(), pb.ExchangeType_OKX) if err != nil { return } for _, exInst := range exchangeTradeInsts { svr.subKlineInsts[exInst.Exchange] = append(svr.subKlineInsts[exInst.Exchange], exInst.InstId) } // 订阅k线 go svr.subscribeStreamKlines(false) return } func (svr *TradingService) subscribeStreamKlines(reconnect bool) { defer func() { if svr.subKlineStream != nil { svr.subKlineStream.CloseSend() svr.subKlineStream = nil } go svr.subscribeStreamKlines(true) }() if reconnect { zlog.Infof("subscribeKlines will reconnect after 5s") time.Sleep(5 * time.Second) } stream, err := svr.exchangeClient.SubscribeKline(context.Background()) if err != nil { zlog.Error("subscribeKlines reqeust error: ", err) return } svr.subKlineStream = stream // 发送订阅消息 exchanges := []pb.ExchangeType{pb.ExchangeType_OKX} for _, exchange := range exchanges { instIds := svr.subKlineInsts[exchange] if len(instIds) == 0 { continue } msg := &pb.ReqStreamSubscribeKline{ SubType: pb.SubscribeType_Subscribe, Exchanges: []pb.ExchangeType{exchange}, InstIds: instIds, Intervals: svr.subscribeKlineIntervals, OnlyConfirm: true, } zlog.Debugf("send stream subscribe kline msg: %#v", msg) if err = stream.Send(msg); err != nil { zlog.Errorf("send stream subscribe kline msg error: %v", msg, err) return } } // 接收消息的goroutine for { msg, err := stream.Recv() if err == io.EOF { zlog.Debugf("subscribeKlines connection server closeed") return } if err != nil { zlog.Error("subscribeKlines recv error: ", err) return } for _, k := range msg.Kline.Klines { kline := new(types.Kline) kline.ParsePBKline(msg.Kline.Exchange, k) zlog.Debugf("recv: streamId=%d, %v, %s, %#v", msg.Kline.StreamId, msg.Kline.Exchange, msg.Kline.InstId, kline) // kline klineStore -> klineSeries -> strategy -> indicator -> klineSeries.Series svr.klineStore.Update(msg.Kline.Exchange, msg.Kline.InstId, kline) } } }