From f7d3fca1ec753b9d294ed5bf5d12fa0afba67312 Mon Sep 17 00:00:00 2001 From: c9s Date: Wed, 12 Apr 2023 14:56:33 +0800 Subject: [PATCH] maxapi: simplify ticker response parsing --- go.sum | 1 + pkg/exchange/max/exchange.go | 32 ++-- pkg/exchange/max/maxapi/get_ticker_request.go | 20 +++ .../maxapi/get_ticker_request_requestgen.go | 154 ++++++++++++++++++ pkg/exchange/max/maxapi/public.go | 56 ++----- pkg/exchange/max/maxapi/reward_test.go | 9 + 6 files changed, 212 insertions(+), 60 deletions(-) create mode 100644 pkg/exchange/max/maxapi/get_ticker_request.go create mode 100644 pkg/exchange/max/maxapi/get_ticker_request_requestgen.go diff --git a/go.sum b/go.sum index 1655f216e..64dda1d23 100644 --- a/go.sum +++ b/go.sum @@ -935,6 +935,7 @@ golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= diff --git a/pkg/exchange/max/exchange.go b/pkg/exchange/max/exchange.go index 28573c589..5e53089c9 100644 --- a/pkg/exchange/max/exchange.go +++ b/pkg/exchange/max/exchange.go @@ -72,13 +72,13 @@ func (e *Exchange) QueryTicker(ctx context.Context, symbol string) (*types.Ticke return &types.Ticker{ Time: ticker.Time, - Volume: fixedpoint.MustNewFromString(ticker.Volume), - Last: fixedpoint.MustNewFromString(ticker.Last), - Open: fixedpoint.MustNewFromString(ticker.Open), - High: fixedpoint.MustNewFromString(ticker.High), - Low: fixedpoint.MustNewFromString(ticker.Low), - Buy: fixedpoint.MustNewFromString(ticker.Buy), - Sell: fixedpoint.MustNewFromString(ticker.Sell), + Volume: ticker.Volume, + Last: ticker.Last, + Open: ticker.Open, + High: ticker.High, + Low: ticker.Low, + Buy: ticker.Buy, + Sell: ticker.Sell, }, nil } @@ -112,15 +112,16 @@ func (e *Exchange) QueryTickers(ctx context.Context, symbol ...string) (map[stri if _, ok := m[toGlobalSymbol(k)]; len(symbol) != 0 && !ok { continue } + tickers[toGlobalSymbol(k)] = types.Ticker{ Time: v.Time, - Volume: fixedpoint.MustNewFromString(v.Volume), - Last: fixedpoint.MustNewFromString(v.Last), - Open: fixedpoint.MustNewFromString(v.Open), - High: fixedpoint.MustNewFromString(v.High), - Low: fixedpoint.MustNewFromString(v.Low), - Buy: fixedpoint.MustNewFromString(v.Buy), - Sell: fixedpoint.MustNewFromString(v.Sell), + Volume: v.Volume, + Last: v.Last, + Open: v.Open, + High: v.High, + Low: v.Low, + Buy: v.Buy, + Sell: v.Sell, } } } @@ -959,8 +960,7 @@ func (e *Exchange) QueryAveragePrice(ctx context.Context, symbol string) (fixedp return fixedpoint.Zero, err } - return fixedpoint.MustNewFromString(ticker.Sell). - Add(fixedpoint.MustNewFromString(ticker.Buy)).Div(Two), nil + return ticker.Sell.Add(ticker.Buy).Div(Two), nil } func (e *Exchange) RepayMarginAsset(ctx context.Context, asset string, amount fixedpoint.Value) error { diff --git a/pkg/exchange/max/maxapi/get_ticker_request.go b/pkg/exchange/max/maxapi/get_ticker_request.go new file mode 100644 index 000000000..7650e2002 --- /dev/null +++ b/pkg/exchange/max/maxapi/get_ticker_request.go @@ -0,0 +1,20 @@ +package max + +import ( + "github.com/c9s/requestgen" +) + +//go:generate -command GetRequest requestgen -method GET +//go:generate -command PostRequest requestgen -method POST +//go:generate -command DeleteRequest requestgen -method DELETE + +//go:generate GetRequest -url "/api/v2/tickers/:market" -type GetTickerRequest -responseType .Ticker +type GetTickerRequest struct { + client requestgen.APIClient + + market *string `param:"market,slug"` +} + +func (c *RestClient) NewGetTickerRequest() *GetTickerRequest { + return &GetTickerRequest{client: c} +} diff --git a/pkg/exchange/max/maxapi/get_ticker_request_requestgen.go b/pkg/exchange/max/maxapi/get_ticker_request_requestgen.go new file mode 100644 index 000000000..0f8329d72 --- /dev/null +++ b/pkg/exchange/max/maxapi/get_ticker_request_requestgen.go @@ -0,0 +1,154 @@ +// Code generated by "requestgen -method GET -url /api/v2/tickers/:market -type GetTickerRequest -responseType .Ticker"; DO NOT EDIT. + +package max + +import ( + "context" + "encoding/json" + "fmt" + "net/url" + "reflect" + "regexp" +) + +func (g *GetTickerRequest) Market(market string) *GetTickerRequest { + g.market = &market + return g +} + +// GetQueryParameters builds and checks the query parameters and returns url.Values +func (g *GetTickerRequest) GetQueryParameters() (url.Values, error) { + 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 (g *GetTickerRequest) 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 *GetTickerRequest) 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 *GetTickerRequest) 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 *GetTickerRequest) GetSlugParameters() (map[string]interface{}, error) { + var params = map[string]interface{}{} + // check market field -> json key market + if g.market != nil { + market := *g.market + + // assign parameter of market + params["market"] = market + + } + + return params, nil +} + +func (g *GetTickerRequest) 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 *GetTickerRequest) 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 *GetTickerRequest) isVarSlice(_v interface{}) bool { + rt := reflect.TypeOf(_v) + switch rt.Kind() { + case reflect.Slice: + return true + } + return false +} + +func (g *GetTickerRequest) 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 +} + +func (g *GetTickerRequest) Do(ctx context.Context) (*Ticker, error) { + + // no body params + var params interface{} + query := url.Values{} + + apiURL := "/api/v2/tickers/:market" + slugs, err := g.GetSlugsMap() + if err != nil { + return nil, err + } + + apiURL = g.applySlugsToUrl(apiURL, slugs) + + 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 Ticker + if err := response.DecodeJSON(&apiResponse); err != nil { + return nil, err + } + return &apiResponse, nil +} diff --git a/pkg/exchange/max/maxapi/public.go b/pkg/exchange/max/maxapi/public.go index b71fe9779..ffa14ce8d 100644 --- a/pkg/exchange/max/maxapi/public.go +++ b/pkg/exchange/max/maxapi/public.go @@ -3,7 +3,6 @@ package max import ( "context" "fmt" - "net/url" "strings" "time" @@ -34,15 +33,15 @@ type Market struct { type Ticker struct { Time time.Time - At int64 `json:"at"` - Buy string `json:"buy"` - Sell string `json:"sell"` - Open string `json:"open"` - High string `json:"high"` - Low string `json:"low"` - Last string `json:"last"` - Volume string `json:"vol"` - VolumeInBTC string `json:"vol_in_btc"` + At int64 `json:"at"` + Buy fixedpoint.Value `json:"buy"` + Sell fixedpoint.Value `json:"sell"` + Open fixedpoint.Value `json:"open"` + High fixedpoint.Value `json:"high"` + Low fixedpoint.Value `json:"low"` + Last fixedpoint.Value `json:"last"` + Volume fixedpoint.Value `json:"vol"` + VolumeInBTC fixedpoint.Value `json:"vol_in_btc"` } func (s *PublicService) Timestamp() (int64, error) { @@ -71,40 +70,9 @@ func (s *PublicService) Tickers() (TickerMap, error) { } func (s *PublicService) Ticker(market string) (*Ticker, error) { - var endPoint = "v2/tickers/" + market - req, err := s.client.NewRequest(context.Background(), "GET", endPoint, url.Values{}, nil) - if err != nil { - return nil, err - } - - response, err := s.client.SendRequest(req) - if err != nil { - return nil, err - } - - v, err := fastjson.ParseBytes(response.Body) - if err != nil { - return nil, err - } - - var ticker = mustParseTicker(v) - return &ticker, nil -} - -func mustParseTicker(v *fastjson.Value) Ticker { - var at = v.GetInt64("at") - return Ticker{ - Time: time.Unix(at, 0), - At: at, - Buy: string(v.GetStringBytes("buy")), - Sell: string(v.GetStringBytes("sell")), - Volume: string(v.GetStringBytes("vol")), - VolumeInBTC: string(v.GetStringBytes("vol_in_btc")), - Last: string(v.GetStringBytes("last")), - Open: string(v.GetStringBytes("open")), - High: string(v.GetStringBytes("high")), - Low: string(v.GetStringBytes("low")), - } + req := s.client.NewGetTickerRequest() + req.Market(market) + return req.Do(context.Background()) } type Interval int64 diff --git a/pkg/exchange/max/maxapi/reward_test.go b/pkg/exchange/max/maxapi/reward_test.go index e4d0c38e0..7bae06605 100644 --- a/pkg/exchange/max/maxapi/reward_test.go +++ b/pkg/exchange/max/maxapi/reward_test.go @@ -32,6 +32,15 @@ func TestPublicService(t *testing.T) { assert.NotEmpty(t, tickers) assert.NotEmpty(t, tickers["btcusdt"]) }) + + t.Run("v2/ticker/:market", func(t *testing.T) { + req := client.NewGetTickerRequest() + req.Market("btcusdt") + ticker, err := req.Do(ctx) + assert.NoError(t, err) + assert.NotNil(t, ticker) + assert.NotEmpty(t, ticker.Sell) + }) } func TestRewardService_GetRewardsRequest(t *testing.T) {