kucoin: convert websocket trade and order

This commit is contained in:
c9s 2021-12-23 13:39:15 +08:00
parent cfd68fdd1d
commit 8e834ce8fe
3 changed files with 111 additions and 11 deletions

View File

@ -2,6 +2,7 @@ package kucoin
import (
"fmt"
"hash/fnv"
"math"
"strings"
"time"
@ -99,3 +100,39 @@ func convertSubscriptions(ss []types.Subscription) ([]kucoinapi.WebSocketCommand
return cmds, nil
}
func hashStringID(s string) uint64 {
h := fnv.New64a()
h.Write([]byte(s))
return h.Sum64()
}
func toGlobalSide(s string) types.SideType {
switch s {
case "buy":
return types.SideTypeBuy
case "sell":
return types.SideTypeSell
}
return types.SideTypeSelf
}
func toGlobalOrderType(s string) types.OrderType {
switch s {
case "limit":
return types.OrderTypeLimit
case "stop_limit":
return types.OrderTypeStopLimit
case "market":
return types.OrderTypeMarket
case "stop_market":
return types.OrderTypeStopMarket
}
return ""
}

View File

@ -35,11 +35,11 @@ const (
)
type WebSocketCommand struct {
Id int64 `json:"id"`
Id int64 `json:"id"`
Type WebSocketMessageType `json:"type"`
Topic string `json:"topic"`
PrivateChannel bool `json:"privateChannel"`
Response bool `json:"response"`
Topic string `json:"topic"`
PrivateChannel bool `json:"privateChannel"`
Response bool `json:"response"`
}
func (c *WebSocketCommand) JSON() ([]byte, error) {
@ -85,16 +85,21 @@ type WebSocketCandle struct {
}
type WebSocketPrivateOrder struct {
OrderId string `json:"orderId"`
TradeId string `json:"tradeId"`
Symbol string `json:"symbol"`
OrderType string `json:"orderType"`
Side string `json:"side"`
OrderId string `json:"orderId"`
Type string `json:"type"`
OrderTime types.MillisecondTimestamp `json:"orderTime"`
Price fixedpoint.Value `json:"price"`
Size fixedpoint.Value `json:"size"`
FilledSize fixedpoint.Value `json:"filledSize"`
RemainSize fixedpoint.Value `json:"remainSize"`
Liquidity string `json:"liquidity"`
MatchPrice fixedpoint.Value `json:"matchPrice"`
MatchSize fixedpoint.Value `json:"matchSize"`
ClientOid string `json:"clientOid"`
Status string `json:"status"`
Ts types.MillisecondTimestamp `json:"ts"`
@ -104,11 +109,11 @@ type WebSocketAccountBalance struct {
Total fixedpoint.Value `json:"total"`
Available fixedpoint.Value `json:"available"`
AvailableChange fixedpoint.Value `json:"availableChange"`
Currency string `json:"currency"`
Currency string `json:"currency"`
Hold fixedpoint.Value `json:"hold"`
HoldChange fixedpoint.Value `json:"holdChange"`
RelationEvent string `json:"relationEvent"`
RelationEventId string `json:"relationEventId"`
RelationEvent string `json:"relationEvent"`
RelationEventId string `json:"relationEventId"`
RelationContext struct {
Symbol string `json:"symbol"`
TradeId string `json:"tradeId"`

View File

@ -12,7 +12,7 @@ import (
"github.com/pkg/errors"
)
const readTimeout = 20 * time.Second
const readTimeout = 30 * time.Second
type WebsocketOp struct {
Op string `json:"op"`
@ -58,6 +58,7 @@ func NewStream(client *kucoinapi.RestClient) *Stream {
stream.OnCandleEvent(stream.handleCandleEvent)
stream.OnOrderBookL2Event(stream.handleOrderBookL2Event)
stream.OnTickerEvent(stream.handleTickerEvent)
stream.OnPrivateOrderEvent(stream.handlePrivateOrderEvent)
return stream
}
@ -67,9 +68,66 @@ func (s *Stream) handleOrderBookL2Event(e *kucoinapi.WebSocketOrderBookL2) {}
func (s *Stream) handleTickerEvent(e *kucoinapi.WebSocketTicker) {}
func (s *Stream) handleAccountBalanceEvent(e *kucoinapi.WebSocketAccountBalance) {}
func (s *Stream) handleAccountBalanceEvent(e *kucoinapi.WebSocketAccountBalance) {
bm := types.BalanceMap{}
bm[e.Currency] = types.Balance{
Currency: e.Currency,
Available: e.Available,
Locked: e.Hold,
}
s.StandardStream.EmitBalanceUpdate(bm)
}
func (s *Stream) handlePrivateOrderEvent(e *kucoinapi.WebSocketPrivateOrder) {}
func (s *Stream) handlePrivateOrderEvent(e *kucoinapi.WebSocketPrivateOrder) {
if e.Type == "match" {
s.StandardStream.EmitTradeUpdate(types.Trade{
OrderID: hashStringID(e.OrderId),
ID: hashStringID(e.TradeId),
Exchange: types.ExchangeKucoin,
Price: e.MatchPrice.Float64(),
Quantity: e.MatchSize.Float64(),
QuoteQuantity: e.MatchPrice.Float64() * e.MatchSize.Float64(),
Symbol: toGlobalSymbol(e.Symbol),
Side: toGlobalSide(e.Side),
IsBuyer: e.Side == "buy",
IsMaker: e.Liquidity == "maker",
Time: types.Time(e.Ts.Time()),
Fee: 0, // not supported
FeeCurrency: "", // not supported
})
}
switch e.Type {
case "open", "match", "filled":
status := types.OrderStatusNew
if e.Status == "done" {
status = types.OrderStatusFilled
} else if e.FilledSize > 0 {
status = types.OrderStatusPartiallyFilled
}
s.StandardStream.EmitOrderUpdate(types.Order{
SubmitOrder: types.SubmitOrder{
Symbol: toGlobalSymbol(e.Symbol),
Side: toGlobalSide(e.Side),
Type: toGlobalOrderType(e.OrderType),
Quantity: e.Size.Float64(),
Price: e.Price.Float64(),
},
Exchange: types.ExchangeKucoin,
OrderID: hashStringID(e.OrderId),
Status: status,
ExecutedQuantity: e.FilledSize.Float64(),
IsWorking: true,
CreationTime: types.Time(e.OrderTime.Time()),
UpdateTime: types.Time(e.Ts.Time()),
})
default:
log.Warnf("unhandled private order type: %s, payload: %+v", e.Type, e)
}
}
func (s *Stream) handleConnect() {
if s.publicOnly {