From d2b45f5d58134b756be096ed644b7256d336c248 Mon Sep 17 00:00:00 2001 From: Edwin Date: Mon, 29 Jan 2024 17:09:19 +0800 Subject: [PATCH] pkg/exchange: refactor kline api --- pkg/exchange/okex/exchange.go | 28 +-- pkg/exchange/okex/okexapi/client_test.go | 9 + .../okex/okexapi/get_candles_request.go | 137 +++++++++++ .../okexapi/get_candles_request_requestgen.go | 226 ++++++++++++++++++ pkg/exchange/okex/okexapi/market.go | 162 ------------- pkg/exchange/okex/parse.go | 116 +-------- pkg/exchange/okex/parse_test.go | 44 ++-- pkg/exchange/okex/stream.go | 2 +- 8 files changed, 410 insertions(+), 314 deletions(-) create mode 100644 pkg/exchange/okex/okexapi/get_candles_request.go create mode 100644 pkg/exchange/okex/okexapi/get_candles_request_requestgen.go diff --git a/pkg/exchange/okex/exchange.go b/pkg/exchange/okex/exchange.go index dc20a2b71..9fc20e796 100644 --- a/pkg/exchange/okex/exchange.go +++ b/pkg/exchange/okex/exchange.go @@ -32,6 +32,7 @@ var ( queryOpenOrderLimiter = rate.NewLimiter(rate.Every(30*time.Millisecond), 30) queryClosedOrderRateLimiter = rate.NewLimiter(rate.Every(100*time.Millisecond), 10) queryTradeLimiter = rate.NewLimiter(rate.Every(100*time.Millisecond), 10) + queryKLineLimiter = rate.NewLimiter(rate.Every(100*time.Millisecond), 20) ) const ( @@ -379,24 +380,24 @@ func (e *Exchange) NewStream() types.Stream { } func (e *Exchange) QueryKLines(ctx context.Context, symbol string, interval types.Interval, options types.KLineQueryOptions) ([]types.KLine, error) { - if err := marketDataLimiter.Wait(ctx); err != nil { - return nil, err + if err := queryKLineLimiter.Wait(ctx); err != nil { + return nil, fmt.Errorf("query k line rate limiter wait error: %w", err) } intervalParam, err := toLocalInterval(interval) if err != nil { - return nil, fmt.Errorf("fail to get interval: %w", err) + return nil, fmt.Errorf("failed to get interval: %w", err) } - req := e.client.NewCandlesticksRequest(toLocalSymbol(symbol)) + req := e.client.NewGetCandlesRequest().InstrumentID(toLocalSymbol(symbol)) req.Bar(intervalParam) if options.StartTime != nil { - req.After(options.StartTime.Unix()) + req.After(*options.StartTime) } if options.EndTime != nil { - req.Before(options.EndTime.Unix()) + req.Before(*options.EndTime) } candles, err := req.Do(ctx) @@ -406,20 +407,7 @@ func (e *Exchange) QueryKLines(ctx context.Context, symbol string, interval type var klines []types.KLine for _, candle := range candles { - klines = append(klines, types.KLine{ - Exchange: types.ExchangeOKEx, - Symbol: symbol, - Interval: interval, - Open: candle.Open, - High: candle.High, - Low: candle.Low, - Close: candle.Close, - Closed: true, - Volume: candle.Volume, - QuoteVolume: candle.VolumeInCurrency, - StartTime: types.Time(candle.Time), - EndTime: types.Time(candle.Time.Add(interval.Duration() - time.Millisecond)), - }) + klines = append(klines, kLineToGlobal(candle, interval, symbol)) } return klines, nil diff --git a/pkg/exchange/okex/okexapi/client_test.go b/pkg/exchange/okex/okexapi/client_test.go index 3fb44777d..3d12fcc8f 100644 --- a/pkg/exchange/okex/okexapi/client_test.go +++ b/pkg/exchange/okex/okexapi/client_test.go @@ -307,3 +307,12 @@ func TestClient_GetOrderDetailsRequest(t *testing.T) { assert.NotEmpty(t, orderDetail) t.Logf("order detail: %+v", orderDetail) } + +func TestClient_CandlesTicksRequest(t *testing.T) { + client := getTestClientOrSkip(t) + ctx := context.Background() + req := client.NewGetCandlesRequest().InstrumentID("BTC-USDT") + res, err := req.Do(ctx) + assert.NoError(t, err) + t.Log(res) +} diff --git a/pkg/exchange/okex/okexapi/get_candles_request.go b/pkg/exchange/okex/okexapi/get_candles_request.go new file mode 100644 index 000000000..a9fda9ce9 --- /dev/null +++ b/pkg/exchange/okex/okexapi/get_candles_request.go @@ -0,0 +1,137 @@ +package okexapi + +//go:generate -command GetRequest requestgen -method GET -responseType .APIResponse -responseDataField Data +//go:generate -command PostRequest requestgen -method POST -responseType .APIResponse -responseDataField Data + +import ( + "encoding/json" + "errors" + "fmt" + "time" + + "github.com/c9s/requestgen" + + "github.com/c9s/bbgo/pkg/fixedpoint" + "github.com/c9s/bbgo/pkg/types" +) + +type KLine struct { + StartTime types.MillisecondTimestamp + OpenPrice fixedpoint.Value + HighestPrice fixedpoint.Value + LowestPrice fixedpoint.Value + ClosePrice fixedpoint.Value + // Volume trading volume, with a unit of contract. + + // If it is a derivatives contract, the value is the number of contracts. + // If it is SPOT/MARGIN, the value is the quantity in base currency. + Volume fixedpoint.Value + // VolumeInCurrency trading volume, with a unit of currency. + // If it is a derivatives contract, the value is the number of base currency. + // If it is SPOT/MARGIN, the value is the quantity in quote currency. + VolumeInCurrency fixedpoint.Value + // VolumeInCurrencyQuote Trading volume, the value is the quantity in quote currency + // e.g. The unit is USDT for BTC-USDT and BTC-USDT-SWAP; + // The unit is USD for BTC-USD-SWAP + // ** REMARK: To prevent overflow, we need to avoid unmarshaling it. ** + //VolumeInCurrencyQuote fixedpoint.Value + // The state of candlesticks. + // 0 represents that it is uncompleted, 1 represents that it is completed. + Confirm fixedpoint.Value +} + +type KLineSlice []KLine + +func (m *KLineSlice) UnmarshalJSON(b []byte) error { + if m == nil { + return errors.New("nil pointer of kline slice") + } + s, err := parseKLineSliceJSON(b) + if err != nil { + return err + } + + *m = s + return nil +} + +// parseKLineSliceJSON tries to parse a 2 dimensional string array into a KLineSlice +// +// [ +// [ +// "1597026383085", +// "8533.02", +// "8553.74", +// "8527.17", +// "8548.26", +// "45247", +// "529.5858061", +// "5529.5858061", +// "0" +// ] +// ] +func parseKLineSliceJSON(in []byte) (slice KLineSlice, err error) { + var rawKLines [][]json.RawMessage + + err = json.Unmarshal(in, &rawKLines) + if err != nil { + return slice, err + } + + for _, raw := range rawKLines { + if len(raw) != 9 { + return nil, fmt.Errorf("unexpected kline length: %d, data: %q", len(raw), raw) + } + var kline KLine + if err = json.Unmarshal(raw[0], &kline.StartTime); err != nil { + return nil, fmt.Errorf("failed to unmarshal into timestamp: %q", raw[0]) + } + if err = json.Unmarshal(raw[1], &kline.OpenPrice); err != nil { + return nil, fmt.Errorf("failed to unmarshal into open price: %q", raw[1]) + } + if err = json.Unmarshal(raw[2], &kline.HighestPrice); err != nil { + return nil, fmt.Errorf("failed to unmarshal into highest price: %q", raw[2]) + } + if err = json.Unmarshal(raw[3], &kline.LowestPrice); err != nil { + return nil, fmt.Errorf("failed to unmarshal into lowest price: %q", raw[3]) + } + if err = json.Unmarshal(raw[4], &kline.ClosePrice); err != nil { + return nil, fmt.Errorf("failed to unmarshal into close price: %q", raw[4]) + } + if err = json.Unmarshal(raw[5], &kline.Volume); err != nil { + return nil, fmt.Errorf("failed to unmarshal into volume: %q", raw[5]) + } + if err = json.Unmarshal(raw[6], &kline.VolumeInCurrency); err != nil { + return nil, fmt.Errorf("failed to unmarshal into volume currency: %q", raw[6]) + } + //if err = json.Unmarshal(raw[7], &kline.VolumeInCurrencyQuote); err != nil { + // return nil, fmt.Errorf("failed to unmarshal into trading currency quote: %q", raw[7]) + //} + if err = json.Unmarshal(raw[8], &kline.Confirm); err != nil { + return nil, fmt.Errorf("failed to unmarshal into confirm: %q", raw[8]) + } + + slice = append(slice, kline) + } + + return slice, nil +} + +//go:generate GetRequest -url "/api/v5/market/candles" -type GetCandlesRequest -responseDataType KLineSlice +type GetCandlesRequest struct { + client requestgen.APIClient + + instrumentID string `param:"instId,query"` + + limit *int `param:"limit,query"` + + bar *string `param:"bar,query"` + + after *time.Time `param:"after,query,milliseconds"` + + before *time.Time `param:"before,query,milliseconds"` +} + +func (c *RestClient) NewGetCandlesRequest() *GetCandlesRequest { + return &GetCandlesRequest{client: c} +} diff --git a/pkg/exchange/okex/okexapi/get_candles_request_requestgen.go b/pkg/exchange/okex/okexapi/get_candles_request_requestgen.go new file mode 100644 index 000000000..58351d447 --- /dev/null +++ b/pkg/exchange/okex/okexapi/get_candles_request_requestgen.go @@ -0,0 +1,226 @@ +// Code generated by "requestgen -method GET -responseType .APIResponse -responseDataField Data -url /api/v5/market/candles -type GetCandlesRequest -responseDataType KLineSlice"; DO NOT EDIT. + +package okexapi + +import ( + "context" + "encoding/json" + "fmt" + "net/url" + "reflect" + "regexp" + "strconv" + "time" +) + +func (g *GetCandlesRequest) InstrumentID(instrumentID string) *GetCandlesRequest { + g.instrumentID = instrumentID + return g +} + +func (g *GetCandlesRequest) Limit(limit int) *GetCandlesRequest { + g.limit = &limit + return g +} + +func (g *GetCandlesRequest) Bar(bar string) *GetCandlesRequest { + g.bar = &bar + return g +} + +func (g *GetCandlesRequest) After(after time.Time) *GetCandlesRequest { + g.after = &after + return g +} + +func (g *GetCandlesRequest) Before(before time.Time) *GetCandlesRequest { + g.before = &before + return g +} + +// GetQueryParameters builds and checks the query parameters and returns url.Values +func (g *GetCandlesRequest) GetQueryParameters() (url.Values, error) { + var params = map[string]interface{}{} + // check instrumentID field -> json key instId + instrumentID := g.instrumentID + + // assign parameter of instrumentID + params["instId"] = instrumentID + // check limit field -> json key limit + if g.limit != nil { + limit := *g.limit + + // assign parameter of limit + params["limit"] = limit + } else { + } + // check bar field -> json key bar + if g.bar != nil { + bar := *g.bar + + // assign parameter of bar + params["bar"] = bar + } else { + } + // check after field -> json key after + if g.after != nil { + after := *g.after + + // assign parameter of after + // convert time.Time to milliseconds time stamp + params["after"] = strconv.FormatInt(after.UnixNano()/int64(time.Millisecond), 10) + } else { + } + // check before field -> json key before + if g.before != nil { + before := *g.before + + // assign parameter of before + // convert time.Time to milliseconds time stamp + params["before"] = strconv.FormatInt(before.UnixNano()/int64(time.Millisecond), 10) + } 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 (g *GetCandlesRequest) GetParameters() (map[string]interface{}, error) { + var params = map[string]interface{}{} + + return params, nil +} + +// GetParametersQuery converts the parameters from GetParameters into the url.Values format +func (g *GetCandlesRequest) GetParametersQuery() (url.Values, error) { + query := url.Values{} + + params, err := g.GetParameters() + if err != nil { + return query, err + } + + for _k, _v := range params { + if g.isVarSlice(_v) { + g.iterateSlice(_v, func(it interface{}) { + query.Add(_k+"[]", fmt.Sprintf("%v", it)) + }) + } else { + query.Add(_k, fmt.Sprintf("%v", _v)) + } + } + + return query, nil +} + +// GetParametersJSON converts the parameters from GetParameters into the JSON format +func (g *GetCandlesRequest) GetParametersJSON() ([]byte, error) { + params, err := g.GetParameters() + if err != nil { + return nil, err + } + + return json.Marshal(params) +} + +// GetSlugParameters builds and checks the slug parameters and return the result in a map object +func (g *GetCandlesRequest) GetSlugParameters() (map[string]interface{}, error) { + var params = map[string]interface{}{} + + return params, nil +} + +func (g *GetCandlesRequest) applySlugsToUrl(url string, slugs map[string]string) string { + for _k, _v := range slugs { + needleRE := regexp.MustCompile(":" + _k + "\\b") + url = needleRE.ReplaceAllString(url, _v) + } + + return url +} + +func (g *GetCandlesRequest) iterateSlice(slice interface{}, _f func(it interface{})) { + sliceValue := reflect.ValueOf(slice) + for _i := 0; _i < sliceValue.Len(); _i++ { + it := sliceValue.Index(_i).Interface() + _f(it) + } +} + +func (g *GetCandlesRequest) isVarSlice(_v interface{}) bool { + rt := reflect.TypeOf(_v) + switch rt.Kind() { + case reflect.Slice: + return true + } + return false +} + +func (g *GetCandlesRequest) GetSlugsMap() (map[string]string, error) { + slugs := map[string]string{} + params, err := g.GetSlugParameters() + if err != nil { + return slugs, nil + } + + for _k, _v := range params { + slugs[_k] = fmt.Sprintf("%v", _v) + } + + return slugs, nil +} + +// GetPath returns the request path of the API +func (g *GetCandlesRequest) GetPath() string { + return "/api/v5/market/candles" +} + +// Do generates the request object and send the request object to the API endpoint +func (g *GetCandlesRequest) Do(ctx context.Context) (KLineSlice, error) { + + // no body params + var params interface{} + query, err := g.GetQueryParameters() + if err != nil { + return nil, err + } + + var apiURL string + + apiURL = g.GetPath() + + req, err := g.client.NewRequest(ctx, "GET", apiURL, query, params) + if err != nil { + return nil, err + } + + response, err := g.client.SendRequest(req) + if err != nil { + return nil, err + } + + var apiResponse APIResponse + if err := response.DecodeJSON(&apiResponse); err != nil { + return nil, err + } + + type responseValidator interface { + Validate() error + } + validator, ok := interface{}(apiResponse).(responseValidator) + if ok { + if err := validator.Validate(); err != nil { + return nil, err + } + } + var data KLineSlice + if err := json.Unmarshal(apiResponse.Data, &data); err != nil { + return nil, err + } + return data, nil +} diff --git a/pkg/exchange/okex/okexapi/market.go b/pkg/exchange/okex/okexapi/market.go index 9c5b7d0db..7f23e2c97 100644 --- a/pkg/exchange/okex/okexapi/market.go +++ b/pkg/exchange/okex/okexapi/market.go @@ -5,163 +5,8 @@ import ( "encoding/json" "fmt" "net/url" - "strconv" - "time" - - "github.com/c9s/bbgo/pkg/fixedpoint" ) -type Candle struct { - InstrumentID string - Interval string - Time time.Time - Open fixedpoint.Value - High fixedpoint.Value - Low fixedpoint.Value - Close fixedpoint.Value - Volume fixedpoint.Value - VolumeInCurrency fixedpoint.Value -} - -type CandlesticksRequest struct { - client *RestClient - - instId string `param:"instId"` - - limit *int `param:"limit"` - - bar *string `param:"bar"` - - after *int64 `param:"after,seconds"` - - before *int64 `param:"before,seconds"` -} - -func (r *CandlesticksRequest) After(after int64) *CandlesticksRequest { - r.after = &after - return r -} - -func (r *CandlesticksRequest) Before(before int64) *CandlesticksRequest { - r.before = &before - return r -} - -func (r *CandlesticksRequest) Bar(bar string) *CandlesticksRequest { - r.bar = &bar - return r -} - -func (r *CandlesticksRequest) Limit(limit int) *CandlesticksRequest { - r.limit = &limit - return r -} - -func (r *CandlesticksRequest) InstrumentID(instId string) *CandlesticksRequest { - r.instId = instId - return r -} - -func (r *CandlesticksRequest) Do(ctx context.Context) ([]Candle, error) { - // SPOT, SWAP, FUTURES, OPTION - var params = url.Values{} - params.Add("instId", r.instId) - - if r.bar != nil { - params.Add("bar", *r.bar) - } - - if r.before != nil { - params.Add("before", strconv.FormatInt(*r.before, 10)) - } - - if r.after != nil { - params.Add("after", strconv.FormatInt(*r.after, 10)) - } - - if r.limit != nil { - params.Add("limit", strconv.Itoa(*r.limit)) - } - - req, err := r.client.NewRequest(ctx, "GET", "/api/v5/market/candles", params, nil) - if err != nil { - return nil, err - } - - response, err := r.client.SendRequest(req) - if err != nil { - return nil, err - } - - type candleEntry [7]string - - var apiResponse APIResponse - if err := response.DecodeJSON(&apiResponse); err != nil { - return nil, err - } - var data []candleEntry - if err := json.Unmarshal(apiResponse.Data, &data); err != nil { - return nil, err - } - - var candles []Candle - for _, entry := range data { - timestamp, err := strconv.ParseInt(entry[0], 10, 64) - if err != nil { - return candles, err - } - - open, err := fixedpoint.NewFromString(entry[1]) - if err != nil { - return candles, err - } - - high, err := fixedpoint.NewFromString(entry[2]) - if err != nil { - return candles, err - } - - low, err := fixedpoint.NewFromString(entry[3]) - if err != nil { - return candles, err - } - - cls, err := fixedpoint.NewFromString(entry[4]) - if err != nil { - return candles, err - } - - vol, err := fixedpoint.NewFromString(entry[5]) - if err != nil { - return candles, err - } - - volCcy, err := fixedpoint.NewFromString(entry[6]) - if err != nil { - return candles, err - } - - var interval = "1m" - if r.bar != nil { - interval = *r.bar - } - - candles = append(candles, Candle{ - InstrumentID: r.instId, - Interval: interval, - Time: time.Unix(0, timestamp*int64(time.Millisecond)), - Open: open, - High: high, - Low: low, - Close: cls, - Volume: vol, - VolumeInCurrency: volCcy, - }) - } - - return candles, nil -} - type MarketTickersRequest struct { client *RestClient @@ -255,10 +100,3 @@ func (c *RestClient) NewMarketTickersRequest(instType string) *MarketTickersRequ instType: instType, } } - -func (c *RestClient) NewCandlesticksRequest(instId string) *CandlesticksRequest { - return &CandlesticksRequest{ - client: c, - instId: instId, - } -} diff --git a/pkg/exchange/okex/parse.go b/pkg/exchange/okex/parse.go index 008d700dd..2baa35fd5 100644 --- a/pkg/exchange/okex/parse.go +++ b/pkg/exchange/okex/parse.go @@ -2,7 +2,6 @@ package okex import ( "encoding/json" - "errors" "fmt" "strconv" "strings" @@ -243,31 +242,7 @@ func ParsePriceVolumeOrderSliceJSON(b []byte) (slice PriceVolumeOrderSlice, err return slice, nil } -type KLine struct { - StartTime types.MillisecondTimestamp - OpenPrice fixedpoint.Value - HighestPrice fixedpoint.Value - LowestPrice fixedpoint.Value - ClosePrice fixedpoint.Value - // Volume trading volume, with a unit of contract.cccccbcvefkeibbhtrebbfklrbetukhrgjgkiilufbde - - // If it is a derivatives contract, the value is the number of contracts. - // If it is SPOT/MARGIN, the value is the quantity in base currency. - Volume fixedpoint.Value - // VolumeCcy trading volume, with a unit of currency. - // If it is a derivatives contract, the value is the number of base currency. - // If it is SPOT/MARGIN, the value is the quantity in quote currency. - VolumeCcy fixedpoint.Value - // VolumeCcyQuote Trading volume, the value is the quantity in quote currency - // e.g. The unit is USDT for BTC-USDT and BTC-USDT-SWAP; - // The unit is USD for BTC-USD-SWAP - VolumeCcyQuote fixedpoint.Value - // The state of candlesticks. - // 0 represents that it is uncompleted, 1 represents that it is completed. - Confirm fixedpoint.Value -} - -func (k KLine) ToGlobal(interval types.Interval, symbol string) types.KLine { +func kLineToGlobal(k okexapi.KLine, interval types.Interval, symbol string) types.KLine { startTime := k.StartTime.Time() return types.KLine{ @@ -281,94 +256,17 @@ func (k KLine) ToGlobal(interval types.Interval, symbol string) types.KLine { High: k.HighestPrice, Low: k.LowestPrice, Volume: k.Volume, - QuoteVolume: k.VolumeCcy, // not supported - TakerBuyBaseAssetVolume: fixedpoint.Zero, // not supported - TakerBuyQuoteAssetVolume: fixedpoint.Zero, // not supported - LastTradeID: 0, // not supported - NumberOfTrades: 0, // not supported + QuoteVolume: k.VolumeInCurrency, // not supported + TakerBuyBaseAssetVolume: fixedpoint.Zero, // not supported + TakerBuyQuoteAssetVolume: fixedpoint.Zero, // not supported + LastTradeID: 0, // not supported + NumberOfTrades: 0, // not supported Closed: !k.Confirm.IsZero(), } } -type KLineSlice []KLine - -func (m *KLineSlice) UnmarshalJSON(b []byte) error { - if m == nil { - return errors.New("nil pointer of kline slice") - } - s, err := parseKLineSliceJSON(b) - if err != nil { - return err - } - - *m = s - return nil -} - -// parseKLineSliceJSON tries to parse a 2 dimensional string array into a KLineSlice -// -// [ -// [ -// "1597026383085", -// "8533.02", -// "8553.74", -// "8527.17", -// "8548.26", -// "45247", -// "529.5858061", -// "5529.5858061", -// "0" -// ] -// ] -func parseKLineSliceJSON(in []byte) (slice KLineSlice, err error) { - var rawKLines [][]json.RawMessage - - err = json.Unmarshal(in, &rawKLines) - if err != nil { - return slice, err - } - - for _, raw := range rawKLines { - if len(raw) != 9 { - return nil, fmt.Errorf("unexpected kline length: %d, data: %q", len(raw), raw) - } - var kline KLine - if err = json.Unmarshal(raw[0], &kline.StartTime); err != nil { - return nil, fmt.Errorf("failed to unmarshal into timestamp: %q", raw[0]) - } - if err = json.Unmarshal(raw[1], &kline.OpenPrice); err != nil { - return nil, fmt.Errorf("failed to unmarshal into open price: %q", raw[1]) - } - if err = json.Unmarshal(raw[2], &kline.HighestPrice); err != nil { - return nil, fmt.Errorf("failed to unmarshal into highest price: %q", raw[2]) - } - if err = json.Unmarshal(raw[3], &kline.LowestPrice); err != nil { - return nil, fmt.Errorf("failed to unmarshal into lowest price: %q", raw[3]) - } - if err = json.Unmarshal(raw[4], &kline.ClosePrice); err != nil { - return nil, fmt.Errorf("failed to unmarshal into close price: %q", raw[4]) - } - if err = json.Unmarshal(raw[5], &kline.Volume); err != nil { - return nil, fmt.Errorf("failed to unmarshal into volume: %q", raw[5]) - } - if err = json.Unmarshal(raw[6], &kline.VolumeCcy); err != nil { - return nil, fmt.Errorf("failed to unmarshal into volume currency: %q", raw[6]) - } - if err = json.Unmarshal(raw[7], &kline.VolumeCcyQuote); err != nil { - return nil, fmt.Errorf("failed to unmarshal into trading currency quote: %q", raw[7]) - } - if err = json.Unmarshal(raw[8], &kline.Confirm); err != nil { - return nil, fmt.Errorf("failed to unmarshal into confirm: %q", raw[8]) - } - - slice = append(slice, kline) - } - - return slice, nil -} - type KLineEvent struct { - Events KLineSlice + Events okexapi.KLineSlice InstrumentID string Symbol string diff --git a/pkg/exchange/okex/parse_test.go b/pkg/exchange/okex/parse_test.go index f95934df1..6877691ec 100644 --- a/pkg/exchange/okex/parse_test.go +++ b/pkg/exchange/okex/parse_test.go @@ -352,17 +352,17 @@ func Test_parseKLineSliceJSON(t *testing.T) { } ` exp := &KLineEvent{ - Events: KLineSlice{ + Events: okexapi.KLineSlice{ { - StartTime: types.NewMillisecondTimestampFromInt(1597026383085), - OpenPrice: fixedpoint.NewFromFloat(8533), - HighestPrice: fixedpoint.NewFromFloat(8553.74), - LowestPrice: fixedpoint.NewFromFloat(8527.17), - ClosePrice: fixedpoint.NewFromFloat(8548.26), - Volume: fixedpoint.NewFromFloat(45247), - VolumeCcy: fixedpoint.NewFromFloat(529.5858061), - VolumeCcyQuote: fixedpoint.NewFromFloat(529.5858061), - Confirm: fixedpoint.Zero, + StartTime: types.NewMillisecondTimestampFromInt(1597026383085), + OpenPrice: fixedpoint.NewFromFloat(8533), + HighestPrice: fixedpoint.NewFromFloat(8553.74), + LowestPrice: fixedpoint.NewFromFloat(8527.17), + ClosePrice: fixedpoint.NewFromFloat(8548.26), + Volume: fixedpoint.NewFromFloat(45247), + VolumeInCurrency: fixedpoint.NewFromFloat(529.5858061), + //VolumeInCurrencyQuote: fixedpoint.NewFromFloat(529.5858061), + Confirm: fixedpoint.Zero, }, }, InstrumentID: "BTC-USDT", @@ -651,17 +651,17 @@ func TestKLine_ToGlobal(t *testing.T) { } ` exp := &KLineEvent{ - Events: KLineSlice{ + Events: okexapi.KLineSlice{ { - StartTime: types.NewMillisecondTimestampFromInt(1597026383085), - OpenPrice: fixedpoint.NewFromFloat(8533), - HighestPrice: fixedpoint.NewFromFloat(8553.74), - LowestPrice: fixedpoint.NewFromFloat(8527.17), - ClosePrice: fixedpoint.NewFromFloat(8548.26), - Volume: fixedpoint.NewFromFloat(45247), - VolumeCcy: fixedpoint.NewFromFloat(529.5858061), - VolumeCcyQuote: fixedpoint.NewFromFloat(529.5858061), - Confirm: fixedpoint.Zero, + StartTime: types.NewMillisecondTimestampFromInt(1597026383085), + OpenPrice: fixedpoint.NewFromFloat(8533), + HighestPrice: fixedpoint.NewFromFloat(8553.74), + LowestPrice: fixedpoint.NewFromFloat(8527.17), + ClosePrice: fixedpoint.NewFromFloat(8548.26), + Volume: fixedpoint.NewFromFloat(45247), + VolumeInCurrency: fixedpoint.NewFromFloat(529.5858061), + //VolumeInCurrencyQuote: fixedpoint.NewFromFloat(529.5858061), + Confirm: fixedpoint.Zero, }, }, InstrumentID: "BTC-USDT", @@ -686,13 +686,13 @@ func TestKLine_ToGlobal(t *testing.T) { High: exp.Events[0].HighestPrice, Low: exp.Events[0].LowestPrice, Volume: exp.Events[0].Volume, - QuoteVolume: exp.Events[0].VolumeCcy, + QuoteVolume: exp.Events[0].VolumeInCurrency, TakerBuyBaseAssetVolume: fixedpoint.Zero, TakerBuyQuoteAssetVolume: fixedpoint.Zero, LastTradeID: 0, NumberOfTrades: 0, Closed: false, - }, event.Events[0].ToGlobal(types.Interval(event.Interval), event.Symbol)) + }, kLineToGlobal(event.Events[0], types.Interval(event.Interval), event.Symbol)) }) } diff --git a/pkg/exchange/okex/stream.go b/pkg/exchange/okex/stream.go index 92fee6c47..6c64ee188 100644 --- a/pkg/exchange/okex/stream.go +++ b/pkg/exchange/okex/stream.go @@ -252,7 +252,7 @@ func (s *Stream) handleMarketTradeEvent(data []MarketTradeEvent) { func (s *Stream) handleKLineEvent(k KLineEvent) { for _, event := range k.Events { - kline := event.ToGlobal(types.Interval(k.Interval), k.Symbol) + kline := kLineToGlobal(event, types.Interval(k.Interval), k.Symbol) if kline.Closed { s.EmitKLineClosed(kline) } else {