From 97336912e5910378501cb0edacd0ed9e1290e5c2 Mon Sep 17 00:00:00 2001 From: c9s Date: Fri, 2 Aug 2024 15:20:28 +0800 Subject: [PATCH] max: use v3/withdrawals apis --- pkg/exchange/max/maxapi/account.go | 6 +- .../maxapi/get_account_request_requestgen.go | 38 ++++++++- .../maxapi/get_accounts_request_requestgen.go | 38 ++++++++- .../get_deposit_history_request_requestgen.go | 38 ++++++++- .../get_vip_level_request_requestgen.go | 38 ++++++++- ...get_withdraw_history_request_requestgen.go | 77 ++++++++++++++----- pkg/priceresolver/simple.go | 2 +- pkg/priceresolver/simple_test.go | 10 +-- pkg/strategy/xalign/strategy.go | 8 ++ 9 files changed, 213 insertions(+), 42 deletions(-) diff --git a/pkg/exchange/max/maxapi/account.go b/pkg/exchange/max/maxapi/account.go index 018c87b90..cc0ae7925 100644 --- a/pkg/exchange/max/maxapi/account.go +++ b/pkg/exchange/max/maxapi/account.go @@ -201,14 +201,14 @@ type Withdraw struct { Notes string `json:"notes"` } -//go:generate GetRequest -url "v2/withdrawals" -type GetWithdrawHistoryRequest -responseType []Withdraw +//go:generate GetRequest -url "v3/withdrawals" -type GetWithdrawHistoryRequest -responseType []Withdraw type GetWithdrawHistoryRequest struct { client requestgen.AuthenticatedAPIClient - currency string `param:"currency"` + currency *string `param:"currency"` + state *string `param:"state"` // submitting, submitted, rejected, accepted, checking, refunded, canceled, suspect from *time.Time `param:"from,seconds"` // seconds to *time.Time `param:"to,seconds"` // seconds - state *string `param:"state"` // submitting, submitted, rejected, accepted, checking, refunded, canceled, suspect limit *int `param:"limit"` } diff --git a/pkg/exchange/max/maxapi/get_account_request_requestgen.go b/pkg/exchange/max/maxapi/get_account_request_requestgen.go index c69b72011..2141de6e8 100644 --- a/pkg/exchange/max/maxapi/get_account_request_requestgen.go +++ b/pkg/exchange/max/maxapi/get_account_request_requestgen.go @@ -119,13 +119,21 @@ func (g *GetAccountRequest) GetSlugsMap() (map[string]string, error) { return slugs, nil } +// GetPath returns the request path of the API +func (g *GetAccountRequest) GetPath() string { + return "v2/members/accounts/:currency" +} + +// Do generates the request object and send the request object to the API endpoint func (g *GetAccountRequest) Do(ctx context.Context) (*Account, error) { // no body params var params interface{} query := url.Values{} - apiURL := "v2/members/accounts/:currency" + var apiURL string + + apiURL = g.GetPath() slugs, err := g.GetSlugsMap() if err != nil { return nil, err @@ -144,8 +152,32 @@ func (g *GetAccountRequest) Do(ctx context.Context) (*Account, error) { } var apiResponse Account - if err := response.DecodeJSON(&apiResponse); err != nil { - return nil, err + + type responseUnmarshaler interface { + Unmarshal(data []byte) error + } + + if unmarshaler, ok := interface{}(&apiResponse).(responseUnmarshaler); ok { + if err := unmarshaler.Unmarshal(response.Body); err != nil { + return nil, err + } + } else { + // The line below checks the content type, however, some API server might not send the correct content type header, + // Hence, this is commented for backward compatibility + // response.IsJSON() + if err := response.DecodeJSON(&apiResponse); err != nil { + return nil, err + } + } + + type responseValidator interface { + Validate() error + } + + if validator, ok := interface{}(&apiResponse).(responseValidator); ok { + if err := validator.Validate(); err != nil { + return nil, err + } } return &apiResponse, nil } diff --git a/pkg/exchange/max/maxapi/get_accounts_request_requestgen.go b/pkg/exchange/max/maxapi/get_accounts_request_requestgen.go index 7e497c98c..04a02e275 100644 --- a/pkg/exchange/max/maxapi/get_accounts_request_requestgen.go +++ b/pkg/exchange/max/maxapi/get_accounts_request_requestgen.go @@ -109,13 +109,21 @@ func (g *GetAccountsRequest) GetSlugsMap() (map[string]string, error) { return slugs, nil } +// GetPath returns the request path of the API +func (g *GetAccountsRequest) GetPath() string { + return "v2/members/accounts" +} + +// Do generates the request object and send the request object to the API endpoint func (g *GetAccountsRequest) Do(ctx context.Context) ([]Account, error) { // no body params var params interface{} query := url.Values{} - apiURL := "v2/members/accounts" + var apiURL string + + apiURL = g.GetPath() req, err := g.client.NewAuthenticatedRequest(ctx, "GET", apiURL, query, params) if err != nil { @@ -128,8 +136,32 @@ func (g *GetAccountsRequest) Do(ctx context.Context) ([]Account, error) { } var apiResponse []Account - if err := response.DecodeJSON(&apiResponse); err != nil { - return nil, err + + type responseUnmarshaler interface { + Unmarshal(data []byte) error + } + + if unmarshaler, ok := interface{}(&apiResponse).(responseUnmarshaler); ok { + if err := unmarshaler.Unmarshal(response.Body); err != nil { + return nil, err + } + } else { + // The line below checks the content type, however, some API server might not send the correct content type header, + // Hence, this is commented for backward compatibility + // response.IsJSON() + if err := response.DecodeJSON(&apiResponse); err != nil { + return nil, err + } + } + + type responseValidator interface { + Validate() error + } + + if validator, ok := interface{}(&apiResponse).(responseValidator); ok { + if err := validator.Validate(); err != nil { + return nil, err + } } return apiResponse, nil } diff --git a/pkg/exchange/max/maxapi/get_deposit_history_request_requestgen.go b/pkg/exchange/max/maxapi/get_deposit_history_request_requestgen.go index a60f24f9a..8d80303f5 100644 --- a/pkg/exchange/max/maxapi/get_deposit_history_request_requestgen.go +++ b/pkg/exchange/max/maxapi/get_deposit_history_request_requestgen.go @@ -178,6 +178,12 @@ func (g *GetDepositHistoryRequest) GetSlugsMap() (map[string]string, error) { return slugs, nil } +// GetPath returns the request path of the API +func (g *GetDepositHistoryRequest) GetPath() string { + return "v2/deposits" +} + +// Do generates the request object and send the request object to the API endpoint func (g *GetDepositHistoryRequest) Do(ctx context.Context) ([]Deposit, error) { // empty params for GET operation @@ -187,7 +193,9 @@ func (g *GetDepositHistoryRequest) Do(ctx context.Context) ([]Deposit, error) { return nil, err } - apiURL := "v2/deposits" + var apiURL string + + apiURL = g.GetPath() req, err := g.client.NewAuthenticatedRequest(ctx, "GET", apiURL, query, params) if err != nil { @@ -200,8 +208,32 @@ func (g *GetDepositHistoryRequest) Do(ctx context.Context) ([]Deposit, error) { } var apiResponse []Deposit - if err := response.DecodeJSON(&apiResponse); err != nil { - return nil, err + + type responseUnmarshaler interface { + Unmarshal(data []byte) error + } + + if unmarshaler, ok := interface{}(&apiResponse).(responseUnmarshaler); ok { + if err := unmarshaler.Unmarshal(response.Body); err != nil { + return nil, err + } + } else { + // The line below checks the content type, however, some API server might not send the correct content type header, + // Hence, this is commented for backward compatibility + // response.IsJSON() + if err := response.DecodeJSON(&apiResponse); err != nil { + return nil, err + } + } + + type responseValidator interface { + Validate() error + } + + if validator, ok := interface{}(&apiResponse).(responseValidator); ok { + if err := validator.Validate(); err != nil { + return nil, err + } } return apiResponse, nil } diff --git a/pkg/exchange/max/maxapi/get_vip_level_request_requestgen.go b/pkg/exchange/max/maxapi/get_vip_level_request_requestgen.go index 790a9cd52..b2a27b64c 100644 --- a/pkg/exchange/max/maxapi/get_vip_level_request_requestgen.go +++ b/pkg/exchange/max/maxapi/get_vip_level_request_requestgen.go @@ -109,13 +109,21 @@ func (g *GetVipLevelRequest) GetSlugsMap() (map[string]string, error) { return slugs, nil } +// GetPath returns the request path of the API +func (g *GetVipLevelRequest) GetPath() string { + return "v2/members/vip_level" +} + +// Do generates the request object and send the request object to the API endpoint func (g *GetVipLevelRequest) Do(ctx context.Context) (*VipLevel, error) { // no body params var params interface{} query := url.Values{} - apiURL := "v2/members/vip_level" + var apiURL string + + apiURL = g.GetPath() req, err := g.client.NewAuthenticatedRequest(ctx, "GET", apiURL, query, params) if err != nil { @@ -128,8 +136,32 @@ func (g *GetVipLevelRequest) Do(ctx context.Context) (*VipLevel, error) { } var apiResponse VipLevel - if err := response.DecodeJSON(&apiResponse); err != nil { - return nil, err + + type responseUnmarshaler interface { + Unmarshal(data []byte) error + } + + if unmarshaler, ok := interface{}(&apiResponse).(responseUnmarshaler); ok { + if err := unmarshaler.Unmarshal(response.Body); err != nil { + return nil, err + } + } else { + // The line below checks the content type, however, some API server might not send the correct content type header, + // Hence, this is commented for backward compatibility + // response.IsJSON() + if err := response.DecodeJSON(&apiResponse); err != nil { + return nil, err + } + } + + type responseValidator interface { + Validate() error + } + + if validator, ok := interface{}(&apiResponse).(responseValidator); ok { + if err := validator.Validate(); err != nil { + return nil, err + } } return &apiResponse, nil } diff --git a/pkg/exchange/max/maxapi/get_withdraw_history_request_requestgen.go b/pkg/exchange/max/maxapi/get_withdraw_history_request_requestgen.go index 200e7ee81..91502e9fc 100644 --- a/pkg/exchange/max/maxapi/get_withdraw_history_request_requestgen.go +++ b/pkg/exchange/max/maxapi/get_withdraw_history_request_requestgen.go @@ -1,4 +1,4 @@ -// Code generated by "requestgen -method GET -url v2/withdrawals -type GetWithdrawHistoryRequest -responseType []Withdraw"; DO NOT EDIT. +// Code generated by "requestgen -method GET -url v3/withdrawals -type GetWithdrawHistoryRequest -responseType []Withdraw"; DO NOT EDIT. package max @@ -14,7 +14,12 @@ import ( ) func (g *GetWithdrawHistoryRequest) Currency(currency string) *GetWithdrawHistoryRequest { - g.currency = currency + g.currency = ¤cy + return g +} + +func (g *GetWithdrawHistoryRequest) State(state string) *GetWithdrawHistoryRequest { + g.state = &state return g } @@ -28,11 +33,6 @@ func (g *GetWithdrawHistoryRequest) To(to time.Time) *GetWithdrawHistoryRequest return g } -func (g *GetWithdrawHistoryRequest) State(state string) *GetWithdrawHistoryRequest { - g.state = &state - return g -} - func (g *GetWithdrawHistoryRequest) Limit(limit int) *GetWithdrawHistoryRequest { g.limit = &limit return g @@ -54,10 +54,21 @@ func (g *GetWithdrawHistoryRequest) GetQueryParameters() (url.Values, error) { func (g *GetWithdrawHistoryRequest) GetParameters() (map[string]interface{}, error) { var params = map[string]interface{}{} // check currency field -> json key currency - currency := g.currency + if g.currency != nil { + currency := *g.currency - // assign parameter of currency - params["currency"] = currency + // assign parameter of currency + params["currency"] = currency + } else { + } + // check state field -> json key state + if g.state != nil { + state := *g.state + + // assign parameter of state + params["state"] = state + } else { + } // check from field -> json key from if g.from != nil { from := *g.from @@ -76,14 +87,6 @@ func (g *GetWithdrawHistoryRequest) GetParameters() (map[string]interface{}, err params["to"] = strconv.FormatInt(to.Unix(), 10) } else { } - // check state field -> json key state - if g.state != nil { - state := *g.state - - // assign parameter of state - params["state"] = state - } else { - } // check limit field -> json key limit if g.limit != nil { limit := *g.limit @@ -175,6 +178,12 @@ func (g *GetWithdrawHistoryRequest) GetSlugsMap() (map[string]string, error) { return slugs, nil } +// GetPath returns the request path of the API +func (g *GetWithdrawHistoryRequest) GetPath() string { + return "v3/withdrawals" +} + +// Do generates the request object and send the request object to the API endpoint func (g *GetWithdrawHistoryRequest) Do(ctx context.Context) ([]Withdraw, error) { // empty params for GET operation @@ -184,7 +193,9 @@ func (g *GetWithdrawHistoryRequest) Do(ctx context.Context) ([]Withdraw, error) return nil, err } - apiURL := "v2/withdrawals" + var apiURL string + + apiURL = g.GetPath() req, err := g.client.NewAuthenticatedRequest(ctx, "GET", apiURL, query, params) if err != nil { @@ -197,8 +208,32 @@ func (g *GetWithdrawHistoryRequest) Do(ctx context.Context) ([]Withdraw, error) } var apiResponse []Withdraw - if err := response.DecodeJSON(&apiResponse); err != nil { - return nil, err + + type responseUnmarshaler interface { + Unmarshal(data []byte) error + } + + if unmarshaler, ok := interface{}(&apiResponse).(responseUnmarshaler); ok { + if err := unmarshaler.Unmarshal(response.Body); err != nil { + return nil, err + } + } else { + // The line below checks the content type, however, some API server might not send the correct content type header, + // Hence, this is commented for backward compatibility + // response.IsJSON() + if err := response.DecodeJSON(&apiResponse); err != nil { + return nil, err + } + } + + type responseValidator interface { + Validate() error + } + + if validator, ok := interface{}(&apiResponse).(responseValidator); ok { + if err := validator.Validate(); err != nil { + return nil, err + } } return apiResponse, nil } diff --git a/pkg/priceresolver/simple.go b/pkg/priceresolver/simple.go index c1a0f46b6..65b6ec51f 100644 --- a/pkg/priceresolver/simple.go +++ b/pkg/priceresolver/simple.go @@ -28,7 +28,7 @@ type SimplePriceResolver struct { mu sync.Mutex } -func NewPriceMap(markets types.MarketMap) *SimplePriceResolver { +func NewSimplePriceResolver(markets types.MarketMap) *SimplePriceResolver { return &SimplePriceResolver{ markets: markets, symbolPrices: make(map[string]fixedpoint.Value), diff --git a/pkg/priceresolver/simple_test.go b/pkg/priceresolver/simple_test.go index 439ae83a6..a5e9c68f2 100644 --- a/pkg/priceresolver/simple_test.go +++ b/pkg/priceresolver/simple_test.go @@ -38,7 +38,7 @@ func TestSimplePriceResolver(t *testing.T) { } t.Run("direct reference", func(t *testing.T) { - pm := NewPriceMap(markets) + pm := NewSimplePriceResolver(markets) pm.UpdateFromTrade(types.Trade{ Symbol: "BTCUSDT", Price: Number(48000.0), @@ -69,7 +69,7 @@ func TestSimplePriceResolver(t *testing.T) { }) t.Run("simple reference", func(t *testing.T) { - pm := NewPriceMap(markets) + pm := NewSimplePriceResolver(markets) pm.UpdateFromTrade(types.Trade{ Symbol: "BTCUSDT", Price: Number(48000.0), @@ -90,7 +90,7 @@ func TestSimplePriceResolver(t *testing.T) { }) t.Run("crypto reference", func(t *testing.T) { - pm := NewPriceMap(markets) + pm := NewSimplePriceResolver(markets) pm.UpdateFromTrade(types.Trade{ Symbol: "BTCUSDT", Price: Number(52000.0), @@ -111,7 +111,7 @@ func TestSimplePriceResolver(t *testing.T) { }) t.Run("inverse reference", func(t *testing.T) { - pm := NewPriceMap(markets) + pm := NewSimplePriceResolver(markets) pm.UpdateFromTrade(types.Trade{ Symbol: "BTCTWD", Price: Number(1536000.0), @@ -128,7 +128,7 @@ func TestSimplePriceResolver(t *testing.T) { }) t.Run("inverse reference", func(t *testing.T) { - pm := NewPriceMap(markets) + pm := NewSimplePriceResolver(markets) pm.UpdateFromTrade(types.Trade{ Symbol: "BTCTWD", Price: Number(1536000.0), diff --git a/pkg/strategy/xalign/strategy.go b/pkg/strategy/xalign/strategy.go index 4dde9dce9..73496b1eb 100644 --- a/pkg/strategy/xalign/strategy.go +++ b/pkg/strategy/xalign/strategy.go @@ -14,6 +14,7 @@ import ( "github.com/c9s/bbgo/pkg/bbgo" "github.com/c9s/bbgo/pkg/core" "github.com/c9s/bbgo/pkg/fixedpoint" + "github.com/c9s/bbgo/pkg/priceresolver" "github.com/c9s/bbgo/pkg/types" ) @@ -56,6 +57,8 @@ type Strategy struct { faultBalanceRecords map[string][]TimeBalance + priceResolver *priceresolver.SimplePriceResolver + sessions map[string]*bbgo.ExchangeSession orderBooks map[string]*bbgo.ActiveOrderBook @@ -350,6 +353,7 @@ func (s *Strategy) CrossRun(ctx context.Context, _ bbgo.OrderExecutionRouter, se s.orderStore = core.NewOrderStore("") + markets := types.MarketMap{} for _, sessionName := range s.PreferredSessions { session, ok := sessions[sessionName] if !ok { @@ -363,8 +367,12 @@ func (s *Strategy) CrossRun(ctx context.Context, _ bbgo.OrderExecutionRouter, se s.orderBooks[sessionName] = orderBook s.sessions[sessionName] = session + + // session.Market(symbol) } + s.priceResolver = priceresolver.NewSimplePriceResolver(markets) + bbgo.OnShutdown(ctx, func(ctx context.Context, wg *sync.WaitGroup) { defer wg.Done() for n, session := range s.sessions {