mirror of
https://github.com/c9s/bbgo.git
synced 2024-09-20 08:11:08 +00:00
Merge pull request #553 from c9s/feature/max-order-history-api
refactor: rewrite max private trade query request with requestgen
This commit is contained in:
commit
6f810bf081
|
@ -204,7 +204,7 @@ func toGlobalTrade(t max.Trade) (*types.Trade, error) {
|
|||
var side = toGlobalSideType(t.Side)
|
||||
|
||||
// trade time
|
||||
mts := time.Unix(0, t.CreatedAtMilliSeconds*int64(time.Millisecond))
|
||||
mts := t.CreatedAtMilliSeconds
|
||||
|
||||
price, err := fixedpoint.NewFromString(t.Price)
|
||||
if err != nil {
|
||||
|
|
|
@ -876,7 +876,7 @@ func (e *Exchange) QueryTrades(ctx context.Context, symbol string, options *type
|
|||
return nil, err
|
||||
}
|
||||
|
||||
req := e.client.TradeService.NewPrivateTradeRequest()
|
||||
req := e.client.TradeService.NewGetPrivateTradeRequest()
|
||||
req.Market(toLocalSymbol(symbol))
|
||||
|
||||
if options.Limit > 0 {
|
||||
|
@ -899,11 +899,6 @@ func (e *Exchange) QueryTrades(ctx context.Context, symbol string, options *type
|
|||
return nil, err
|
||||
}
|
||||
|
||||
// ensure everything is sorted ascending
|
||||
sort.Slice(maxTrades, func(i, j int) bool {
|
||||
return maxTrades[i].CreatedAtMilliSeconds < maxTrades[j].CreatedAtMilliSeconds
|
||||
})
|
||||
|
||||
for _, t := range maxTrades {
|
||||
localTrade, err := toGlobalTrade(t)
|
||||
if err != nil {
|
||||
|
@ -914,6 +909,9 @@ func (e *Exchange) QueryTrades(ctx context.Context, symbol string, options *type
|
|||
trades = append(trades, *localTrade)
|
||||
}
|
||||
|
||||
// ensure everything is sorted ascending
|
||||
trades = types.SortTradesAscending(trades)
|
||||
|
||||
return trades, nil
|
||||
}
|
||||
|
||||
|
|
242
pkg/exchange/max/maxapi/get_private_trades_request_requestgen.go
Normal file
242
pkg/exchange/max/maxapi/get_private_trades_request_requestgen.go
Normal file
|
@ -0,0 +1,242 @@
|
|||
// Code generated by "requestgen -method GET -url v2/trades/my -type GetPrivateTradesRequest -responseType []Trade"; DO NOT EDIT.
|
||||
|
||||
package max
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
func (p *GetPrivateTradesRequest) Market(market string) *GetPrivateTradesRequest {
|
||||
p.market = market
|
||||
return p
|
||||
}
|
||||
|
||||
func (p *GetPrivateTradesRequest) Timestamp(timestamp time.Time) *GetPrivateTradesRequest {
|
||||
p.timestamp = ×tamp
|
||||
return p
|
||||
}
|
||||
|
||||
func (p *GetPrivateTradesRequest) From(from int64) *GetPrivateTradesRequest {
|
||||
p.from = &from
|
||||
return p
|
||||
}
|
||||
|
||||
func (p *GetPrivateTradesRequest) To(to int64) *GetPrivateTradesRequest {
|
||||
p.to = &to
|
||||
return p
|
||||
}
|
||||
|
||||
func (p *GetPrivateTradesRequest) OrderBy(orderBy string) *GetPrivateTradesRequest {
|
||||
p.orderBy = &orderBy
|
||||
return p
|
||||
}
|
||||
|
||||
func (p *GetPrivateTradesRequest) Pagination(pagination bool) *GetPrivateTradesRequest {
|
||||
p.pagination = &pagination
|
||||
return p
|
||||
}
|
||||
|
||||
func (p *GetPrivateTradesRequest) Limit(limit int64) *GetPrivateTradesRequest {
|
||||
p.limit = &limit
|
||||
return p
|
||||
}
|
||||
|
||||
func (p *GetPrivateTradesRequest) Offset(offset int64) *GetPrivateTradesRequest {
|
||||
p.offset = &offset
|
||||
return p
|
||||
}
|
||||
|
||||
// GetQueryParameters builds and checks the query parameters and returns url.Values
|
||||
func (p *GetPrivateTradesRequest) 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 (p *GetPrivateTradesRequest) GetParameters() (map[string]interface{}, error) {
|
||||
var params = map[string]interface{}{}
|
||||
// check market field -> json key market
|
||||
market := p.market
|
||||
|
||||
// assign parameter of market
|
||||
params["market"] = market
|
||||
// check timestamp field -> json key timestamp
|
||||
if p.timestamp != nil {
|
||||
timestamp := *p.timestamp
|
||||
|
||||
// assign parameter of timestamp
|
||||
// convert time.Time to seconds time stamp
|
||||
params["timestamp"] = strconv.FormatInt(timestamp.Unix(), 10)
|
||||
} else {
|
||||
}
|
||||
// check from field -> json key from
|
||||
if p.from != nil {
|
||||
from := *p.from
|
||||
|
||||
// assign parameter of from
|
||||
params["from"] = from
|
||||
} else {
|
||||
}
|
||||
// check to field -> json key to
|
||||
if p.to != nil {
|
||||
to := *p.to
|
||||
|
||||
// assign parameter of to
|
||||
params["to"] = to
|
||||
} else {
|
||||
}
|
||||
// check orderBy field -> json key order_by
|
||||
if p.orderBy != nil {
|
||||
orderBy := *p.orderBy
|
||||
|
||||
// assign parameter of orderBy
|
||||
params["order_by"] = orderBy
|
||||
} else {
|
||||
}
|
||||
// check pagination field -> json key pagination
|
||||
if p.pagination != nil {
|
||||
pagination := *p.pagination
|
||||
|
||||
// assign parameter of pagination
|
||||
params["pagination"] = pagination
|
||||
} else {
|
||||
}
|
||||
// check limit field -> json key limit
|
||||
if p.limit != nil {
|
||||
limit := *p.limit
|
||||
|
||||
// assign parameter of limit
|
||||
params["limit"] = limit
|
||||
} else {
|
||||
}
|
||||
// check offset field -> json key offset
|
||||
if p.offset != nil {
|
||||
offset := *p.offset
|
||||
|
||||
// assign parameter of offset
|
||||
params["offset"] = offset
|
||||
} else {
|
||||
}
|
||||
|
||||
return params, nil
|
||||
}
|
||||
|
||||
// GetParametersQuery converts the parameters from GetParameters into the url.Values format
|
||||
func (p *GetPrivateTradesRequest) GetParametersQuery() (url.Values, error) {
|
||||
query := url.Values{}
|
||||
|
||||
params, err := p.GetParameters()
|
||||
if err != nil {
|
||||
return query, err
|
||||
}
|
||||
|
||||
for k, v := range params {
|
||||
if p.isVarSlice(v) {
|
||||
p.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 (p *GetPrivateTradesRequest) GetParametersJSON() ([]byte, error) {
|
||||
params, err := p.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 (p *GetPrivateTradesRequest) GetSlugParameters() (map[string]interface{}, error) {
|
||||
var params = map[string]interface{}{}
|
||||
|
||||
return params, nil
|
||||
}
|
||||
|
||||
func (p *GetPrivateTradesRequest) 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 (p *GetPrivateTradesRequest) 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 (p *GetPrivateTradesRequest) isVarSlice(v interface{}) bool {
|
||||
rt := reflect.TypeOf(v)
|
||||
switch rt.Kind() {
|
||||
case reflect.Slice:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (p *GetPrivateTradesRequest) GetSlugsMap() (map[string]string, error) {
|
||||
slugs := map[string]string{}
|
||||
params, err := p.GetSlugParameters()
|
||||
if err != nil {
|
||||
return slugs, nil
|
||||
}
|
||||
|
||||
for k, v := range params {
|
||||
slugs[k] = fmt.Sprintf("%v", v)
|
||||
}
|
||||
|
||||
return slugs, nil
|
||||
}
|
||||
|
||||
func (p *GetPrivateTradesRequest) Do(ctx context.Context) ([]Trade, error) {
|
||||
|
||||
// empty params for GET operation
|
||||
var params interface{}
|
||||
query, err := p.GetParametersQuery()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
apiURL := "v2/trades/my"
|
||||
|
||||
req, err := p.client.NewAuthenticatedRequest(ctx, "GET", apiURL, query, params)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
response, err := p.client.SendRequest(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var apiResponse []Trade
|
||||
if err := response.DecodeJSON(&apiResponse); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return apiResponse, nil
|
||||
}
|
|
@ -1,11 +1,16 @@
|
|||
package max
|
||||
|
||||
//go:generate -command GetRequest requestgen -method GET
|
||||
//go:generate -command PostRequest requestgen -method POST
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/c9s/requestgen"
|
||||
|
||||
"github.com/c9s/bbgo/pkg/types"
|
||||
)
|
||||
|
||||
type MarkerInfo struct {
|
||||
|
@ -30,7 +35,7 @@ type Trade struct {
|
|||
Market string `json:"market" db:"market"`
|
||||
MarketName string `json:"market_name"`
|
||||
CreatedAt int64 `json:"created_at"`
|
||||
CreatedAtMilliSeconds int64 `json:"created_at_in_ms"`
|
||||
CreatedAtMilliSeconds types.MillisecondTimestamp `json:"created_at_in_ms"`
|
||||
Side string `json:"side" db:"side"`
|
||||
OrderID uint64 `json:"order_id"`
|
||||
Fee string `json:"fee" db:"fee"` // float number as string
|
||||
|
@ -111,8 +116,8 @@ func (options *QueryTradeOptions) Params() url.Values {
|
|||
return params
|
||||
}
|
||||
|
||||
func (s *TradeService) NewPrivateTradeRequest() *PrivateTradeRequest {
|
||||
return &PrivateTradeRequest{client: s.client}
|
||||
func (s *TradeService) NewGetPrivateTradeRequest() *GetPrivateTradesRequest {
|
||||
return &GetPrivateTradesRequest{client: s.client}
|
||||
}
|
||||
|
||||
type PrivateRequestParams struct {
|
||||
|
@ -120,120 +125,27 @@ type PrivateRequestParams struct {
|
|||
Path string `json:"path"`
|
||||
}
|
||||
|
||||
type PrivateTradeRequest struct {
|
||||
client *RestClient
|
||||
//go:generate GetRequest -url "v2/trades/my" -type GetPrivateTradesRequest -responseType []Trade
|
||||
type GetPrivateTradesRequest struct {
|
||||
client requestgen.AuthenticatedAPIClient
|
||||
|
||||
market *string
|
||||
market string `param:"market"`
|
||||
|
||||
// Timestamp is the seconds elapsed since Unix epoch, set to return trades executed before the time only
|
||||
timestamp *int64
|
||||
// timestamp is the seconds elapsed since Unix epoch, set to return trades executed before the time only
|
||||
timestamp *time.Time `param:"timestamp,seconds"`
|
||||
|
||||
// From field is a trade id, set ot return trades created after the trade
|
||||
from *int64
|
||||
from *int64 `param:"from"`
|
||||
|
||||
// To field trade id, set to return trades created before the trade
|
||||
to *int64
|
||||
to *int64 `param:"to"`
|
||||
|
||||
orderBy *string
|
||||
orderBy *string `param:"order_by"`
|
||||
|
||||
pagination *bool
|
||||
pagination *bool `param:"pagination"`
|
||||
|
||||
limit *int64
|
||||
limit *int64 `param:"limit"`
|
||||
|
||||
offset *int64
|
||||
}
|
||||
|
||||
func (r *PrivateTradeRequest) Market(market string) *PrivateTradeRequest {
|
||||
r.market = &market
|
||||
return r
|
||||
}
|
||||
|
||||
func (r *PrivateTradeRequest) From(from int64) *PrivateTradeRequest {
|
||||
r.from = &from
|
||||
return r
|
||||
}
|
||||
|
||||
func (r *PrivateTradeRequest) Timestamp(t int64) *PrivateTradeRequest {
|
||||
r.timestamp = &t
|
||||
return r
|
||||
}
|
||||
|
||||
func (r *PrivateTradeRequest) To(to int64) *PrivateTradeRequest {
|
||||
r.to = &to
|
||||
return r
|
||||
}
|
||||
|
||||
func (r *PrivateTradeRequest) Limit(limit int64) *PrivateTradeRequest {
|
||||
r.limit = &limit
|
||||
return r
|
||||
}
|
||||
|
||||
func (r *PrivateTradeRequest) Offset(offset int64) *PrivateTradeRequest {
|
||||
r.offset = &offset
|
||||
return r
|
||||
}
|
||||
|
||||
func (r *PrivateTradeRequest) Pagination(p bool) *PrivateTradeRequest {
|
||||
r.pagination = &p
|
||||
return r
|
||||
}
|
||||
|
||||
func (r *PrivateTradeRequest) OrderBy(orderBy string) *PrivateTradeRequest {
|
||||
r.orderBy = &orderBy
|
||||
return r
|
||||
}
|
||||
|
||||
func (r *PrivateTradeRequest) Do(ctx context.Context) (trades []Trade, err error) {
|
||||
if r.market == nil {
|
||||
return nil, errors.New("parameter market is mandatory")
|
||||
}
|
||||
|
||||
payload := map[string]interface{}{
|
||||
"market": r.market,
|
||||
}
|
||||
|
||||
if r.timestamp != nil {
|
||||
payload["timestamp"] = r.timestamp
|
||||
}
|
||||
|
||||
if r.from != nil {
|
||||
payload["from"] = r.from
|
||||
}
|
||||
|
||||
if r.to != nil {
|
||||
payload["to"] = r.to
|
||||
}
|
||||
|
||||
if r.orderBy != nil {
|
||||
payload["order_by"] = r.orderBy
|
||||
}
|
||||
|
||||
if r.pagination != nil {
|
||||
payload["pagination"] = r.pagination
|
||||
}
|
||||
|
||||
if r.limit != nil {
|
||||
payload["limit"] = r.limit
|
||||
}
|
||||
|
||||
if r.offset != nil {
|
||||
payload["offset"] = r.offset
|
||||
}
|
||||
|
||||
req, err := r.client.newAuthenticatedRequest(context.Background(), "GET", "v2/trades/my", nil, payload, nil)
|
||||
if err != nil {
|
||||
return trades, err
|
||||
}
|
||||
|
||||
response, err := r.client.SendRequest(req)
|
||||
if err != nil {
|
||||
return trades, err
|
||||
}
|
||||
|
||||
if err := response.DecodeJSON(&trades); err != nil {
|
||||
return trades, err
|
||||
}
|
||||
|
||||
return trades, err
|
||||
offset *int64 `param:"offset"`
|
||||
}
|
||||
|
||||
|
|
52
pkg/exchange/max/maxapi/trade_test.go
Normal file
52
pkg/exchange/max/maxapi/trade_test.go
Normal file
|
@ -0,0 +1,52 @@
|
|||
package max
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestTradeService(t *testing.T) {
|
||||
key, secret, ok := integrationTestConfigured(t, "MAX")
|
||||
if !ok {
|
||||
t.SkipNow()
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
client := NewRestClient(ProductionAPIURL)
|
||||
client.Auth(key, secret)
|
||||
|
||||
t.Run("default timestamp", func(t *testing.T) {
|
||||
req := client.TradeService.NewGetPrivateTradeRequest()
|
||||
until := time.Now().AddDate(0, -6, 0)
|
||||
|
||||
trades, err := req.Market("btcusdt").
|
||||
Timestamp(until).
|
||||
Do(ctx)
|
||||
if assert.NoError(t, err) {
|
||||
assert.NotEmptyf(t, trades, "got %d trades", len(trades))
|
||||
for _, td := range trades {
|
||||
t.Logf("trade: %+v", td)
|
||||
assert.True(t, td.CreatedAtMilliSeconds.Time().Before(until))
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("desc and pagination = false", func(t *testing.T) {
|
||||
req := client.TradeService.NewGetPrivateTradeRequest()
|
||||
trades, err := req.Market("btcusdt").
|
||||
Pagination(false).
|
||||
OrderBy("asc").
|
||||
Do(ctx)
|
||||
|
||||
if assert.NoError(t, err) {
|
||||
assert.NotEmptyf(t, trades, "got %d trades", len(trades))
|
||||
for _, td := range trades {
|
||||
t.Logf("trade: %+v", td)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
Loading…
Reference in New Issue
Block a user