From f77d03d270ff2874d1a165bf729e46f763eea0ca Mon Sep 17 00:00:00 2001 From: edwin Date: Mon, 5 Feb 2024 12:11:36 +0800 Subject: [PATCH] pkg/exchange: update borrow/repay api changes --- .../binance/binanceapi/client_test.go | 21 ++ ...get_margin_borrow_repay_history_request.go | 64 +++++ ...orrow_repay_history_request_requestgen.go} | 79 ++++-- ...rgin_borrow_repay_history_request_test.go} | 2 +- .../get_margin_loan_history_request.go | 54 ---- ..._margin_loan_history_request_requestgen.go | 234 ------------------ .../get_margin_repay_history_request.go | 47 ---- .../get_margin_repay_history_request_test.go | 29 --- pkg/exchange/binance/convert_margin.go | 22 -- pkg/exchange/binance/margin_history.go | 74 +++--- 10 files changed, 177 insertions(+), 449 deletions(-) create mode 100644 pkg/exchange/binance/binanceapi/get_margin_borrow_repay_history_request.go rename pkg/exchange/binance/binanceapi/{get_margin_repay_history_request_requestgen.go => get_margin_borrow_repay_history_request_requestgen.go} (58%) rename pkg/exchange/binance/binanceapi/{get_margin_loan_history_request_test.go => get_margin_borrow_repay_history_request_test.go} (91%) delete mode 100644 pkg/exchange/binance/binanceapi/get_margin_loan_history_request.go delete mode 100644 pkg/exchange/binance/binanceapi/get_margin_loan_history_request_requestgen.go delete mode 100644 pkg/exchange/binance/binanceapi/get_margin_repay_history_request.go delete mode 100644 pkg/exchange/binance/binanceapi/get_margin_repay_history_request_test.go diff --git a/pkg/exchange/binance/binanceapi/client_test.go b/pkg/exchange/binance/binanceapi/client_test.go index 746a6676d5..3e1221ab40 100644 --- a/pkg/exchange/binance/binanceapi/client_test.go +++ b/pkg/exchange/binance/binanceapi/client_test.go @@ -176,3 +176,24 @@ func TestClient_NewTransferAssetRequest(t *testing.T) { assert.NotEmpty(t, res) t.Logf("result: %+v", res) } + +func TestClient_GetMarginBorrowRepayHistoryRequest(t *testing.T) { + client := getTestClientOrSkip(t) + ctx := context.Background() + + err := client.SetTimeOffsetFromServer(ctx) + assert.NoError(t, err) + + req := client.NewGetMarginBorrowRepayHistoryRequest() + end := time.Now() + start := end.Add(-24 * time.Hour * 30) + req.StartTime(start) + req.EndTime(end) + req.Asset("BTC") + req.SetBorrowRepayType(BorrowRepayTypeBorrow) + res, err := req.Do(ctx) + assert.NoError(t, err) + assert.NotNil(t, res) + assert.NotEmpty(t, res) + t.Logf("result: %+v", res) +} diff --git a/pkg/exchange/binance/binanceapi/get_margin_borrow_repay_history_request.go b/pkg/exchange/binance/binanceapi/get_margin_borrow_repay_history_request.go new file mode 100644 index 0000000000..686a9b4b34 --- /dev/null +++ b/pkg/exchange/binance/binanceapi/get_margin_borrow_repay_history_request.go @@ -0,0 +1,64 @@ +package binanceapi + +import ( + "time" + + "github.com/c9s/requestgen" + + "github.com/c9s/bbgo/pkg/fixedpoint" + "github.com/c9s/bbgo/pkg/types" +) + +// one of PENDING (pending execution), CONFIRMED (successfully loaned), FAILED (execution failed, nothing happened to your account); +type MarginBorrowStatus string + +const ( + BorrowRepayStatusPending MarginBorrowStatus = "PENDING" + BorrowRepayStatusConfirmed MarginBorrowStatus = "CONFIRMED" + BorrowRepayStatusFailed MarginBorrowStatus = "FAILED" +) + +type BorrowRepayType string + +const ( + BorrowRepayTypeBorrow BorrowRepayType = "BORROW" + BorrowRepayTypeRepay BorrowRepayType = "REPAY" +) + +type MarginBorrowRepayRecord struct { + IsolatedSymbol string `json:"isolatedSymbol"` + Amount fixedpoint.Value `json:"amount"` + Asset string `json:"asset"` + Interest fixedpoint.Value `json:"interest"` + Principal fixedpoint.Value `json:"principal"` + Status MarginBorrowStatus `json:"status"` + Timestamp types.MillisecondTimestamp `json:"timestamp"` + TxId uint64 `json:"txId"` +} + +// GetMarginBorrowRepayHistoryRequest +// +// txId or startTime must be sent. txId takes precedence. +// Response in descending order +// If isolatedSymbol is not sent, crossed margin data will be returned +// The max interval between startTime and endTime is 30 days. +// If startTime and endTime not sent, return records of the last 7 days by default +// Set archived to true to query data from 6 months ago +// +//go:generate requestgen -method GET -url "/sapi/v1/margin/borrow-repay" -type GetMarginBorrowRepayHistoryRequest -responseType .RowsResponse -responseDataField Rows -responseDataType []MarginBorrowRepayRecord +type GetMarginBorrowRepayHistoryRequest struct { + client requestgen.AuthenticatedAPIClient + + asset string `param:"asset"` + startTime *time.Time `param:"startTime,milliseconds"` + endTime *time.Time `param:"endTime,milliseconds"` + isolatedSymbol *string `param:"isolatedSymbol"` + archived *bool `param:"archived"` + size *int `param:"size"` + current *int `param:"current"` + BorrowRepayType BorrowRepayType `param:"type"` +} + +func (c *RestClient) NewGetMarginBorrowRepayHistoryRequest() *GetMarginBorrowRepayHistoryRequest { + return &GetMarginBorrowRepayHistoryRequest{client: c} +} diff --git a/pkg/exchange/binance/binanceapi/get_margin_repay_history_request_requestgen.go b/pkg/exchange/binance/binanceapi/get_margin_borrow_repay_history_request_requestgen.go similarity index 58% rename from pkg/exchange/binance/binanceapi/get_margin_repay_history_request_requestgen.go rename to pkg/exchange/binance/binanceapi/get_margin_borrow_repay_history_request_requestgen.go index 17e5364155..a85fc3ae05 100644 --- a/pkg/exchange/binance/binanceapi/get_margin_repay_history_request_requestgen.go +++ b/pkg/exchange/binance/binanceapi/get_margin_borrow_repay_history_request_requestgen.go @@ -1,4 +1,4 @@ -// Code generated by "requestgen -method GET -url /sapi/v1/margin/repay -type GetMarginRepayHistoryRequest -responseType .RowsResponse -responseDataField Rows -responseDataType []MarginRepayRecord"; DO NOT EDIT. +// Code generated by "requestgen -method GET -url /sapi/v1/margin/borrow-repay -type GetMarginBorrowRepayHistoryRequest -responseType .RowsResponse -responseDataField Rows -responseDataType []MarginBorrowRepayRecord"; DO NOT EDIT. package binanceapi @@ -13,43 +13,48 @@ import ( "time" ) -func (g *GetMarginRepayHistoryRequest) Asset(asset string) *GetMarginRepayHistoryRequest { +func (g *GetMarginBorrowRepayHistoryRequest) Asset(asset string) *GetMarginBorrowRepayHistoryRequest { g.asset = asset return g } -func (g *GetMarginRepayHistoryRequest) StartTime(startTime time.Time) *GetMarginRepayHistoryRequest { +func (g *GetMarginBorrowRepayHistoryRequest) StartTime(startTime time.Time) *GetMarginBorrowRepayHistoryRequest { g.startTime = &startTime return g } -func (g *GetMarginRepayHistoryRequest) EndTime(endTime time.Time) *GetMarginRepayHistoryRequest { +func (g *GetMarginBorrowRepayHistoryRequest) EndTime(endTime time.Time) *GetMarginBorrowRepayHistoryRequest { g.endTime = &endTime return g } -func (g *GetMarginRepayHistoryRequest) IsolatedSymbol(isolatedSymbol string) *GetMarginRepayHistoryRequest { +func (g *GetMarginBorrowRepayHistoryRequest) IsolatedSymbol(isolatedSymbol string) *GetMarginBorrowRepayHistoryRequest { g.isolatedSymbol = &isolatedSymbol return g } -func (g *GetMarginRepayHistoryRequest) Archived(archived bool) *GetMarginRepayHistoryRequest { +func (g *GetMarginBorrowRepayHistoryRequest) Archived(archived bool) *GetMarginBorrowRepayHistoryRequest { g.archived = &archived return g } -func (g *GetMarginRepayHistoryRequest) Size(size int) *GetMarginRepayHistoryRequest { +func (g *GetMarginBorrowRepayHistoryRequest) Size(size int) *GetMarginBorrowRepayHistoryRequest { g.size = &size return g } -func (g *GetMarginRepayHistoryRequest) Current(current int) *GetMarginRepayHistoryRequest { +func (g *GetMarginBorrowRepayHistoryRequest) Current(current int) *GetMarginBorrowRepayHistoryRequest { g.current = ¤t return g } +func (g *GetMarginBorrowRepayHistoryRequest) SetBorrowRepayType(BorrowRepayType BorrowRepayType) *GetMarginBorrowRepayHistoryRequest { + g.BorrowRepayType = BorrowRepayType + return g +} + // GetQueryParameters builds and checks the query parameters and returns url.Values -func (g *GetMarginRepayHistoryRequest) GetQueryParameters() (url.Values, error) { +func (g *GetMarginBorrowRepayHistoryRequest) GetQueryParameters() (url.Values, error) { var params = map[string]interface{}{} query := url.Values{} @@ -61,7 +66,7 @@ func (g *GetMarginRepayHistoryRequest) GetQueryParameters() (url.Values, error) } // GetParameters builds and checks the parameters and return the result in a map object -func (g *GetMarginRepayHistoryRequest) GetParameters() (map[string]interface{}, error) { +func (g *GetMarginBorrowRepayHistoryRequest) GetParameters() (map[string]interface{}, error) { var params = map[string]interface{}{} // check asset field -> json key asset asset := g.asset @@ -118,12 +123,28 @@ func (g *GetMarginRepayHistoryRequest) GetParameters() (map[string]interface{}, params["current"] = current } else { } + // check BorrowRepayType field -> json key type + BorrowRepayType := g.BorrowRepayType + + // TEMPLATE check-valid-values + switch BorrowRepayType { + case BorrowRepayTypeBorrow, BorrowRepayTypeRepay: + params["type"] = BorrowRepayType + + default: + return nil, fmt.Errorf("type value %v is invalid", BorrowRepayType) + + } + // END TEMPLATE check-valid-values + + // assign parameter of BorrowRepayType + params["type"] = BorrowRepayType return params, nil } // GetParametersQuery converts the parameters from GetParameters into the url.Values format -func (g *GetMarginRepayHistoryRequest) GetParametersQuery() (url.Values, error) { +func (g *GetMarginBorrowRepayHistoryRequest) GetParametersQuery() (url.Values, error) { query := url.Values{} params, err := g.GetParameters() @@ -145,7 +166,7 @@ func (g *GetMarginRepayHistoryRequest) GetParametersQuery() (url.Values, error) } // GetParametersJSON converts the parameters from GetParameters into the JSON format -func (g *GetMarginRepayHistoryRequest) GetParametersJSON() ([]byte, error) { +func (g *GetMarginBorrowRepayHistoryRequest) GetParametersJSON() ([]byte, error) { params, err := g.GetParameters() if err != nil { return nil, err @@ -155,13 +176,13 @@ func (g *GetMarginRepayHistoryRequest) GetParametersJSON() ([]byte, error) { } // GetSlugParameters builds and checks the slug parameters and return the result in a map object -func (g *GetMarginRepayHistoryRequest) GetSlugParameters() (map[string]interface{}, error) { +func (g *GetMarginBorrowRepayHistoryRequest) GetSlugParameters() (map[string]interface{}, error) { var params = map[string]interface{}{} return params, nil } -func (g *GetMarginRepayHistoryRequest) applySlugsToUrl(url string, slugs map[string]string) string { +func (g *GetMarginBorrowRepayHistoryRequest) applySlugsToUrl(url string, slugs map[string]string) string { for _k, _v := range slugs { needleRE := regexp.MustCompile(":" + _k + "\\b") url = needleRE.ReplaceAllString(url, _v) @@ -170,7 +191,7 @@ func (g *GetMarginRepayHistoryRequest) applySlugsToUrl(url string, slugs map[str return url } -func (g *GetMarginRepayHistoryRequest) iterateSlice(slice interface{}, _f func(it interface{})) { +func (g *GetMarginBorrowRepayHistoryRequest) iterateSlice(slice interface{}, _f func(it interface{})) { sliceValue := reflect.ValueOf(slice) for _i := 0; _i < sliceValue.Len(); _i++ { it := sliceValue.Index(_i).Interface() @@ -178,7 +199,7 @@ func (g *GetMarginRepayHistoryRequest) iterateSlice(slice interface{}, _f func(i } } -func (g *GetMarginRepayHistoryRequest) isVarSlice(_v interface{}) bool { +func (g *GetMarginBorrowRepayHistoryRequest) isVarSlice(_v interface{}) bool { rt := reflect.TypeOf(_v) switch rt.Kind() { case reflect.Slice: @@ -187,7 +208,7 @@ func (g *GetMarginRepayHistoryRequest) isVarSlice(_v interface{}) bool { return false } -func (g *GetMarginRepayHistoryRequest) GetSlugsMap() (map[string]string, error) { +func (g *GetMarginBorrowRepayHistoryRequest) GetSlugsMap() (map[string]string, error) { slugs := map[string]string{} params, err := g.GetSlugParameters() if err != nil { @@ -201,7 +222,13 @@ func (g *GetMarginRepayHistoryRequest) GetSlugsMap() (map[string]string, error) return slugs, nil } -func (g *GetMarginRepayHistoryRequest) Do(ctx context.Context) ([]MarginRepayRecord, error) { +// GetPath returns the request path of the API +func (g *GetMarginBorrowRepayHistoryRequest) GetPath() string { + return "/sapi/v1/margin/borrow-repay" +} + +// Do generates the request object and send the request object to the API endpoint +func (g *GetMarginBorrowRepayHistoryRequest) Do(ctx context.Context) ([]MarginBorrowRepayRecord, error) { // empty params for GET operation var params interface{} @@ -210,7 +237,9 @@ func (g *GetMarginRepayHistoryRequest) Do(ctx context.Context) ([]MarginRepayRec return nil, err } - apiURL := "/sapi/v1/margin/repay" + var apiURL string + + apiURL = g.GetPath() req, err := g.client.NewAuthenticatedRequest(ctx, "GET", apiURL, query, params) if err != nil { @@ -226,7 +255,17 @@ func (g *GetMarginRepayHistoryRequest) Do(ctx context.Context) ([]MarginRepayRec if err := response.DecodeJSON(&apiResponse); err != nil { return nil, err } - var data []MarginRepayRecord + + type responseValidator interface { + Validate() error + } + validator, ok := interface{}(apiResponse).(responseValidator) + if ok { + if err := validator.Validate(); err != nil { + return nil, err + } + } + var data []MarginBorrowRepayRecord if err := json.Unmarshal(apiResponse.Rows, &data); err != nil { return nil, err } diff --git a/pkg/exchange/binance/binanceapi/get_margin_loan_history_request_test.go b/pkg/exchange/binance/binanceapi/get_margin_borrow_repay_history_request_test.go similarity index 91% rename from pkg/exchange/binance/binanceapi/get_margin_loan_history_request_test.go rename to pkg/exchange/binance/binanceapi/get_margin_borrow_repay_history_request_test.go index c9daa028f1..4d58c3f914 100644 --- a/pkg/exchange/binance/binanceapi/get_margin_loan_history_request_test.go +++ b/pkg/exchange/binance/binanceapi/get_margin_borrow_repay_history_request_test.go @@ -15,7 +15,7 @@ func Test_GetMarginLoanHistoryRequest(t *testing.T) { err := client.SetTimeOffsetFromServer(ctx) assert.NoError(t, err) - req := client.NewGetMarginLoanHistoryRequest() + req := client.NewGetMarginBorrowRepayHistoryRequest() req.Asset("USDT") req.IsolatedSymbol("DOTUSDT") req.StartTime(time.Date(2022, time.February, 1, 0, 0, 0, 0, time.UTC)) diff --git a/pkg/exchange/binance/binanceapi/get_margin_loan_history_request.go b/pkg/exchange/binance/binanceapi/get_margin_loan_history_request.go deleted file mode 100644 index e7a801a9dd..0000000000 --- a/pkg/exchange/binance/binanceapi/get_margin_loan_history_request.go +++ /dev/null @@ -1,54 +0,0 @@ -package binanceapi - -import ( - "time" - - "github.com/c9s/requestgen" - - "github.com/c9s/bbgo/pkg/fixedpoint" - "github.com/c9s/bbgo/pkg/types" -) - -// one of PENDING (pending execution), CONFIRMED (successfully loaned), FAILED (execution failed, nothing happened to your account); -type LoanStatus string - -const ( - LoanStatusPending LoanStatus = "PENDING" - LoanStatusConfirmed LoanStatus = "CONFIRMED" - LoanStatusFailed LoanStatus = "FAILED" -) - -type MarginLoanRecord struct { - IsolatedSymbol string `json:"isolatedSymbol"` - TxId int64 `json:"txId"` - Asset string `json:"asset"` - Principal fixedpoint.Value `json:"principal"` - Timestamp types.MillisecondTimestamp `json:"timestamp"` - Status LoanStatus `json:"status"` -} - -// GetMarginLoanHistoryRequest -// -// txId or startTime must be sent. txId takes precedence. -// Response in descending order -// If isolatedSymbol is not sent, crossed margin data will be returned -// The max interval between startTime and endTime is 30 days. -// If startTime and endTime not sent, return records of the last 7 days by default -// Set archived to true to query data from 6 months ago -// -//go:generate requestgen -method GET -url "/sapi/v1/margin/loan" -type GetMarginLoanHistoryRequest -responseType .RowsResponse -responseDataField Rows -responseDataType []MarginLoanRecord -type GetMarginLoanHistoryRequest struct { - client requestgen.AuthenticatedAPIClient - - asset string `param:"asset"` - startTime *time.Time `param:"startTime,milliseconds"` - endTime *time.Time `param:"endTime,milliseconds"` - isolatedSymbol *string `param:"isolatedSymbol"` - archived *bool `param:"archived"` - size *int `param:"size"` - current *int `param:"current"` -} - -func (c *RestClient) NewGetMarginLoanHistoryRequest() *GetMarginLoanHistoryRequest { - return &GetMarginLoanHistoryRequest{client: c} -} diff --git a/pkg/exchange/binance/binanceapi/get_margin_loan_history_request_requestgen.go b/pkg/exchange/binance/binanceapi/get_margin_loan_history_request_requestgen.go deleted file mode 100644 index d893d55f57..0000000000 --- a/pkg/exchange/binance/binanceapi/get_margin_loan_history_request_requestgen.go +++ /dev/null @@ -1,234 +0,0 @@ -// Code generated by "requestgen -method GET -url /sapi/v1/margin/loan -type GetMarginLoanHistoryRequest -responseType .RowsResponse -responseDataField Rows -responseDataType []MarginLoanRecord"; DO NOT EDIT. - -package binanceapi - -import ( - "context" - "encoding/json" - "fmt" - "net/url" - "reflect" - "regexp" - "strconv" - "time" -) - -func (g *GetMarginLoanHistoryRequest) Asset(asset string) *GetMarginLoanHistoryRequest { - g.asset = asset - return g -} - -func (g *GetMarginLoanHistoryRequest) StartTime(startTime time.Time) *GetMarginLoanHistoryRequest { - g.startTime = &startTime - return g -} - -func (g *GetMarginLoanHistoryRequest) EndTime(endTime time.Time) *GetMarginLoanHistoryRequest { - g.endTime = &endTime - return g -} - -func (g *GetMarginLoanHistoryRequest) IsolatedSymbol(isolatedSymbol string) *GetMarginLoanHistoryRequest { - g.isolatedSymbol = &isolatedSymbol - return g -} - -func (g *GetMarginLoanHistoryRequest) Archived(archived bool) *GetMarginLoanHistoryRequest { - g.archived = &archived - return g -} - -func (g *GetMarginLoanHistoryRequest) Size(size int) *GetMarginLoanHistoryRequest { - g.size = &size - return g -} - -func (g *GetMarginLoanHistoryRequest) Current(current int) *GetMarginLoanHistoryRequest { - g.current = ¤t - return g -} - -// GetQueryParameters builds and checks the query parameters and returns url.Values -func (g *GetMarginLoanHistoryRequest) 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 *GetMarginLoanHistoryRequest) GetParameters() (map[string]interface{}, error) { - var params = map[string]interface{}{} - // check asset field -> json key asset - asset := g.asset - - // assign parameter of asset - params["asset"] = asset - // check startTime field -> json key startTime - if g.startTime != nil { - startTime := *g.startTime - - // assign parameter of startTime - // convert time.Time to milliseconds time stamp - params["startTime"] = strconv.FormatInt(startTime.UnixNano()/int64(time.Millisecond), 10) - } else { - } - // check endTime field -> json key endTime - if g.endTime != nil { - endTime := *g.endTime - - // assign parameter of endTime - // convert time.Time to milliseconds time stamp - params["endTime"] = strconv.FormatInt(endTime.UnixNano()/int64(time.Millisecond), 10) - } else { - } - // check isolatedSymbol field -> json key isolatedSymbol - if g.isolatedSymbol != nil { - isolatedSymbol := *g.isolatedSymbol - - // assign parameter of isolatedSymbol - params["isolatedSymbol"] = isolatedSymbol - } else { - } - // check archived field -> json key archived - if g.archived != nil { - archived := *g.archived - - // assign parameter of archived - params["archived"] = archived - } else { - } - // check size field -> json key size - if g.size != nil { - size := *g.size - - // assign parameter of size - params["size"] = size - } else { - } - // check current field -> json key current - if g.current != nil { - current := *g.current - - // assign parameter of current - params["current"] = current - } else { - } - - return params, nil -} - -// GetParametersQuery converts the parameters from GetParameters into the url.Values format -func (g *GetMarginLoanHistoryRequest) 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 *GetMarginLoanHistoryRequest) 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 *GetMarginLoanHistoryRequest) GetSlugParameters() (map[string]interface{}, error) { - var params = map[string]interface{}{} - - return params, nil -} - -func (g *GetMarginLoanHistoryRequest) 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 *GetMarginLoanHistoryRequest) 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 *GetMarginLoanHistoryRequest) isVarSlice(_v interface{}) bool { - rt := reflect.TypeOf(_v) - switch rt.Kind() { - case reflect.Slice: - return true - } - return false -} - -func (g *GetMarginLoanHistoryRequest) 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 *GetMarginLoanHistoryRequest) Do(ctx context.Context) ([]MarginLoanRecord, error) { - - // empty params for GET operation - var params interface{} - query, err := g.GetParametersQuery() - if err != nil { - return nil, err - } - - apiURL := "/sapi/v1/margin/loan" - - 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 RowsResponse - if err := response.DecodeJSON(&apiResponse); err != nil { - return nil, err - } - var data []MarginLoanRecord - if err := json.Unmarshal(apiResponse.Rows, &data); err != nil { - return nil, err - } - return data, nil -} diff --git a/pkg/exchange/binance/binanceapi/get_margin_repay_history_request.go b/pkg/exchange/binance/binanceapi/get_margin_repay_history_request.go deleted file mode 100644 index 6d9a13448b..0000000000 --- a/pkg/exchange/binance/binanceapi/get_margin_repay_history_request.go +++ /dev/null @@ -1,47 +0,0 @@ -package binanceapi - -import ( - "time" - - "github.com/c9s/requestgen" - - "github.com/c9s/bbgo/pkg/fixedpoint" - "github.com/c9s/bbgo/pkg/types" -) - -// RepayStatus one of PENDING (pending execution), CONFIRMED (successfully loaned), FAILED (execution failed, nothing happened to your account); -type RepayStatus string - -const ( - RepayStatusPending LoanStatus = "PENDING" - RepayStatusConfirmed LoanStatus = "CONFIRMED" - RepayStatusFailed LoanStatus = "FAILED" -) - -type MarginRepayRecord struct { - IsolatedSymbol string `json:"isolatedSymbol"` - Amount fixedpoint.Value `json:"amount"` - Asset string `json:"asset"` - Interest fixedpoint.Value `json:"interest"` - Principal fixedpoint.Value `json:"principal"` - Status string `json:"status"` - Timestamp types.MillisecondTimestamp `json:"timestamp"` - TxId uint64 `json:"txId"` -} - -//go:generate requestgen -method GET -url "/sapi/v1/margin/repay" -type GetMarginRepayHistoryRequest -responseType .RowsResponse -responseDataField Rows -responseDataType []MarginRepayRecord -type GetMarginRepayHistoryRequest struct { - client requestgen.AuthenticatedAPIClient - - asset string `param:"asset"` - startTime *time.Time `param:"startTime,milliseconds"` - endTime *time.Time `param:"endTime,milliseconds"` - isolatedSymbol *string `param:"isolatedSymbol"` - archived *bool `param:"archived"` - size *int `param:"size"` - current *int `param:"current"` -} - -func (c *RestClient) NewGetMarginRepayHistoryRequest() *GetMarginRepayHistoryRequest { - return &GetMarginRepayHistoryRequest{client: c} -} diff --git a/pkg/exchange/binance/binanceapi/get_margin_repay_history_request_test.go b/pkg/exchange/binance/binanceapi/get_margin_repay_history_request_test.go deleted file mode 100644 index 5161d32ff1..0000000000 --- a/pkg/exchange/binance/binanceapi/get_margin_repay_history_request_test.go +++ /dev/null @@ -1,29 +0,0 @@ -package binanceapi - -import ( - "context" - "testing" - "time" - - "github.com/stretchr/testify/assert" -) - -func Test_GetMarginRepayHistoryRequest(t *testing.T) { - client := getTestClientOrSkip(t) - ctx := context.Background() - - err := client.SetTimeOffsetFromServer(ctx) - assert.NoError(t, err) - - req := client.NewGetMarginRepayHistoryRequest() - req.Asset("USDT") - req.IsolatedSymbol("DOTUSDT") - req.StartTime(time.Date(2022, time.February, 1, 0, 0, 0, 0, time.UTC)) - req.EndTime(time.Date(2022, time.March, 1, 0, 0, 0, 0, time.UTC)) - req.Size(100) - - records, err := req.Do(ctx) - assert.NoError(t, err) - assert.NotEmpty(t, records) - t.Logf("loans: %+v", records) -} diff --git a/pkg/exchange/binance/convert_margin.go b/pkg/exchange/binance/convert_margin.go index e04bad07e1..10680f32d2 100644 --- a/pkg/exchange/binance/convert_margin.go +++ b/pkg/exchange/binance/convert_margin.go @@ -8,28 +8,6 @@ import ( "github.com/c9s/bbgo/pkg/types" ) -func toGlobalLoan(record binanceapi.MarginLoanRecord) types.MarginLoan { - return types.MarginLoan{ - Exchange: types.ExchangeBinance, - TransactionID: uint64(record.TxId), - Asset: record.Asset, - Principle: record.Principal, - Time: types.Time(record.Timestamp), - IsolatedSymbol: record.IsolatedSymbol, - } -} - -func toGlobalRepay(record binanceapi.MarginRepayRecord) types.MarginRepay { - return types.MarginRepay{ - Exchange: types.ExchangeBinance, - TransactionID: record.TxId, - Asset: record.Asset, - Principle: record.Principal, - Time: types.Time(record.Timestamp), - IsolatedSymbol: record.IsolatedSymbol, - } -} - func toGlobalInterest(record binanceapi.MarginInterest) types.MarginInterest { return types.MarginInterest{ Exchange: types.ExchangeBinance, diff --git a/pkg/exchange/binance/margin_history.go b/pkg/exchange/binance/margin_history.go index 5408e04ba5..b33889d46d 100644 --- a/pkg/exchange/binance/margin_history.go +++ b/pkg/exchange/binance/margin_history.go @@ -2,16 +2,31 @@ package binance import ( "context" + "fmt" "time" + "github.com/c9s/bbgo/pkg/exchange/binance/binanceapi" "github.com/c9s/bbgo/pkg/types" ) -func (e *Exchange) QueryLoanHistory(ctx context.Context, asset string, startTime, endTime *time.Time) ([]types.MarginLoan, error) { - req := e.client2.NewGetMarginLoanHistoryRequest() +type BorrowRepayType interface { + types.MarginLoan | types.MarginRepay +} + +func queryBorrowRepayHistory[T BorrowRepayType](e *Exchange, ctx context.Context, asset string, startTime, endTime *time.Time) ([]T, error) { + req := e.client2.NewGetMarginBorrowRepayHistoryRequest() req.Asset(asset) req.Size(100) + switch v := any(T{}); v.(type) { + case types.MarginLoan: + req.SetBorrowRepayType(binanceapi.BorrowRepayTypeBorrow) + case types.MarginRepay: + req.SetBorrowRepayType(binanceapi.BorrowRepayTypeRepay) + default: + return nil, fmt.Errorf("T is other type") + } + if startTime != nil { req.StartTime(*startTime) @@ -42,52 +57,27 @@ func (e *Exchange) QueryLoanHistory(ctx context.Context, asset string, startTime return nil, err } - var loans []types.MarginLoan + var borrowRepay []T for _, record := range records { - loans = append(loans, toGlobalLoan(record)) + borrowRepay = append(borrowRepay, T{ + Exchange: types.ExchangeBinance, + TransactionID: record.TxId, + Asset: record.Asset, + Principle: record.Principal, + Time: types.Time(record.Timestamp), + IsolatedSymbol: record.IsolatedSymbol, + }) } - return loans, err + return borrowRepay, nil } -func (e *Exchange) QueryRepayHistory(ctx context.Context, asset string, startTime, endTime *time.Time) ([]types.MarginRepay, error) { - req := e.client2.NewGetMarginRepayHistoryRequest() - req.Asset(asset) - req.Size(100) - - if startTime != nil { - req.StartTime(*startTime) - - // 6 months - if time.Since(*startTime) > time.Hour*24*30*6 { - req.Archived(true) - } - } - - if startTime != nil && endTime != nil { - duration := endTime.Sub(*startTime) - if duration > time.Hour*24*30 { - t := startTime.Add(time.Hour * 24 * 30) - endTime = &t - } - } - - if endTime != nil { - req.EndTime(*endTime) - } - - if e.MarginSettings.IsIsolatedMargin { - req.IsolatedSymbol(e.MarginSettings.IsolatedMarginSymbol) - } - - records, err := req.Do(ctx) - - var repays []types.MarginRepay - for _, record := range records { - repays = append(repays, toGlobalRepay(record)) - } +func (e *Exchange) QueryLoanHistory(ctx context.Context, asset string, startTime, endTime *time.Time) ([]types.MarginLoan, error) { + return queryBorrowRepayHistory[types.MarginLoan](e, ctx, asset, startTime, endTime) +} - return repays, err +func (e *Exchange) QueryRepayHistory(ctx context.Context, asset string, startTime, endTime *time.Time) ([]types.MarginRepay, error) { + return queryBorrowRepayHistory[types.MarginRepay](e, ctx, asset, startTime, endTime) } func (e *Exchange) QueryLiquidationHistory(ctx context.Context, startTime, endTime *time.Time) ([]types.MarginLiquidation, error) {