qbtrade/pkg/grpc/convert.go
2024-06-27 22:42:38 +08:00

238 lines
6.4 KiB
Go

package grpc
import (
"fmt"
"strconv"
log "github.com/sirupsen/logrus"
"git.qtrade.icu/lychiyu/qbtrade/pkg/fixedpoint"
"git.qtrade.icu/lychiyu/qbtrade/pkg/pb"
"git.qtrade.icu/lychiyu/qbtrade/pkg/qbtrade"
"git.qtrade.icu/lychiyu/qbtrade/pkg/types"
)
func toSubscriptions(sub *pb.Subscription) (types.Subscription, error) {
switch sub.Channel {
case pb.Channel_TRADE:
return types.Subscription{
Symbol: sub.Symbol,
Channel: types.MarketTradeChannel,
}, nil
case pb.Channel_BOOK:
return types.Subscription{
Symbol: sub.Symbol,
Channel: types.BookChannel,
Options: types.SubscribeOptions{
Depth: types.Depth(sub.Depth),
},
}, nil
case pb.Channel_KLINE:
return types.Subscription{
Symbol: sub.Symbol,
Channel: types.KLineChannel,
Options: types.SubscribeOptions{
Interval: types.Interval(sub.Interval),
},
}, nil
}
return types.Subscription{}, fmt.Errorf("unsupported subscription channel: %s", sub.Channel)
}
func transPriceVolume(srcPvs types.PriceVolumeSlice) (pvs []*pb.PriceVolume) {
for _, srcPv := range srcPvs {
pvs = append(pvs, &pb.PriceVolume{
Price: srcPv.Price.String(),
Volume: srcPv.Volume.String(),
})
}
return pvs
}
func transBook(session *qbtrade.ExchangeSession, book types.SliceOrderBook, event pb.Event) *pb.MarketData {
return &pb.MarketData{
Session: session.Name,
Exchange: session.ExchangeName.String(),
Symbol: book.Symbol,
Channel: pb.Channel_BOOK,
Event: event,
Depth: &pb.Depth{
Exchange: session.ExchangeName.String(),
Symbol: book.Symbol,
Asks: transPriceVolume(book.Asks),
Bids: transPriceVolume(book.Bids),
},
}
}
func toOrderType(orderType pb.OrderType) types.OrderType {
switch orderType {
case pb.OrderType_MARKET:
return types.OrderTypeMarket
case pb.OrderType_LIMIT:
return types.OrderTypeLimit
}
log.Warnf("unexpected order type: %v", orderType)
return types.OrderTypeLimit
}
func toSide(side pb.Side) types.SideType {
switch side {
case pb.Side_BUY:
return types.SideTypeBuy
case pb.Side_SELL:
return types.SideTypeSell
}
log.Warnf("unexpected side type: %v", side)
return types.SideTypeBuy
}
func toSubmitOrders(pbOrders []*pb.SubmitOrder) (submitOrders []types.SubmitOrder) {
for _, pbOrder := range pbOrders {
submitOrders = append(submitOrders, types.SubmitOrder{
ClientOrderID: pbOrder.ClientOrderId,
Symbol: pbOrder.Symbol,
Side: toSide(pbOrder.Side),
Type: toOrderType(pbOrder.OrderType),
Price: fixedpoint.MustNewFromString(pbOrder.Price),
Quantity: fixedpoint.MustNewFromString(pbOrder.Quantity),
StopPrice: fixedpoint.MustNewFromString(pbOrder.StopPrice),
TimeInForce: "",
})
}
return submitOrders
}
func transBalances(session *qbtrade.ExchangeSession, balances types.BalanceMap) (pbBalances []*pb.Balance) {
for _, b := range balances {
pbBalances = append(pbBalances, &pb.Balance{
Exchange: session.ExchangeName.String(),
Currency: b.Currency,
Available: b.Available.String(),
Locked: b.Locked.String(),
})
}
return pbBalances
}
func transTrade(session *qbtrade.ExchangeSession, trade types.Trade) *pb.Trade {
return &pb.Trade{
Session: session.Name,
Exchange: trade.Exchange.String(),
Symbol: trade.Symbol,
Id: strconv.FormatUint(trade.ID, 10),
Price: trade.Price.String(),
Quantity: trade.Quantity.String(),
CreatedAt: trade.Time.UnixMilli(),
Side: transSide(trade.Side),
FeeCurrency: trade.FeeCurrency,
Fee: trade.Fee.String(),
Maker: trade.IsMaker,
}
}
func transMarketTrade(session *qbtrade.ExchangeSession, marketTrade types.Trade) *pb.MarketData {
return &pb.MarketData{
Session: session.Name,
Exchange: session.ExchangeName.String(),
Symbol: marketTrade.Symbol,
Channel: pb.Channel_TRADE,
Event: pb.Event_UPDATE,
Trades: []*pb.Trade{
{
Exchange: marketTrade.Exchange.String(),
Symbol: marketTrade.Symbol,
Id: strconv.FormatUint(marketTrade.ID, 10),
Price: marketTrade.Price.String(),
Quantity: marketTrade.Quantity.String(),
CreatedAt: marketTrade.Time.UnixMilli(),
Side: transSide(marketTrade.Side),
FeeCurrency: marketTrade.FeeCurrency,
Fee: marketTrade.Fee.String(),
Maker: marketTrade.IsMaker,
},
},
}
}
func transSide(side types.SideType) pb.Side {
switch side {
case types.SideTypeBuy:
return pb.Side_BUY
case types.SideTypeSell:
return pb.Side_SELL
}
return pb.Side_SELL
}
func transOrderType(orderType types.OrderType) pb.OrderType {
switch orderType {
case types.OrderTypeLimit:
return pb.OrderType_LIMIT
case types.OrderTypeMarket:
return pb.OrderType_MARKET
case types.OrderTypeStopLimit:
return pb.OrderType_STOP_LIMIT
case types.OrderTypeStopMarket:
return pb.OrderType_STOP_MARKET
}
return pb.OrderType_LIMIT
}
func transOrder(session *qbtrade.ExchangeSession, order types.Order) *pb.Order {
return &pb.Order{
Exchange: order.Exchange.String(),
Symbol: order.Symbol,
Id: strconv.FormatUint(order.OrderID, 10),
Side: transSide(order.Side),
OrderType: transOrderType(order.Type),
Price: order.Price.String(),
StopPrice: order.StopPrice.String(),
Status: string(order.Status),
CreatedAt: order.CreationTime.UnixMilli(),
Quantity: order.Quantity.String(),
ExecutedQuantity: order.ExecutedQuantity.String(),
ClientOrderId: order.ClientOrderID,
GroupId: int64(order.GroupID),
}
}
func transKLine(session *qbtrade.ExchangeSession, kline types.KLine) *pb.KLine {
return &pb.KLine{
Session: session.Name,
Exchange: kline.Exchange.String(),
Symbol: kline.Symbol,
Open: kline.Open.String(),
High: kline.High.String(),
Low: kline.Low.String(),
Close: kline.Close.String(),
Volume: kline.Volume.String(),
QuoteVolume: kline.QuoteVolume.String(),
StartTime: kline.StartTime.UnixMilli(),
EndTime: kline.StartTime.UnixMilli(),
Closed: kline.Closed,
}
}
func transKLineResponse(session *qbtrade.ExchangeSession, kline types.KLine) *pb.MarketData {
return &pb.MarketData{
Session: session.Name,
Exchange: kline.Exchange.String(),
Symbol: kline.Symbol,
Channel: pb.Channel_KLINE,
Event: pb.Event_UPDATE,
Kline: transKLine(session, kline),
SubscribedAt: 0,
}
}