kucoin: fix trades sync

This commit is contained in:
c9s 2022-04-12 23:25:41 +08:00
parent fad9449ee6
commit a34dbf12e2
7 changed files with 73 additions and 55 deletions

View File

@ -3,7 +3,6 @@ package batch
import ( import (
"context" "context"
"errors" "errors"
"sort"
"time" "time"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
@ -41,7 +40,6 @@ func (e TradeBatchQuery) Query(ctx context.Context, symbol string, options *type
var startTime = *options.StartTime var startTime = *options.StartTime
var endTime = *options.EndTime var endTime = *options.EndTime
go func() { go func() {
limiter := rate.NewLimiter(rate.Every(5*time.Second), 2) // from binance (original 1200, use 1000 for safety) limiter := rate.NewLimiter(rate.Every(5*time.Second), 2) // from binance (original 1200, use 1000 for safety)
@ -66,9 +64,7 @@ func (e TradeBatchQuery) Query(ctx context.Context, symbol string, options *type
}) })
// sort trades by time in ascending order // sort trades by time in ascending order
sort.Slice(trades, func(i, j int) bool { types.SortTradesAscending(trades)
return trades[i].Time.Before(time.Time(trades[j].Time))
})
if err != nil { if err != nil {
errC <- err errC <- err
@ -78,7 +74,9 @@ func (e TradeBatchQuery) Query(ctx context.Context, symbol string, options *type
// if all trades are duplicated or empty, we end the batch query // if all trades are duplicated or empty, we end the batch query
if len(trades) == 0 { if len(trades) == 0 {
return return
} else if len(trades) > 0 { }
if len(trades) > 0 {
allExists := true allExists := true
for _, td := range trades { for _, td := range trades {
k := td.Key() k := td.Key()

View File

@ -364,10 +364,9 @@ func (e *Exchange) QueryTrades(ctx context.Context, symbol string, options *type
if options.StartTime != nil && options.EndTime != nil { if options.StartTime != nil && options.EndTime != nil {
req.StartAt(*options.StartTime) req.StartAt(*options.StartTime)
if options.EndTime.Sub(*options.StartTime) < 7*24*time.Hour { if options.EndTime.Sub(*options.StartTime) < 7*24*time.Hour {
req.EndAt(*options.EndTime) req.EndAt(*options.EndTime)
} else {
req.StartAt(options.StartTime.Add(7*24*time.Hour - time.Minute))
} }
} else if options.StartTime != nil { } else if options.StartTime != nil {
req.StartAt(*options.StartTime) req.StartAt(*options.StartTime)
@ -383,6 +382,7 @@ func (e *Exchange) QueryTrades(ctx context.Context, symbol string, options *type
if err != nil { if err != nil {
return trades, err return trades, err
} }
for _, fill := range response.Items { for _, fill := range response.Items {
trade := toGlobalTrade(fill) trade := toGlobalTrade(fill)
trades = append(trades, trade) trades = append(trades, trade)

View File

@ -195,4 +195,3 @@ type APIResponse struct {
Message string `json:"msg"` Message string `json:"msg"`
Data json.RawMessage `json:"data"` Data json.RawMessage `json:"data"`
} }

View File

@ -50,18 +50,6 @@ func (r *GetFillsRequest) EndAt(endAt time.Time) *GetFillsRequest {
// GetQueryParameters builds and checks the query parameters and returns url.Values // GetQueryParameters builds and checks the query parameters and returns url.Values
func (r *GetFillsRequest) GetQueryParameters() (url.Values, error) { func (r *GetFillsRequest) GetQueryParameters() (url.Values, error) {
var params = map[string]interface{}{} var params = map[string]interface{}{}
query := url.Values{}
for k, v := range params {
query.Add(k, fmt.Sprintf("%v", v))
}
return query, nil
}
// GetParameters builds and checks the parameters and return the result in a map object
func (r *GetFillsRequest) GetParameters() (map[string]interface{}, error) {
var params = map[string]interface{}{}
// check orderID field -> json key orderId // check orderID field -> json key orderId
if r.orderID != nil { if r.orderID != nil {
orderID := *r.orderID orderID := *r.orderID
@ -147,6 +135,18 @@ func (r *GetFillsRequest) GetParameters() (map[string]interface{}, error) {
} else { } else {
} }
query := url.Values{}
for k, v := range params {
query.Add(k, fmt.Sprintf("%v", v))
}
return query, nil
}
// GetParameters builds and checks the parameters and return the result in a map object
func (r *GetFillsRequest) GetParameters() (map[string]interface{}, error) {
var params = map[string]interface{}{}
return params, nil return params, nil
} }
@ -208,9 +208,12 @@ func (r *GetFillsRequest) GetSlugsMap() (map[string]string, error) {
func (r *GetFillsRequest) Do(ctx context.Context) (*FillListPage, error) { func (r *GetFillsRequest) Do(ctx context.Context) (*FillListPage, error) {
// empty params for GET operation // no body params
var params interface{} var params interface{}
query := url.Values{} query, err := r.GetQueryParameters()
if err != nil {
return nil, err
}
apiURL := "/api/v1/fills" apiURL := "/api/v1/fills"

View File

@ -52,19 +52,19 @@ func (c *TradeService) NewGetFillsRequest() *GetFillsRequest {
type GetFillsRequest struct { type GetFillsRequest struct {
client requestgen.AuthenticatedAPIClient client requestgen.AuthenticatedAPIClient
orderID *string `param:"orderId"` orderID *string `param:"orderId,query"`
tradeType *string `param:"tradeType" default:"TRADE"` tradeType *string `param:"tradeType,query" default:"TRADE"`
symbol *string `param:"symbol"` symbol *string `param:"symbol,query"`
side *string `param:"side" validValues:"buy,sell"` side *string `param:"side,query" validValues:"buy,sell"`
orderType *string `param:"type" validValues:"limit,market,limit_stop,market_stop"` orderType *string `param:"type,query" validValues:"limit,market,limit_stop,market_stop"`
startAt *time.Time `param:"startAt,milliseconds"` startAt *time.Time `param:"startAt,query,milliseconds"`
endAt *time.Time `param:"endAt,milliseconds"` endAt *time.Time `param:"endAt,query,milliseconds"`
} }
type FillListPage struct { type FillListPage struct {

View File

@ -61,32 +61,37 @@ func (s *Server) Subscribe(request *pb.SubscribeRequest, server pb.MarketDataSer
streamPool := map[string]types.Stream{} streamPool := map[string]types.Stream{}
for sessionName, subs := range exchangeSubscriptions { for sessionName, subs := range exchangeSubscriptions {
if session, ok := s.Environ.Session(sessionName); ok { session, ok := s.Environ.Session(sessionName)
stream := session.Exchange.NewStream() if !ok {
stream.SetPublicOnly() log.Errorf("session %s not found", sessionName)
for _, sub := range subs { continue
stream.Subscribe(sub.Channel, sub.Symbol, sub.Options)
}
stream.OnBookSnapshot(func(book types.SliceOrderBook) {
if err := server.Send(transBook(session, book, pb.Event_SNAPSHOT)); err != nil {
log.WithError(err).Error("grpc stream send error")
}
})
stream.OnBookUpdate(func(book types.SliceOrderBook) {
if err := server.Send(transBook(session, book, pb.Event_UPDATE)); err != nil {
log.WithError(err).Error("grpc stream send error")
}
})
stream.OnKLineClosed(func(kline types.KLine) {
err := server.Send(transKLine(session, kline))
if err != nil {
log.WithError(err).Error("grpc stream send error")
}
})
streamPool[sessionName] = stream
} }
stream := session.Exchange.NewStream()
stream.SetPublicOnly()
for _, sub := range subs {
log.Infof("%s subscribe %s %s %+v", sessionName, sub.Channel, sub.Symbol, sub.Options)
stream.Subscribe(sub.Channel, sub.Symbol, sub.Options)
}
stream.OnBookSnapshot(func(book types.SliceOrderBook) {
if err := server.Send(transBook(session, book, pb.Event_SNAPSHOT)); err != nil {
log.WithError(err).Error("grpc stream send error")
}
})
stream.OnBookUpdate(func(book types.SliceOrderBook) {
if err := server.Send(transBook(session, book, pb.Event_UPDATE)); err != nil {
log.WithError(err).Error("grpc stream send error")
}
})
stream.OnKLineClosed(func(kline types.KLine) {
err := server.Send(transKLine(session, kline))
if err != nil {
log.WithError(err).Error("grpc stream send error")
}
})
streamPool[sessionName] = stream
} }
for sessionName, stream := range streamPool { for sessionName, stream := range streamPool {

13
pkg/types/sort.go Normal file
View File

@ -0,0 +1,13 @@
package types
import (
"sort"
"time"
)
func SortTradesAscending(trades []Trade) []Trade {
sort.Slice(trades, func(i, j int) bool {
return trades[i].Time.Before(time.Time(trades[j].Time))
})
return trades
}