From ace2c55a17166d0b88d9c76b0679ee49e5c06eeb Mon Sep 17 00:00:00 2001 From: Edwin Date: Thu, 10 Aug 2023 15:02:30 +0800 Subject: [PATCH] exchange/bybit: add fee rate restful api --- pkg/exchange/bybit/bybitapi/client_test.go | 7 + .../bybit/bybitapi/get_fee_rates_request.go | 38 ++++ .../get_fee_rates_request_requestgen.go | 189 ++++++++++++++++++ 3 files changed, 234 insertions(+) create mode 100644 pkg/exchange/bybit/bybitapi/get_fee_rates_request.go create mode 100644 pkg/exchange/bybit/bybitapi/get_fee_rates_request_requestgen.go diff --git a/pkg/exchange/bybit/bybitapi/client_test.go b/pkg/exchange/bybit/bybitapi/client_test.go index 8156dd2c5..4a1403d38 100644 --- a/pkg/exchange/bybit/bybitapi/client_test.go +++ b/pkg/exchange/bybit/bybitapi/client_test.go @@ -173,4 +173,11 @@ func TestClient(t *testing.T) { assert.NoError(t, err) t.Logf("apiResp: %+v", apiResp.List) }) + + t.Run("GetFeeRatesRequest", func(t *testing.T) { + req := client.NewGetFeeRatesRequest() + apiResp, err := req.Do(ctx) + assert.NoError(t, err) + t.Logf("apiResp: %+v", apiResp) + }) } diff --git a/pkg/exchange/bybit/bybitapi/get_fee_rates_request.go b/pkg/exchange/bybit/bybitapi/get_fee_rates_request.go new file mode 100644 index 000000000..325316c9a --- /dev/null +++ b/pkg/exchange/bybit/bybitapi/get_fee_rates_request.go @@ -0,0 +1,38 @@ +package bybitapi + +import ( + "github.com/c9s/requestgen" + + "github.com/c9s/bbgo/pkg/fixedpoint" +) + +//go:generate -command GetRequest requestgen -method GET -responseType .APIResponse -responseDataField Result +//go:generate -command PostRequest requestgen -method POST -responseType .APIResponse -responseDataField Result + +type FeeRates struct { + List []FeeRate `json:"list"` +} + +type FeeRate struct { + Symbol string `json:"symbol"` + TakerFeeRate fixedpoint.Value `json:"takerFeeRate"` + MakerFeeRate fixedpoint.Value `json:"makerFeeRate"` +} + +//go:generate GetRequest -url "/v5/account/fee-rate" -type GetFeeRatesRequest -responseDataType .FeeRates +type GetFeeRatesRequest struct { + client requestgen.AuthenticatedAPIClient + + category Category `param:"category,query" validValues:"spot"` + // Symbol name. Valid for linear, inverse, spot + symbol *string `param:"symbol,query"` + // Base coin. SOL, BTC, ETH. Valid for option + baseCoin *string `param:"baseCoin,query"` +} + +func (c *RestClient) NewGetFeeRatesRequest() *GetFeeRatesRequest { + return &GetFeeRatesRequest{ + client: c, + category: CategorySpot, + } +} diff --git a/pkg/exchange/bybit/bybitapi/get_fee_rates_request_requestgen.go b/pkg/exchange/bybit/bybitapi/get_fee_rates_request_requestgen.go new file mode 100644 index 000000000..ac182c22a --- /dev/null +++ b/pkg/exchange/bybit/bybitapi/get_fee_rates_request_requestgen.go @@ -0,0 +1,189 @@ +// Code generated by "requestgen -method GET -responseType .APIResponse -responseDataField Result -url /v5/account/fee-rate -type GetFeeRatesRequest -responseDataType .FeeRates"; DO NOT EDIT. + +package bybitapi + +import ( + "context" + "encoding/json" + "fmt" + "net/url" + "reflect" + "regexp" +) + +func (g *GetFeeRatesRequest) Category(category Category) *GetFeeRatesRequest { + g.category = category + return g +} + +func (g *GetFeeRatesRequest) Symbol(symbol string) *GetFeeRatesRequest { + g.symbol = &symbol + return g +} + +func (g *GetFeeRatesRequest) BaseCoin(baseCoin string) *GetFeeRatesRequest { + g.baseCoin = &baseCoin + return g +} + +// GetQueryParameters builds and checks the query parameters and returns url.Values +func (g *GetFeeRatesRequest) GetQueryParameters() (url.Values, error) { + var params = map[string]interface{}{} + // check category field -> json key category + category := g.category + + // TEMPLATE check-valid-values + switch category { + case "spot": + params["category"] = category + + default: + return nil, fmt.Errorf("category value %v is invalid", category) + + } + // END TEMPLATE check-valid-values + + // assign parameter of category + params["category"] = category + // check symbol field -> json key symbol + if g.symbol != nil { + symbol := *g.symbol + + // assign parameter of symbol + params["symbol"] = symbol + } else { + } + // check baseCoin field -> json key baseCoin + if g.baseCoin != nil { + baseCoin := *g.baseCoin + + // assign parameter of baseCoin + params["baseCoin"] = baseCoin + } 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 *GetFeeRatesRequest) 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 *GetFeeRatesRequest) 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 *GetFeeRatesRequest) 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 *GetFeeRatesRequest) GetSlugParameters() (map[string]interface{}, error) { + var params = map[string]interface{}{} + + return params, nil +} + +func (g *GetFeeRatesRequest) 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 *GetFeeRatesRequest) 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 *GetFeeRatesRequest) isVarSlice(_v interface{}) bool { + rt := reflect.TypeOf(_v) + switch rt.Kind() { + case reflect.Slice: + return true + } + return false +} + +func (g *GetFeeRatesRequest) 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 *GetFeeRatesRequest) Do(ctx context.Context) (*FeeRates, error) { + + // no body params + var params interface{} + query, err := g.GetQueryParameters() + if err != nil { + return nil, err + } + + apiURL := "/v5/account/fee-rate" + + req, err := g.client.NewAuthenticatedRequest(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 + } + var data FeeRates + if err := json.Unmarshal(apiResponse.Result, &data); err != nil { + return nil, err + } + return &data, nil +}