mirror of
https://github.com/c9s/bbgo.git
synced 2024-11-10 09:11:55 +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)
|
var side = toGlobalSideType(t.Side)
|
||||||
|
|
||||||
// trade time
|
// trade time
|
||||||
mts := time.Unix(0, t.CreatedAtMilliSeconds*int64(time.Millisecond))
|
mts := t.CreatedAtMilliSeconds
|
||||||
|
|
||||||
price, err := fixedpoint.NewFromString(t.Price)
|
price, err := fixedpoint.NewFromString(t.Price)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -876,7 +876,7 @@ func (e *Exchange) QueryTrades(ctx context.Context, symbol string, options *type
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
req := e.client.TradeService.NewPrivateTradeRequest()
|
req := e.client.TradeService.NewGetPrivateTradeRequest()
|
||||||
req.Market(toLocalSymbol(symbol))
|
req.Market(toLocalSymbol(symbol))
|
||||||
|
|
||||||
if options.Limit > 0 {
|
if options.Limit > 0 {
|
||||||
|
@ -899,11 +899,6 @@ func (e *Exchange) QueryTrades(ctx context.Context, symbol string, options *type
|
||||||
return nil, err
|
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 {
|
for _, t := range maxTrades {
|
||||||
localTrade, err := toGlobalTrade(t)
|
localTrade, err := toGlobalTrade(t)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -914,6 +909,9 @@ func (e *Exchange) QueryTrades(ctx context.Context, symbol string, options *type
|
||||||
trades = append(trades, *localTrade)
|
trades = append(trades, *localTrade)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ensure everything is sorted ascending
|
||||||
|
trades = types.SortTradesAscending(trades)
|
||||||
|
|
||||||
return trades, nil
|
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
|
package max
|
||||||
|
|
||||||
|
//go:generate -command GetRequest requestgen -method GET
|
||||||
|
//go:generate -command PostRequest requestgen -method POST
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"net/url"
|
"net/url"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
"github.com/c9s/requestgen"
|
||||||
|
|
||||||
|
"github.com/c9s/bbgo/pkg/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
type MarkerInfo struct {
|
type MarkerInfo struct {
|
||||||
|
@ -30,7 +35,7 @@ type Trade struct {
|
||||||
Market string `json:"market" db:"market"`
|
Market string `json:"market" db:"market"`
|
||||||
MarketName string `json:"market_name"`
|
MarketName string `json:"market_name"`
|
||||||
CreatedAt int64 `json:"created_at"`
|
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"`
|
Side string `json:"side" db:"side"`
|
||||||
OrderID uint64 `json:"order_id"`
|
OrderID uint64 `json:"order_id"`
|
||||||
Fee string `json:"fee" db:"fee"` // float number as string
|
Fee string `json:"fee" db:"fee"` // float number as string
|
||||||
|
@ -111,8 +116,8 @@ func (options *QueryTradeOptions) Params() url.Values {
|
||||||
return params
|
return params
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *TradeService) NewPrivateTradeRequest() *PrivateTradeRequest {
|
func (s *TradeService) NewGetPrivateTradeRequest() *GetPrivateTradesRequest {
|
||||||
return &PrivateTradeRequest{client: s.client}
|
return &GetPrivateTradesRequest{client: s.client}
|
||||||
}
|
}
|
||||||
|
|
||||||
type PrivateRequestParams struct {
|
type PrivateRequestParams struct {
|
||||||
|
@ -120,120 +125,27 @@ type PrivateRequestParams struct {
|
||||||
Path string `json:"path"`
|
Path string `json:"path"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type PrivateTradeRequest struct {
|
//go:generate GetRequest -url "v2/trades/my" -type GetPrivateTradesRequest -responseType []Trade
|
||||||
client *RestClient
|
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 is the seconds elapsed since Unix epoch, set to return trades executed before the time only
|
||||||
timestamp *int64
|
timestamp *time.Time `param:"timestamp,seconds"`
|
||||||
|
|
||||||
// From field is a trade id, set ot return trades created after the trade
|
// 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 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
|
offset *int64 `param:"offset"`
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
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