From 91b5816f77b5c64bc9362b66b8c66275f469a556 Mon Sep 17 00:00:00 2001 From: ddxyq <657023321@qq.com> Date: Thu, 4 Jul 2024 14:59:50 +0800 Subject: [PATCH] complete sub-master interface(subaccount_service.go); complete spot market interface (#589) * complete sub-master interface(subaccount_service.go); complete spot market interface * fix typos check * gofmt * add some comment * use full name --- v2/client.go | 169 +++ v2/subaccount_service.go | 2418 ++++++++++++++++++++++++++++++++ v2/subaccount_service_test.go | 2459 +++++++++++++++++++++++++++++++++ v2/tradingDayTicker.go | 86 ++ v2/tradingDayTicker_test.go | 90 ++ v2/uiKlines_service.go | 114 ++ v2/uiKlines_service_test.go | 83 ++ 7 files changed, 5419 insertions(+) create mode 100644 v2/tradingDayTicker.go create mode 100644 v2/tradingDayTicker_test.go create mode 100644 v2/uiKlines_service.go create mode 100644 v2/uiKlines_service_test.go diff --git a/v2/client.go b/v2/client.go index 694b992a..0814a634 100644 --- a/v2/client.go +++ b/v2/client.go @@ -544,6 +544,10 @@ func (c *Client) NewKlinesService() *KlinesService { return &KlinesService{c: c} } +func (c *Client) NewUiKlinesService() *UiKlinesService { + return &UiKlinesService{c: c} +} + // NewListPriceChangeStatsService init list prices change stats service func (c *Client) NewListPriceChangeStatsService() *ListPriceChangeStatsService { return &ListPriceChangeStatsService{c: c} @@ -554,6 +558,10 @@ func (c *Client) NewListPricesService() *ListPricesService { return &ListPricesService{c: c} } +func (c *Client) NewTradingDayTickerService() *TradingDayTickerService { + return &TradingDayTickerService{c: c} +} + // NewListBookTickersService init listing booking tickers service func (c *Client) NewListBookTickersService() *ListBookTickersService { return &ListBookTickersService{c: c} @@ -1122,3 +1130,164 @@ func (c *Client) NewSubAccountTransferHistoryService() *SubAccountTransferHistor func (c *Client) NewListUserUniversalTransferService() *ListUserUniversalTransferService { return &ListUserUniversalTransferService{c: c} } + +// Create virtual sub-account +func (c *Client) NewCreateVirtualSubAccountService() *CreateVirtualSubAccountService { + return &CreateVirtualSubAccountService{c: c} +} + +// Sub-Account spot transfer history +func (c *Client) NewSubAccountSpotTransferHistoryService() *SubAccountSpotTransferHistoryService { + return &SubAccountSpotTransferHistoryService{c: c} +} + +// Sub-Account futures transfer history +func (c *Client) NewSubAccountFuturesTransferHistoryService() *SubAccountFuturesTransferHistoryService { + return &SubAccountFuturesTransferHistoryService{c: c} +} + +// Get sub account deposit record +func (c *Client) NewSubAccountDepositRecordService() *SubAccountDepositRecordService { + return &SubAccountDepositRecordService{c: c} +} + +// Get sub account margin futures status +func (c *Client) NewSubAccountMarginFuturesStatusService() *SubAccountMarginFuturesStatusService { + return &SubAccountMarginFuturesStatusService{c: c} +} + +// sub account margin enable +func (c *Client) NewSubAccountMarginEnableService() *SubAccountMarginEnableService { + return &SubAccountMarginEnableService{c: c} +} + +// get sub-account margin account detail +func (c *Client) NewSubAccountMarginAccountInfoService() *SubAccountMarginAccountInfoService { + return &SubAccountMarginAccountInfoService{c: c} +} + +// get sub-account margin account summary +func (c *Client) NewSubAccountMarginAccountSummaryService() *SubAccountMarginAccountSummaryService { + return &SubAccountMarginAccountSummaryService{c: c} +} + +func (c *Client) NewSubAccountFuturesEnableService() *SubAccountFuturesEnableService { + return &SubAccountFuturesEnableService{c: c} +} + +// get sub-account futures account summary, include U-M and C-M, v2 interface +func (c *Client) NewSubAccountFuturesAccountSummaryService() *SubAccountFuturesAccountSummaryService { + return &SubAccountFuturesAccountSummaryService{c: c} +} + +// get target sub-account futures position information, include U-M and C-M, v2 interface. +func (c *Client) NewSubAccountFuturesPositionsService() *SubAccountFuturesPositionsService { + return &SubAccountFuturesPositionsService{c: c} +} + +// execute sub-account margin account transfer +func (c *Client) NewSubAccountMarginTransferService() *SubAccountMarginTransferService { + return &SubAccountMarginTransferService{c: c} +} + +// sub-account transfer balance to master-account +func (c *Client) NewSubAccountTransferSubToMasterService() *SubAccountTransferSubToMasterService { + return &SubAccountTransferSubToMasterService{c: c} +} + +// Universal transfer of master and sub accounts +func (c *Client) NewSubAccountUniversalTransferService() *SubAccountUniversalTransferService { + return &SubAccountUniversalTransferService{c: c} +} + +// Query the universal transfer history of sub and master accounts +func (c *Client) NewSubAccUniversalTransferHistoryService() *SubAccUniversalTransferHistoryService { + return &SubAccUniversalTransferHistoryService{c: c} +} + +// Binance Leveraged Tokens enable +func (c *Client) NewSubAccountBlvtEnableService() *SubAccountBlvtEnableService { + return &SubAccountBlvtEnableService{c: c} +} + +// query sub-account api ip restriction +func (c *Client) NewSubAccountApiIpRestrictionService() *SubAccountApiIpRestrictionService { + return &SubAccountApiIpRestrictionService{c: c} +} + +// delete sub-account ip restriction +func (c *Client) NewSubAccountApiDeleteIpRestrictionService() *SubAccountApiDeleteIpRestrictionService { + return &SubAccountApiDeleteIpRestrictionService{c: c} +} + +// add sub-account ip restriction +func (c *Client) NewSubAccountApiAddIpRestrictionService() *SubAccountApiAddIpRestrictionService { + return &SubAccountApiAddIpRestrictionService{c: c} +} + +func (c *Client) NewManagedSubAccountWithdrawService() *ManagedSubAccountWithdrawService { + return &ManagedSubAccountWithdrawService{c: c} +} + +// Query asset snapshot of managed-sub account +func (c *Client) NewManagedSubAccountSnapshotService() *ManagedSubAccountSnapshotService { + return &ManagedSubAccountSnapshotService{c: c} +} + +// managed-sub account query transfer log, this interface is for investor +func (c *Client) NewManagedSubAccountQueryTransferLogForInvestorService() *ManagedSubAccountQueryTransferLogForInvestorService { + return &ManagedSubAccountQueryTransferLogForInvestorService{c: c} +} + +func (c *Client) NewManagedSubAccountQueryTransferLogForTradeParentService() *ManagedSubAccountQueryTransferLogForTradeParentService { + return &ManagedSubAccountQueryTransferLogForTradeParentService{c: c} +} + +// Investor account inquiry custody account futures assets +func (c *Client) NewManagedSubAccountQueryFuturesAssetService() *ManagedSubAccountQueryFuturesAssetService { + return &ManagedSubAccountQueryFuturesAssetService{c: c} +} + +// Investor account inquiry for leveraged assets in custodial accounts +func (c *Client) NewManagedSubAccountQueryMarginAssetService() *ManagedSubAccountQueryMarginAssetService { + return &ManagedSubAccountQueryMarginAssetService{c: c} +} + +// Query sub account assets, v4 interface. +func (c *Client) NewSubAccountAssetService() *SubAccountAssetService { + return &SubAccountAssetService{c: c} +} + +// Query the list of managed-accounts +func (c *Client) NewManagedSubAccountInfoService() *ManagedSubAccountInfoService { + return &ManagedSubAccountInfoService{c: c} +} + +// Obtain the recharge address for the custody account +func (c *Client) NewManagedSubAccountDepositAddressService() *ManagedSubAccountDepositAddressService { + return &ManagedSubAccountDepositAddressService{c: c} +} + +func (c *Client) NewSubAccountOptionsEnableService() *SubAccountOptionsEnableService { + return &SubAccountOptionsEnableService{c: c} +} + +// Query transfer records of managed-sub accounts +func (c *Client) NewManagedSubAccountQueryTransferLogService() *ManagedSubAccountQueryTransferLogService { + return &ManagedSubAccountQueryTransferLogService{c: c} +} + +// Execute sub account futures balance transfer +func (c *Client) NewSubAccountFuturesInternalTransferService() *SubAccountFuturesInternalTransferService { + return &SubAccountFuturesInternalTransferService{c: c} +} + +// Query sub account transaction volume statistics list +func (c *Client) NewSubAccountTransactionStatisticsService() *SubAccountTransactionStatisticsService { + return &SubAccountTransactionStatisticsService{c: c} +} + +// get the target sub-account futures account detail, v2 interface. +func (c *Client) NewSubAccountFuturesAccountV2Service() *SubAccountFuturesAccountV2Service { + return &SubAccountFuturesAccountV2Service{c: c} +} diff --git a/v2/subaccount_service.go b/v2/subaccount_service.go index 3384b52d..0893fcb5 100644 --- a/v2/subaccount_service.go +++ b/v2/subaccount_service.go @@ -765,3 +765,2421 @@ type SubAccountTransferHistory struct { TranID int64 `json:"tranId"` Time int64 `json:"time"` } + +// Create virtual sub-account +type CreateVirtualSubAccountService struct { + c *Client + subAccountString string + recvWindow *int64 +} + +type CreateVirtualSubAccountResponse struct { + Email string `json:"email"` +} + +func (s *CreateVirtualSubAccountService) SubAccountString(subAccountString string) *CreateVirtualSubAccountService { + s.subAccountString = subAccountString + return s +} + +func (s *CreateVirtualSubAccountService) RecvWindow(recvWindow int64) *CreateVirtualSubAccountService { + s.recvWindow = &recvWindow + return s +} + +func (s *CreateVirtualSubAccountService) Do(ctx context.Context, opts ...RequestOption) (res *CreateVirtualSubAccountResponse, err error) { + r := &request{ + method: http.MethodPost, + endpoint: "/sapi/v1/sub-account/virtualSubAccount", + secType: secTypeSigned, + } + r.setFormParam("subAccountString", s.subAccountString) + if s.recvWindow != nil { + r.recvWindow = *s.recvWindow + } + + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return nil, err + } + res = new(CreateVirtualSubAccountResponse) + err = json.Unmarshal(data, res) + if err != nil { + return nil, err + } + + return res, nil +} + +// Sub-Account spot transfer history +type SubAccountSpotTransferHistoryService struct { + c *Client + fromEmail *string // Sub-account email + toEmail *string // true or false + startTime *uint64 + endTime *uint64 + page *int32 // default 1 + limit *int32 // default 1, max 200 + recvWindow *int64 +} + +type SubAccountSpotTransfer struct { + From string `json:"from"` + To string `json:"to"` + Asset string `json:"asset"` + Qty string `json:"qty"` + Status string `json:"status"` + TranId uint64 `json:"tranId"` + Time uint64 `json:"time"` +} + +func (s *SubAccountSpotTransferHistoryService) FromEmail(fromEmail string) *SubAccountSpotTransferHistoryService { + s.fromEmail = &fromEmail + return s +} + +func (s *SubAccountSpotTransferHistoryService) ToEmail(toEmail string) *SubAccountSpotTransferHistoryService { + s.toEmail = &toEmail + return s +} + +func (s *SubAccountSpotTransferHistoryService) StartTime(startTime uint64) *SubAccountSpotTransferHistoryService { + s.startTime = &startTime + return s +} + +func (s *SubAccountSpotTransferHistoryService) EndTime(endTime uint64) *SubAccountSpotTransferHistoryService { + s.endTime = &endTime + return s +} + +func (s *SubAccountSpotTransferHistoryService) Page(page int32) *SubAccountSpotTransferHistoryService { + s.page = &page + return s +} + +func (s *SubAccountSpotTransferHistoryService) Limit(limit int32) *SubAccountSpotTransferHistoryService { + s.limit = &limit + return s +} + +func (s *SubAccountSpotTransferHistoryService) RecvWindow(recvWindow int64) *SubAccountSpotTransferHistoryService { + s.recvWindow = &recvWindow + return s +} + +func (s *SubAccountSpotTransferHistoryService) Do(ctx context.Context, opts ...RequestOption) (res []*SubAccountSpotTransfer, err error) { + r := &request{ + method: http.MethodGet, + endpoint: "/sapi/v1/sub-account/sub/transfer/history", + secType: secTypeSigned, + } + if s.fromEmail != nil { + r.setParam("fromEmail", *s.fromEmail) + } + if s.toEmail != nil { + r.setParam("toEmail", *s.toEmail) + } + if s.startTime != nil { + r.setParam("startTime", *s.startTime) + } + if s.endTime != nil { + r.setParam("endTime", *s.endTime) + } + if s.page != nil { + r.setParam("page", *s.page) + } + if s.limit != nil { + r.setParam("limit", *s.limit) + } + if s.recvWindow != nil { + r.recvWindow = *s.recvWindow + } + + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return nil, err + } + res = make([]*SubAccountSpotTransfer, 0) + err = json.Unmarshal(data, &res) + if err != nil { + return nil, err + } + + return res, nil +} + +// Sub-Account futures transfer history +type SubAccountFuturesTransferHistoryService struct { + c *Client + email string // Sub-account email + futuresType int64 // 1: usdt 2: coin + startTime *int64 + endTime *int64 + page *int32 // default 1 + limit *int32 // default 50, max 500 + recvWindow *int64 +} + +type SubAccountFuturesTransferHistoryResponse struct { + Success bool `json:"success"` + FuturesType int32 `json:"futuresType"` + Transfers []*SubAccountFuturesTransfer `json:"transfers"` +} + +type SubAccountFuturesTransfer struct { + From string `json:"from"` + To string `json:"to"` + Asset string `json:"asset"` + Qty string `json:"qty"` + Status string `json:"status"` + TranId uint64 `json:"tranId"` + Time uint64 `json:"time"` +} + +func (s *SubAccountFuturesTransferHistoryService) Email(email string) *SubAccountFuturesTransferHistoryService { + s.email = email + return s +} + +func (s *SubAccountFuturesTransferHistoryService) FuturesType(futuresType int64) *SubAccountFuturesTransferHistoryService { + s.futuresType = futuresType + return s +} + +func (s *SubAccountFuturesTransferHistoryService) StartTime(startTime int64) *SubAccountFuturesTransferHistoryService { + s.startTime = &startTime + return s +} + +func (s *SubAccountFuturesTransferHistoryService) EndTime(endTime int64) *SubAccountFuturesTransferHistoryService { + s.endTime = &endTime + return s +} + +func (s *SubAccountFuturesTransferHistoryService) Page(page int32) *SubAccountFuturesTransferHistoryService { + s.page = &page + return s +} + +func (s *SubAccountFuturesTransferHistoryService) Limit(limit int32) *SubAccountFuturesTransferHistoryService { + s.limit = &limit + return s +} + +func (s *SubAccountFuturesTransferHistoryService) RecvWindow(recvWindow int64) *SubAccountFuturesTransferHistoryService { + s.recvWindow = &recvWindow + return s +} + +func (s *SubAccountFuturesTransferHistoryService) Do(ctx context.Context, opts ...RequestOption) (res *SubAccountFuturesTransferHistoryResponse, err error) { + r := &request{ + method: http.MethodGet, + endpoint: "/sapi/v1/sub-account/futures/internalTransfer", + secType: secTypeSigned, + } + r.setParam("email", s.email) + r.setParam("futuresType", s.futuresType) + if s.startTime != nil { + r.setParam("startTime", *s.startTime) + } + if s.endTime != nil { + r.setParam("endTime", *s.endTime) + } + if s.page != nil { + r.setParam("page", *s.page) + } + if s.limit != nil { + r.setParam("limit", *s.limit) + } + if s.recvWindow != nil { + r.recvWindow = *s.recvWindow + } + + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return nil, err + } + res = new(SubAccountFuturesTransferHistoryResponse) + err = json.Unmarshal(data, res) + if err != nil { + return nil, err + } + + return res, nil +} + +// Execute sub account futures balance transfer +type SubAccountFuturesInternalTransferService struct { + c *Client + fromEmail string // sender email + toEmail string // receiver email + futuresType int64 // 1: usdt 2: coin + asset string + amount string // decimal format + recvWindow *int64 +} + +type SubAccountFuturesInternalTransferResponse struct { + Success bool `json:"success"` + TxnId string `json:"txnId"` +} + +func (s *SubAccountFuturesInternalTransferService) FromEmail(fromEmail string) *SubAccountFuturesInternalTransferService { + s.fromEmail = fromEmail + return s +} + +func (s *SubAccountFuturesInternalTransferService) ToEmail(toEmail string) *SubAccountFuturesInternalTransferService { + s.toEmail = toEmail + return s +} + +func (s *SubAccountFuturesInternalTransferService) FuturesType(futuresType int64) *SubAccountFuturesInternalTransferService { + s.futuresType = futuresType + return s +} + +func (s *SubAccountFuturesInternalTransferService) Asset(asset string) *SubAccountFuturesInternalTransferService { + s.asset = asset + return s +} + +func (s *SubAccountFuturesInternalTransferService) Amount(amount string) *SubAccountFuturesInternalTransferService { + s.amount = amount + return s +} + +func (s *SubAccountFuturesInternalTransferService) RecvWindow(recvWindow int64) *SubAccountFuturesInternalTransferService { + s.recvWindow = &recvWindow + return s +} + +func (s *SubAccountFuturesInternalTransferService) Do(ctx context.Context, opts ...RequestOption) (res *SubAccountFuturesInternalTransferResponse, err error) { + r := &request{ + method: http.MethodPost, + endpoint: "/sapi/v1/sub-account/futures/internalTransfer", + secType: secTypeSigned, + } + r.setFormParam("fromEmail", s.fromEmail) + r.setFormParam("toEmail", s.toEmail) + r.setFormParam("futuresType", s.futuresType) + r.setFormParam("asset", s.asset) + r.setFormParam("amount", s.amount) + if s.recvWindow != nil { + r.recvWindow = *s.recvWindow + } + + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return nil, err + } + res = new(SubAccountFuturesInternalTransferResponse) + err = json.Unmarshal(data, res) + if err != nil { + return nil, err + } + + return res, nil +} + +// Get sub account deposit record +type SubAccountDepositRecordService struct { + c *Client + email string // sub-account email + coin *string + status *int32 // 0(0:pending,6: credited but cannot withdraw,7:Wrong Deposit,8:Waiting User confirm,1:success) + startTime *int64 + endTime *int64 + limit *int // sub-account email + offset *int // default 0 + txId *string + recvWindow *int64 +} + +type SubAccountDepositRecord struct { + Id string `json:"id"` + Amount string `json:"amount"` + Coin string `json:"coin"` + Network string `json:"network"` + Status int32 `json:"status"` + Address string `json:"address"` + TxId string `json:"txId"` + AddressTag string `json:"addressTag"` + InsertTime int64 `json:"insertTime"` + TransferType int32 `json:"transferType"` + ConfirmTimes string `json:"confirmTimes"` + UnlockConfirm int32 `json:"unlockConfirm"` + WalletType int32 `json:"walletType"` +} + +func (s *SubAccountDepositRecordService) Email(email string) *SubAccountDepositRecordService { + s.email = email + return s +} + +func (s *SubAccountDepositRecordService) Coin(coin string) *SubAccountDepositRecordService { + s.coin = &coin + return s +} + +func (s *SubAccountDepositRecordService) Status(status int32) *SubAccountDepositRecordService { + s.status = &status + return s +} + +func (s *SubAccountDepositRecordService) StartTime(startTime int64) *SubAccountDepositRecordService { + s.startTime = &startTime + return s +} + +func (s *SubAccountDepositRecordService) EndTime(endTime int64) *SubAccountDepositRecordService { + s.endTime = &endTime + return s +} + +func (s *SubAccountDepositRecordService) Limit(limit int) *SubAccountDepositRecordService { + s.limit = &limit + return s +} + +func (s *SubAccountDepositRecordService) Offset(offset int) *SubAccountDepositRecordService { + s.offset = &offset + return s +} + +func (s *SubAccountDepositRecordService) TxId(txId string) *SubAccountDepositRecordService { + s.txId = &txId + return s +} + +func (s *SubAccountDepositRecordService) RecvWindow(recvWindow int64) *SubAccountDepositRecordService { + s.recvWindow = &recvWindow + return s +} + +func (s *SubAccountDepositRecordService) Do(ctx context.Context, opts ...RequestOption) (res []*SubAccountDepositRecord, err error) { + r := &request{ + method: http.MethodGet, + endpoint: "/sapi/v1/capital/deposit/subHisrec", + secType: secTypeSigned, + } + r.setParam("email", s.email) + if s.coin != nil { + r.setParam("coin", *s.coin) + } + if s.status != nil { + r.setParam("status", *s.status) + } + if s.startTime != nil { + r.setParam("startTime", *s.startTime) + } + if s.endTime != nil { + r.setParam("endTime", *s.endTime) + } + if s.limit != nil { + r.setParam("limit", *s.limit) + } + if s.offset != nil { + r.setParam("offset", *s.offset) + } + if s.txId != nil { + r.setParam("txId", *s.txId) + } + if s.recvWindow != nil { + r.recvWindow = *s.recvWindow + } + + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return nil, err + } + res = make([]*SubAccountDepositRecord, 0) + err = json.Unmarshal(data, &res) + if err != nil { + return nil, err + } + + return res, nil +} + +// Get sub account margin futures status +type SubAccountMarginFuturesStatusService struct { + c *Client + email *string // sub-account email + recvWindow *int64 +} + +type SubAccountMarginFuturesStatus struct { + Email string `json:"email"` + IsSubUserEnabled bool `json:"isSubUserEnabled"` + IsUserActive bool `json:"isUserActive"` + InsertTime int64 `json:"insertTime"` + IsMarginEnabled bool `json:"isMarginEnabled"` + IsFutureEnabled bool `json:"isFutureEnabled"` + Mobile int64 `json:"mobile"` +} + +func (s *SubAccountMarginFuturesStatusService) Email(email string) *SubAccountMarginFuturesStatusService { + s.email = &email + return s +} + +func (s *SubAccountMarginFuturesStatusService) RecvWindow(recvWindow int64) *SubAccountMarginFuturesStatusService { + s.recvWindow = &recvWindow + return s +} + +func (s *SubAccountMarginFuturesStatusService) Do(ctx context.Context, opts ...RequestOption) (res []*SubAccountMarginFuturesStatus, err error) { + r := &request{ + method: http.MethodGet, + endpoint: "/sapi/v1/sub-account/status", + secType: secTypeSigned, + } + if s.email != nil { + r.setParam("email", *s.email) + } + if s.recvWindow != nil { + r.recvWindow = *s.recvWindow + } + + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return nil, err + } + res = make([]*SubAccountMarginFuturesStatus, 0) + err = json.Unmarshal(data, &res) + if err != nil { + return nil, err + } + + return res, nil +} + +// sub account margin enable +type SubAccountMarginEnableService struct { + c *Client + email string // sub-account email + recvWindow *int64 +} + +type SubAccountMarginEnableResponse struct { + Email string `json:"email"` + IsMarginEnabled bool `json:"isMarginEnabled"` +} + +func (s *SubAccountMarginEnableService) Email(email string) *SubAccountMarginEnableService { + s.email = email + return s +} + +func (s *SubAccountMarginEnableService) RecvWindow(recvWindow int64) *SubAccountMarginEnableService { + s.recvWindow = &recvWindow + return s +} + +func (s *SubAccountMarginEnableService) Do(ctx context.Context, opts ...RequestOption) (res *SubAccountMarginEnableResponse, err error) { + r := &request{ + method: http.MethodPost, + endpoint: "/sapi/v1/sub-account/margin/enable", + secType: secTypeSigned, + } + r.setFormParam("email", s.email) + if s.recvWindow != nil { + r.recvWindow = *s.recvWindow + } + + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return nil, err + } + res = new(SubAccountMarginEnableResponse) + err = json.Unmarshal(data, res) + if err != nil { + return nil, err + } + + return res, nil +} + +// get sub-account margin account detail +type SubAccountMarginAccountInfoService struct { + c *Client + email string // sub-account email + recvWindow *int64 +} + +type SubAccountMarginAccountInfo struct { + Email string `json:"email"` + MarginLevel string `json:"marginLevel"` + TotalAssetOfBtc string `json:"totalAssetOfBtc"` + TotalLiabilityOfBtc string `json:"totalLiabilityOfBtc"` + TotalNetAssetOfBtc string `json:"totalNetAssetOfBtc"` + MarginTradeCoeffVo *MarginTradeCoeffVo `json:"marginTradeCoeffVo"` + MarginUserAssetVoList []*MarginUserAssetVo `json:"marginUserAssetVoList"` +} + +type MarginTradeCoeffVo struct { + ForceLiquidationBar string `json:"forceLiquidationBar"` + MarginCallBar string `json:"marginCallBar"` + NormalBar string `json:"normalBar"` +} + +type MarginUserAssetVo struct { + Asset string `json:"asset"` + Borrowed string `json:"borrowed"` + Free string `json:"free"` + Interest string `json:"interest"` + Locked string `json:"locked"` + NetAsset string `json:"netAsset"` +} + +func (s *SubAccountMarginAccountInfoService) Email(email string) *SubAccountMarginAccountInfoService { + s.email = email + return s +} + +func (s *SubAccountMarginAccountInfoService) RecvWindow(recvWindow int64) *SubAccountMarginAccountInfoService { + s.recvWindow = &recvWindow + return s +} + +func (s *SubAccountMarginAccountInfoService) Do(ctx context.Context, opts ...RequestOption) (res *SubAccountMarginAccountInfo, err error) { + r := &request{ + method: http.MethodGet, + endpoint: "/sapi/v1/sub-account/margin/account", + secType: secTypeSigned, + } + r.setParam("email", s.email) + if s.recvWindow != nil { + r.recvWindow = *s.recvWindow + } + + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return nil, err + } + res = new(SubAccountMarginAccountInfo) + err = json.Unmarshal(data, res) + if err != nil { + return nil, err + } + + return res, nil +} + +// get sub-account margin account summary +type SubAccountMarginAccountSummaryService struct { + c *Client + recvWindow *int64 +} + +type SubAccountMarginAccountSummary struct { + TotalAssetOfBtc string `json:"totalAssetOfBtc"` + TotalLiabilityOfBtc string `json:"totalLiabilityOfBtc"` + TotalNetAssetOfBtc string `json:"totalNetAssetOfBtc"` + SubAccountList []*MarginSubAccount `json:"subAccountList"` +} + +type MarginSubAccount struct { + Email string `json:"email"` + TotalAssetOfBtc string `json:"totalAssetOfBtc"` + TotalLiabilityOfBtc string `json:"totalLiabilityOfBtc"` + TotalNetAssetOfBtc string `json:"totalNetAssetOfBtc"` +} + +func (s *SubAccountMarginAccountSummaryService) RecvWindow(recvWindow int64) *SubAccountMarginAccountSummaryService { + s.recvWindow = &recvWindow + return s +} + +func (s *SubAccountMarginAccountSummaryService) Do(ctx context.Context, opts ...RequestOption) (res *SubAccountMarginAccountSummary, err error) { + r := &request{ + method: http.MethodGet, + endpoint: "/sapi/v1/sub-account/margin/accountSummary", + secType: secTypeSigned, + } + if s.recvWindow != nil { + r.recvWindow = *s.recvWindow + } + + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return nil, err + } + res = new(SubAccountMarginAccountSummary) + err = json.Unmarshal(data, res) + if err != nil { + return nil, err + } + + return res, nil +} + +type SubAccountFuturesEnableService struct { + c *Client + email string // sub-account email + recvWindow *int64 +} + +type SubAccountFuturesEnableResponse struct { + Email string `json:"email"` + IsFuturesEnabled bool `json:"isFuturesEnabled"` +} + +func (s *SubAccountFuturesEnableService) Email(email string) *SubAccountFuturesEnableService { + s.email = email + return s +} + +func (s *SubAccountFuturesEnableService) RecvWindow(recvWindow int64) *SubAccountFuturesEnableService { + s.recvWindow = &recvWindow + return s +} + +func (s *SubAccountFuturesEnableService) Do(ctx context.Context, opts ...RequestOption) (res *SubAccountFuturesEnableResponse, err error) { + r := &request{ + method: http.MethodPost, + endpoint: "/sapi/v1/sub-account/futures/enable", + secType: secTypeSigned, + } + r.setFormParam("email", s.email) + if s.recvWindow != nil { + r.recvWindow = *s.recvWindow + } + + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return nil, err + } + res = new(SubAccountFuturesEnableResponse) + err = json.Unmarshal(data, res) + if err != nil { + return nil, err + } + + return res, nil +} + +// get the target sub-account futures account detail, v2 interface. +type SubAccountFuturesAccountV2Service struct { + c *Client + email string // sub-account email + futuresType int32 // 1:USDT Margined Futures, 2:COIN Margined Futures + recvWindow *int64 +} + +type SubAccountFuturesAccountV2ServiceResponse struct { + FutureAccountResp *SubAccountFuturesAccountV2 `json:"futureAccountResp"` // set while futuresType=1(USDT margined) + DeliveryAccountResp *SubAccountDeliveryAccountV2 `json:"deliveryAccountResp"` // set while futuresType=2(COIN margined) +} + +type SubAccountFuturesAccountV2 struct { + Email string `json:"email"` + Asset string `json:"asset"` + Assets []*FuturesAsset `json:"assets"` + CanDeposit bool `json:"canDeposit"` + CanTrade bool `json:"canTrade"` + CanWithdraw bool `json:"canWithdraw"` + FeeTier int32 `json:"feeTier"` + MaxWithdrawAmount string `json:"maxWithdrawAmount"` + TotalInitialMargin string `json:"totalInitialMargin"` + TotalMaintenanceMargin string `json:"totalMaintenanceMargin"` + TotalMarginBalance string `json:"totalMarginBalance"` + TotalOpenOrderInitialMargin string `json:"totalOpenOrderInitialMargin"` + TotalPositionInitialMargin string `json:"totalPositionInitialMargin"` + TotalUnrealizedProfit string `json:"totalUnrealizedProfit"` + TotalWalletBalance string `json:"totalWalletBalance"` + UpdateTime int64 `json:"updateTime"` +} + +type SubAccountDeliveryAccountV2 struct { + Email string `json:"email"` + Assets []*FuturesAsset `json:"assets"` + CanDeposit bool `json:"canDeposit"` + CanTrade bool `json:"canTrade"` + CanWithdraw bool `json:"canWithdraw"` + FeeTier int32 `json:"feeTier"` + UpdateTime int64 `json:"updateTime"` +} + +type FuturesAsset struct { + Asset string `json:"asset"` + InitialMargin string `json:"initialMargin"` + MaintenanceMargin string `json:"maintenanceMargin"` + MarginBalance string `json:"marginBalance"` + MaxWithdrawAmount string `json:"maxWithdrawAmount"` + OpenOrderInitialMargin string `json:"openOrderInitialMargin"` + PositionInitialMargin string `json:"positionInitialMargin"` + UnrealizedProfit string `json:"unrealizedProfit"` + WalletBalance string `json:"walletBalance"` +} + +func (s *SubAccountFuturesAccountV2Service) Email(email string) *SubAccountFuturesAccountV2Service { + s.email = email + return s +} + +func (s *SubAccountFuturesAccountV2Service) FuturesType(futuresType int32) *SubAccountFuturesAccountV2Service { + s.futuresType = futuresType + return s +} + +func (s *SubAccountFuturesAccountV2Service) RecvWindow(recvWindow int64) *SubAccountFuturesAccountV2Service { + s.recvWindow = &recvWindow + return s +} + +func (s *SubAccountFuturesAccountV2Service) Do(ctx context.Context, opts ...RequestOption) (res *SubAccountFuturesAccountV2ServiceResponse, err error) { + r := &request{ + method: http.MethodGet, + endpoint: "/sapi/v2/sub-account/futures/account", + secType: secTypeSigned, + } + r.setParam("email", s.email) + r.setParam("futuresType", s.futuresType) + if s.recvWindow != nil { + r.recvWindow = *s.recvWindow + } + + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return nil, err + } + res = new(SubAccountFuturesAccountV2ServiceResponse) + err = json.Unmarshal(data, res) + if err != nil { + return nil, err + } + + return res, nil +} + +// get sub-account futures account summary, include U-M and C-M, v2 interface +type SubAccountFuturesAccountSummaryService struct { + c *Client + futuresType int32 // 1:USDT Margined Futures, 2:COIN Margined Futures + page *int32 // default 1 + limit *int32 // default 10, max 20 + recvWindow *int64 +} + +type SubAccountFuturesAccountSummaryServiceResponse struct { + FutureAccountSummaryResp *SubAccountFuturesAccountSummary `json:"futureAccountSummaryResp"` // set while futuresType=1 + DeliveryAccountSummaryResp *SubAccountDeliveryAccountSummary `json:"deliveryAccountSummaryResp"` // set while futuresType=2 +} + +type SubAccountFuturesAccountSummary struct { + TotalInitialMargin string `json:"totalInitialMargin"` + TotalMaintenanceMargin string `json:"totalMaintenanceMargin"` + TotalMarginBalance string `json:"totalMarginBalance"` + TotalOpenOrderInitialMargin string `json:"totalOpenOrderInitialMargin"` + TotalPositionInitialMargin string `json:"totalPositionInitialMargin"` + TotalUnrealizedProfit string `json:"totalUnrealizedProfit"` + TotalWalletBalance string `json:"totalWalletBalance"` + Asset string `json:"asset"` + SubAccountList []*FuturesSubAccount `json:"subAccountList"` +} + +type FuturesSubAccount struct { + Email string `json:"email"` + TotalInitialMargin string `json:"totalInitialMargin"` + TotalMaintenanceMargin string `json:"totalMaintenanceMargin"` + TotalMarginBalance string `json:"totalMarginBalance"` + TotalOpenOrderInitialMargin string `json:"totalOpenOrderInitialMargin"` + TotalPositionInitialMargin string `json:"totalPositionInitialMargin"` + TotalUnrealizedProfit string `json:"totalUnrealizedProfit"` + TotalWalletBalance string `json:"totalWalletBalance"` + Asset string `json:"asset"` +} + +type SubAccountDeliveryAccountSummary struct { + TotalMarginBalanceOfBTC string `json:"totalMarginBalanceOfBTC"` + TotalUnrealizedProfitOfBTC string `json:"totalUnrealizedProfitOfBTC"` + TotalWalletBalanceOfBTC string `json:"totalWalletBalanceOfBTC"` + Asset string `json:"asset"` + SubAccountList []*DeliverySubAccount `json:"subAccountList"` +} + +type DeliverySubAccount struct { + Email string `json:"email"` + TotalMarginBalance string `json:"totalMarginBalance"` + TotalUnrealizedProfit string `json:"totalUnrealizedProfit"` + TotalWalletBalance string `json:"totalWalletBalance"` + Asset string `json:"asset"` +} + +func (s *SubAccountFuturesAccountSummaryService) FuturesType(futuresType int32) *SubAccountFuturesAccountSummaryService { + s.futuresType = futuresType + return s +} + +func (s *SubAccountFuturesAccountSummaryService) Page(page int32) *SubAccountFuturesAccountSummaryService { + s.page = &page + return s +} + +func (s *SubAccountFuturesAccountSummaryService) Limit(limit int32) *SubAccountFuturesAccountSummaryService { + s.limit = &limit + return s +} + +func (s *SubAccountFuturesAccountSummaryService) RecvWindow(recvWindow int64) *SubAccountFuturesAccountSummaryService { + s.recvWindow = &recvWindow + return s +} + +func (s *SubAccountFuturesAccountSummaryService) Do(ctx context.Context, opts ...RequestOption) (res *SubAccountFuturesAccountSummaryServiceResponse, err error) { + r := &request{ + method: http.MethodGet, + endpoint: "/sapi/v2/sub-account/futures/accountSummary", + secType: secTypeSigned, + } + r.setParam("futuresType", s.futuresType) + if s.page != nil { + r.setParam("page", *s.page) + } + if s.limit != nil { + r.setParam("limit", *s.limit) + } + if s.recvWindow != nil { + r.recvWindow = *s.recvWindow + } + + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return nil, err + } + res = new(SubAccountFuturesAccountSummaryServiceResponse) + err = json.Unmarshal(data, res) + if err != nil { + return nil, err + } + + return res, nil +} + +// get target sub-account futures position information, include U-M and C-M, v2 interface. +type SubAccountFuturesPositionsService struct { + c *Client + email string + futuresType int32 // 1:USDT Margined Futures, 2:COIN Margined Futures + recvWindow *int64 +} + +type SubAccountFuturesPositionsServiceResponse struct { + FuturePositionRiskVos []*SubAccountFuturesPosition `json:"futurePositionRiskVos"` // set while futuresType=1 + DeliveryPositionRiskVos []*SubAccountDeliveryPosition `json:"deliveryPositionRiskVos"` // set while futuresType=2 +} + +type SubAccountFuturesPosition struct { + EntryPrice string `json:"entryPrice"` + Leverage string `json:"leverage"` + MaxNotional string `json:"maxNotional"` + LiquidationPrice string `json:"liquidationPrice"` + MarkPrice string `json:"markPrice"` + PositionAmount string `json:"positionAmount"` + Symbol string `json:"symbol"` + UnrealizedProfit string `json:"unrealizedProfit"` +} + +type SubAccountDeliveryPosition struct { + EntryPrice string `json:"entryPrice"` + MarkPrice string `json:"markPrice"` + Leverage string `json:"leverage"` + Isolated string `json:"isolated"` + IsolatedWallet string `json:"isolatedWallet"` + IsolatedMargin string `json:"isolatedMargin"` + IsAutoAddMargin string `json:"isAutoAddMargin"` + PositionSide string `json:"positionSide"` + PositionAmount string `json:"positionAmount"` + Symbol string `json:"symbol"` + UnrealizedProfit string `json:"unrealizedProfit"` +} + +func (s *SubAccountFuturesPositionsService) Email(email string) *SubAccountFuturesPositionsService { + s.email = email + return s +} + +func (s *SubAccountFuturesPositionsService) FuturesType(futuresType int32) *SubAccountFuturesPositionsService { + s.futuresType = futuresType + return s +} + +func (s *SubAccountFuturesPositionsService) RecvWindow(recvWindow int64) *SubAccountFuturesPositionsService { + s.recvWindow = &recvWindow + return s +} + +func (s *SubAccountFuturesPositionsService) Do(ctx context.Context, opts ...RequestOption) (res *SubAccountFuturesPositionsServiceResponse, err error) { + r := &request{ + method: http.MethodGet, + endpoint: "/sapi/v2/sub-account/futures/positionRisk", + secType: secTypeSigned, + } + r.setParam("email", s.email) + r.setParam("futuresType", s.futuresType) + if s.recvWindow != nil { + r.recvWindow = *s.recvWindow + } + + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return nil, err + } + res = new(SubAccountFuturesPositionsServiceResponse) + err = json.Unmarshal(data, res) + if err != nil { + return nil, err + } + + return res, nil +} + +// execute sub-account margin account transfer +type SubAccountMarginTransferService struct { + c *Client + email string + asset string + amount string // decimal format + transferType int32 // 1: Transfer from the spot account of the sub account to its leverage account; 2: Transfer from the leverage account of the sub account to its spot account + recvWindow *int64 +} + +type SubAccountMarginTransferResponse struct { + TxnId string `json:"txnId"` +} + +func (s *SubAccountMarginTransferService) Email(email string) *SubAccountMarginTransferService { + s.email = email + return s +} + +func (s *SubAccountMarginTransferService) Asset(asset string) *SubAccountMarginTransferService { + s.asset = asset + return s +} + +func (s *SubAccountMarginTransferService) Amount(amount string) *SubAccountMarginTransferService { + s.amount = amount + return s +} + +func (s *SubAccountMarginTransferService) TransferType(transferType int32) *SubAccountMarginTransferService { + s.transferType = transferType + return s +} + +func (s *SubAccountMarginTransferService) RecvWindow(recvWindow int64) *SubAccountMarginTransferService { + s.recvWindow = &recvWindow + return s +} + +func (s *SubAccountMarginTransferService) Do(ctx context.Context, opts ...RequestOption) (res *SubAccountMarginTransferResponse, err error) { + r := &request{ + method: http.MethodPost, + endpoint: "/sapi/v1/sub-account/margin/transfer", + secType: secTypeSigned, + } + r.setFormParam("email", s.email) + r.setFormParam("asset", s.asset) + r.setFormParam("amount", s.amount) + r.setFormParam("type", s.transferType) + if s.recvWindow != nil { + r.recvWindow = *s.recvWindow + } + + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return nil, err + } + res = new(SubAccountMarginTransferResponse) + err = json.Unmarshal(data, res) + if err != nil { + return nil, err + } + + return res, nil +} + +// sub-account transfer balance to master-account +type SubAccountTransferSubToMasterService struct { + c *Client + asset string + amount string // decimal format + recvWindow *int64 +} + +type SubAccountTransferSubToMasterResponse struct { + TxnId string `json:"txnId"` +} + +func (s *SubAccountTransferSubToMasterService) Asset(asset string) *SubAccountTransferSubToMasterService { + s.asset = asset + return s +} + +func (s *SubAccountTransferSubToMasterService) Amount(amount string) *SubAccountTransferSubToMasterService { + s.amount = amount + return s +} + +func (s *SubAccountTransferSubToMasterService) RecvWindow(recvWindow int64) *SubAccountTransferSubToMasterService { + s.recvWindow = &recvWindow + return s +} + +func (s *SubAccountTransferSubToMasterService) Do(ctx context.Context, opts ...RequestOption) (res *SubAccountTransferSubToMasterResponse, err error) { + r := &request{ + method: http.MethodPost, + endpoint: "/sapi/v1/sub-account/transfer/subToMaster", + secType: secTypeSigned, + } + r.setFormParam("asset", s.asset) + r.setFormParam("amount", s.amount) + if s.recvWindow != nil { + r.recvWindow = *s.recvWindow + } + + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return nil, err + } + res = new(SubAccountTransferSubToMasterResponse) + err = json.Unmarshal(data, res) + if err != nil { + return nil, err + } + + return res, nil +} + +// Universal transfer of master and sub accounts +type SubAccountUniversalTransferService struct { + c *Client + fromEmail *string + toEmail *string + fromAccountType string // "SPOT","USDT_FUTURE","COIN_FUTURE","MARGIN"(Cross),"ISOLATED_MARGIN" + toAccountType string // "SPOT","USDT_FUTURE","COIN_FUTURE","MARGIN"(Cross),"ISOLATED_MARGIN" + clientTranId *string // Non repeatable + symbol *string // Only used under ISOLATEd_MARGIN type + asset string + amount string // decimal format + recvWindow *int64 +} + +type SubAccountUniversalTransferResponse struct { + TranId int64 `json:"tranId"` + ClientTranId string `json:"clientTranId"` +} + +func (s *SubAccountUniversalTransferService) FromEmail(fromEmail string) *SubAccountUniversalTransferService { + s.fromEmail = &fromEmail + return s +} + +func (s *SubAccountUniversalTransferService) ToEmail(toEmail string) *SubAccountUniversalTransferService { + s.toEmail = &toEmail + return s +} + +func (s *SubAccountUniversalTransferService) FromAccountType(fromAccountType string) *SubAccountUniversalTransferService { + s.fromAccountType = fromAccountType + return s +} + +func (s *SubAccountUniversalTransferService) ToAccountType(toAccountType string) *SubAccountUniversalTransferService { + s.toAccountType = toAccountType + return s +} + +func (s *SubAccountUniversalTransferService) ClientTranId(clientTranId string) *SubAccountUniversalTransferService { + s.clientTranId = &clientTranId + return s +} + +func (s *SubAccountUniversalTransferService) Symbol(symbol string) *SubAccountUniversalTransferService { + s.symbol = &symbol + return s +} + +func (s *SubAccountUniversalTransferService) Asset(asset string) *SubAccountUniversalTransferService { + s.asset = asset + return s +} + +func (s *SubAccountUniversalTransferService) Amount(amount string) *SubAccountUniversalTransferService { + s.amount = amount + return s +} + +func (s *SubAccountUniversalTransferService) RecvWindow(recvWindow int64) *SubAccountUniversalTransferService { + s.recvWindow = &recvWindow + return s +} + +func (s *SubAccountUniversalTransferService) Do(ctx context.Context, opts ...RequestOption) (res *SubAccountUniversalTransferResponse, err error) { + r := &request{ + method: http.MethodPost, + endpoint: "/sapi/v1/sub-account/universalTransfer", + secType: secTypeSigned, + } + if s.fromEmail != nil { + r.setFormParam("fromEmail", *s.fromEmail) + } + if s.toEmail != nil { + r.setFormParam("toEmail", *s.toEmail) + } + r.setFormParam("fromAccountType", s.fromAccountType) + r.setFormParam("toAccountType", s.toAccountType) + if s.clientTranId != nil { + r.setFormParam("clientTranId", *s.clientTranId) + } + if s.symbol != nil { + r.setFormParam("symbol", *s.symbol) + } + r.setFormParam("asset", s.asset) + r.setFormParam("amount", s.amount) + if s.recvWindow != nil { + r.recvWindow = *s.recvWindow + } + + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return nil, err + } + res = new(SubAccountUniversalTransferResponse) + err = json.Unmarshal(data, res) + if err != nil { + return nil, err + } + + return res, nil +} + +// Query the universal transfer history of sub and master accounts +type SubAccUniversalTransferHistoryService struct { + c *Client + fromEmail *string + toEmail *string + clientTranId *string // Non repeatable + startTime *int64 + endTime *int64 + page *int32 // default 1 + limit *int32 // default 500, max 500 + recvWindow *int64 +} + +type SubAccountUniversalTransferHistoryServiceResponse struct { + Result []*SubAccountUniversalTransferRecord `json:"result"` + TotalCount int64 `json:"totalCount"` +} + +type SubAccountUniversalTransferRecord struct { + TranId int64 `json:"tranId"` + FromEmail string `json:"fromEmail"` + ToEmail string `json:"toEmail"` + Asset string `json:"asset"` + Amount string `json:"amount"` + CreateTimeStamp int64 `json:"createTimeStamp"` + FromAccountType string `json:"fromAccountType"` + ToAccountType string `json:"toAccountType"` + Status string `json:"status"` + ClientTranId string `json:"clientTranId"` +} + +func (s *SubAccUniversalTransferHistoryService) FromEmail(fromEmail string) *SubAccUniversalTransferHistoryService { + s.fromEmail = &fromEmail + return s +} + +func (s *SubAccUniversalTransferHistoryService) ToEmail(toEmail string) *SubAccUniversalTransferHistoryService { + s.toEmail = &toEmail + return s +} + +func (s *SubAccUniversalTransferHistoryService) ClientTranId(clientTranId string) *SubAccUniversalTransferHistoryService { + s.clientTranId = &clientTranId + return s +} + +func (s *SubAccUniversalTransferHistoryService) StartTime(startTime int64) *SubAccUniversalTransferHistoryService { + s.startTime = &startTime + return s +} + +func (s *SubAccUniversalTransferHistoryService) EndTime(endTime int64) *SubAccUniversalTransferHistoryService { + s.endTime = &endTime + return s +} + +func (s *SubAccUniversalTransferHistoryService) Page(page int32) *SubAccUniversalTransferHistoryService { + s.page = &page + return s +} + +func (s *SubAccUniversalTransferHistoryService) Limit(limit int32) *SubAccUniversalTransferHistoryService { + s.limit = &limit + return s +} + +func (s *SubAccUniversalTransferHistoryService) RecvWindow(recvWindow int64) *SubAccUniversalTransferHistoryService { + s.recvWindow = &recvWindow + return s +} + +func (s *SubAccUniversalTransferHistoryService) Do(ctx context.Context, opts ...RequestOption) (res *SubAccountUniversalTransferHistoryServiceResponse, err error) { + r := &request{ + method: http.MethodGet, + endpoint: "/sapi/v1/sub-account/universalTransfer", + secType: secTypeSigned, + } + if s.fromEmail != nil { + r.setParam("fromEmail", *s.fromEmail) + } + if s.toEmail != nil { + r.setParam("toEmail", *s.toEmail) + } + if s.clientTranId != nil { + r.setParam("clientTranId", *s.clientTranId) + } + if s.startTime != nil { + r.setParam("startTime", *s.startTime) + } + if s.endTime != nil { + r.setParam("endTime", *s.endTime) + } + if s.page != nil { + r.setParam("page", *s.page) + } + if s.limit != nil { + r.setParam("limit", *s.limit) + } + if s.recvWindow != nil { + r.recvWindow = *s.recvWindow + } + + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return nil, err + } + res = new(SubAccountUniversalTransferHistoryServiceResponse) + err = json.Unmarshal(data, res) + if err != nil { + return nil, err + } + + return res, nil +} + +// Binance Leveraged Tokens enable +type SubAccountBlvtEnableService struct { + c *Client + email string // sub-account email + enableBlvt bool // Only true for now + recvWindow *int64 +} + +type SubAccountBlvtEnableServiceResponse struct { + Email string `json:"email"` + EnableBlvt bool `json:"enableBlvt"` +} + +func (s *SubAccountBlvtEnableService) Email(email string) *SubAccountBlvtEnableService { + s.email = email + return s +} + +func (s *SubAccountBlvtEnableService) EnableBlvt(enableBlvt bool) *SubAccountBlvtEnableService { + s.enableBlvt = enableBlvt + return s +} + +func (s *SubAccountBlvtEnableService) RecvWindow(recvWindow int64) *SubAccountBlvtEnableService { + s.recvWindow = &recvWindow + return s +} + +func (s *SubAccountBlvtEnableService) Do(ctx context.Context, opts ...RequestOption) (res *SubAccountBlvtEnableServiceResponse, err error) { + r := &request{ + method: http.MethodPost, + endpoint: "/sapi/v1/sub-account/blvt/enable", + secType: secTypeSigned, + } + r.setFormParam("email", s.email) + r.setFormParam("enableBlvt", s.enableBlvt) + if s.recvWindow != nil { + r.recvWindow = *s.recvWindow + } + + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return nil, err + } + res = new(SubAccountBlvtEnableServiceResponse) + err = json.Unmarshal(data, res) + if err != nil { + return nil, err + } + + return res, nil +} + +// query sub-account api ip restriction +type SubAccountApiIpRestrictionService struct { + c *Client + email string // sub-account email + subAccountApiKey string + recvWindow *int64 +} + +type SubAccountApiIpRestrictServiceResponse struct { + IpRestrict string `json:"ipRestrict"` + IpList []string `json:"ipList"` + UpdateTime int64 `json:"updateTime"` + ApiKey string `json:"apiKey"` +} + +func (s *SubAccountApiIpRestrictionService) Email(email string) *SubAccountApiIpRestrictionService { + s.email = email + return s +} + +func (s *SubAccountApiIpRestrictionService) SubAccountApiKey(subAccountApiKey string) *SubAccountApiIpRestrictionService { + s.subAccountApiKey = subAccountApiKey + return s +} + +func (s *SubAccountApiIpRestrictionService) RecvWindow(recvWindow int64) *SubAccountApiIpRestrictionService { + s.recvWindow = &recvWindow + return s +} + +func (s *SubAccountApiIpRestrictionService) Do(ctx context.Context, opts ...RequestOption) (res *SubAccountApiIpRestrictServiceResponse, err error) { + r := &request{ + method: http.MethodGet, + endpoint: "/sapi/v1/sub-account/subAccountApi/ipRestriction", + secType: secTypeSigned, + } + r.setParam("email", s.email) + r.setParam("subAccountApiKey", s.subAccountApiKey) + if s.recvWindow != nil { + r.recvWindow = *s.recvWindow + } + + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return nil, err + } + res = new(SubAccountApiIpRestrictServiceResponse) + err = json.Unmarshal(data, res) + if err != nil { + return nil, err + } + + return res, nil +} + +// delete sub-account ip restriction +type SubAccountApiDeleteIpRestrictionService struct { + c *Client + email string // sub-account email + subAccountApiKey string + ipAddress *string // Can be deleted in batches, separated by commas + recvWindow *int64 +} + +type SubAccountApiDeleteIpRestrictServiceResponse struct { + IpRestrict string `json:"ipRestrict"` + IpList []string `json:"ipList"` + UpdateTime int64 `json:"updateTime"` + ApiKey string `json:"apiKey"` +} + +func (s *SubAccountApiDeleteIpRestrictionService) Email(email string) *SubAccountApiDeleteIpRestrictionService { + s.email = email + return s +} + +func (s *SubAccountApiDeleteIpRestrictionService) SubAccountApiKey(subAccountApiKey string) *SubAccountApiDeleteIpRestrictionService { + s.subAccountApiKey = subAccountApiKey + return s +} + +func (s *SubAccountApiDeleteIpRestrictionService) IpAddress(ipAddress string) *SubAccountApiDeleteIpRestrictionService { + s.ipAddress = &ipAddress + return s +} + +func (s *SubAccountApiDeleteIpRestrictionService) RecvWindow(recvWindow int64) *SubAccountApiDeleteIpRestrictionService { + s.recvWindow = &recvWindow + return s +} + +func (s *SubAccountApiDeleteIpRestrictionService) Do(ctx context.Context, opts ...RequestOption) (res *SubAccountApiDeleteIpRestrictServiceResponse, err error) { + r := &request{ + method: http.MethodDelete, + endpoint: "/sapi/v1/sub-account/subAccountApi/ipRestriction/ipList", + secType: secTypeSigned, + } + r.setFormParam("email", s.email) + r.setFormParam("subAccountApiKey", s.subAccountApiKey) + if s.ipAddress != nil { + r.setFormParam("ipAddress", *s.ipAddress) + } + if s.recvWindow != nil { + r.recvWindow = *s.recvWindow + } + + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return nil, err + } + res = new(SubAccountApiDeleteIpRestrictServiceResponse) + err = json.Unmarshal(data, res) + if err != nil { + return nil, err + } + + return res, nil +} + +// add sub-account ip restriction +type SubAccountApiAddIpRestrictionService struct { + c *Client + email string // sub-account email + subAccountApiKey string + status string // IP restriction status. 1 or not filled in (null)=IP not restricted. 2=Access is limited to trusted IPs only. + ipAddress *string // IP can be filled in bulk, separated by commas + recvWindow *int64 +} + +type SubAccountApiAddIpRestrictServiceResponse struct { + IpRestrict string `json:"ipRestrict"` + IpList []string `json:"ipList"` + UpdateTime int64 `json:"updateTime"` + ApiKey string `json:"apiKey"` +} + +func (s *SubAccountApiAddIpRestrictionService) Email(email string) *SubAccountApiAddIpRestrictionService { + s.email = email + return s +} + +func (s *SubAccountApiAddIpRestrictionService) SubAccountApiKey(subAccountApiKey string) *SubAccountApiAddIpRestrictionService { + s.subAccountApiKey = subAccountApiKey + return s +} + +func (s *SubAccountApiAddIpRestrictionService) Status(status string) *SubAccountApiAddIpRestrictionService { + s.status = status + return s +} + +func (s *SubAccountApiAddIpRestrictionService) IpAddress(ipAddress string) *SubAccountApiAddIpRestrictionService { + s.ipAddress = &ipAddress + return s +} + +func (s *SubAccountApiAddIpRestrictionService) RecvWindow(recvWindow int64) *SubAccountApiAddIpRestrictionService { + s.recvWindow = &recvWindow + return s +} + +func (s *SubAccountApiAddIpRestrictionService) Do(ctx context.Context, opts ...RequestOption) (res *SubAccountApiAddIpRestrictServiceResponse, err error) { + r := &request{ + method: http.MethodPost, + endpoint: "/sapi/v1/sub-account/subAccountApi/ipRestriction", + secType: secTypeSigned, + } + r.setFormParam("email", s.email) + r.setFormParam("subAccountApiKey", s.subAccountApiKey) + r.setFormParam("status", s.status) + if s.ipAddress != nil { + r.setFormParam("ipAddress", *s.ipAddress) + } + if s.recvWindow != nil { + r.recvWindow = *s.recvWindow + } + + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return nil, err + } + res = new(SubAccountApiAddIpRestrictServiceResponse) + err = json.Unmarshal(data, res) + if err != nil { + return nil, err + } + + return res, nil +} + +type ManagedSubAccountWithdrawService struct { + c *Client + fromEmail string + asset string + amount string // decimal format + transferDate *int64 // The withdrawal will automatically occur on the selected date (UTC0). If no date is selected, the withdrawal will take effect immediately + recvWindow *int64 +} + +type ManagedSubAccountWithdrawServiceResponse struct { + TranId int64 `json:"tranId"` +} + +func (s *ManagedSubAccountWithdrawService) FromEmail(fromEmail string) *ManagedSubAccountWithdrawService { + s.fromEmail = fromEmail + return s +} + +func (s *ManagedSubAccountWithdrawService) Asset(asset string) *ManagedSubAccountWithdrawService { + s.asset = asset + return s +} + +func (s *ManagedSubAccountWithdrawService) Amount(amount string) *ManagedSubAccountWithdrawService { + s.amount = amount + return s +} + +func (s *ManagedSubAccountWithdrawService) TransferDate(transferDate int64) *ManagedSubAccountWithdrawService { + s.transferDate = &transferDate + return s +} + +func (s *ManagedSubAccountWithdrawService) RecvWindow(recvWindow int64) *ManagedSubAccountWithdrawService { + s.recvWindow = &recvWindow + return s +} + +func (s *ManagedSubAccountWithdrawService) Do(ctx context.Context, opts ...RequestOption) (res *ManagedSubAccountWithdrawServiceResponse, err error) { + r := &request{ + method: http.MethodPost, + endpoint: "/sapi/v1/managed-subaccount/withdraw", + secType: secTypeSigned, + } + r.setFormParam("fromEmail", s.fromEmail) + r.setFormParam("asset", s.asset) + r.setFormParam("amount", s.amount) + if s.transferDate != nil { + r.setFormParam("transferDate", *s.transferDate) + } + if s.recvWindow != nil { + r.recvWindow = *s.recvWindow + } + + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return nil, err + } + res = new(ManagedSubAccountWithdrawServiceResponse) + err = json.Unmarshal(data, res) + if err != nil { + return nil, err + } + + return res, nil +} + +// Query asset snapshot of managed-sub account +type ManagedSubAccountSnapshotService struct { + c *Client + email string + accType string // SPOT (spot), MARGIN (full position), FUTURES (U-based contract) + startTime *int64 + endTime *int64 + limit *int32 // min 7, max 30, default 7 + recvWindow *int64 +} + +type ManagedSubAccountSnapshotServiceResponse struct { + Code int64 `json:"code"` + Msg string `json:"msg"` + SnapshotVos []*SnapshotVo `json:"snapshotVos"` +} + +type SnapshotVo struct { + Data SnapshotVoData `json:"data"` + Type string `json:"type"` + UpdateTime int64 `json:"updateTime"` +} + +type SnapshotVoData struct { + Balances []*SnapShotSpotBalance `json:"balances"` // set while SnapshotVo.type=spot + TotalAssetOfBtc string `json:"totalAssetOfBtc"` // set while SnapshotVo.type is one of spot and margin + MarginLevel string `json:"marginLevel"` // set while SnapshotVo.type=margin + TotalLiabilityOfBtc string `json:"totalLiabilityOfBtc"` // set while SnapshotVo.type=margin + TotalNetAssetOfBtc string `json:"totalNetAssetOfBtc"` // set while SnapshotVo.type=margin + UserAssets []*MarginUserAsset `json:"userAssets"` // set while SnapshotVo.type=margin + Assets []*FuturesUserAsset `json:"assets"` // set while SnapshotVo.type=futures + Position []*FuturesUserPosition `json:"position"` // set while SnapshotVo.type=futures +} + +type SnapShotSpotBalance struct { + Asset string `json:"asset"` + Free string `json:"free"` + Locked string `json:"locked"` +} + +type MarginUserAsset struct { + Asset string `json:"asset"` + Borrowed string `json:"borrowed"` + Free string `json:"free"` + Interest string `json:"interest"` + Locked string `json:"locked"` + NetAsset string `json:"netAsset"` +} + +type FuturesUserAsset struct { + Asset string `json:"asset"` + MarginBalance string `json:"marginBalance"` + WalletBalance string `json:"walletBalance"` +} + +type FuturesUserPosition struct { + EntryPrice string `json:"entryPrice"` + MarkPrice string `json:"markPrice"` + PositionAmt string `json:"positionAmt"` + Symbol string `json:"symbol"` + UnRealizedProfit string `json:"unRealizedProfit"` +} + +func (s *ManagedSubAccountSnapshotService) Email(email string) *ManagedSubAccountSnapshotService { + s.email = email + return s +} + +func (s *ManagedSubAccountSnapshotService) AccType(accType string) *ManagedSubAccountSnapshotService { + s.accType = accType + return s +} + +func (s *ManagedSubAccountSnapshotService) StartTime(startTime int64) *ManagedSubAccountSnapshotService { + s.startTime = &startTime + return s +} + +func (s *ManagedSubAccountSnapshotService) EndTime(endTime int64) *ManagedSubAccountSnapshotService { + s.endTime = &endTime + return s +} + +func (s *ManagedSubAccountSnapshotService) Limit(limit int32) *ManagedSubAccountSnapshotService { + s.limit = &limit + return s +} + +func (s *ManagedSubAccountSnapshotService) RecvWindow(recvWindow int64) *ManagedSubAccountSnapshotService { + s.recvWindow = &recvWindow + return s +} + +func (s *ManagedSubAccountSnapshotService) Do(ctx context.Context, opts ...RequestOption) (res *ManagedSubAccountSnapshotServiceResponse, err error) { + r := &request{ + method: http.MethodGet, + endpoint: "/sapi/v1/managed-subaccount/accountSnapshot", + secType: secTypeSigned, + } + r.setParam("email", s.email) + r.setParam("type", s.accType) + if s.startTime != nil { + r.setParam("startTime", *s.startTime) + } + if s.endTime != nil { + r.setParam("endTime", *s.endTime) + } + if s.limit != nil { + r.setParam("limit", *s.limit) + } + if s.recvWindow != nil { + r.recvWindow = *s.recvWindow + } + + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return nil, err + } + res = new(ManagedSubAccountSnapshotServiceResponse) + err = json.Unmarshal(data, res) + if err != nil { + return nil, err + } + + return res, nil +} + +// managed-sub account query transfer log, this interface is for investor +type ManagedSubAccountQueryTransferLogForInvestorService struct { + c *Client + email string + startTime int64 + endTime int64 // The start and end time intervals cannot exceed six months + page int32 + limit int32 // max 500 + transfers *string // from/to + transferFunctionAccountType *string // SPOT/MARGIN/ISOLATED_MARGIN/USDT_FUTURE/COIN_FUTURE +} + +type ManagedSubAccountQueryTransferLogForInvestorServiceResponse struct { + ManagerSubTransferHistoryVos []*ManagedSubTransferHistoryVo `json:"managerSubTransferHistoryVos"` + Count int32 `json:"count"` +} + +type ManagedSubTransferHistoryVo struct { + FromEmail string `json:"fromEmail"` + FromAccountType string `json:"fromAccountType"` + ToEmail string `json:"toEmail"` + ToAccountType string `json:"toAccountType"` + Asset string `json:"asset"` + Amount string `json:"amount"` + ScheduledData int64 `json:"scheduledData"` + CreateTime int64 `json:"createTime"` + Status string `json:"status"` + TranId int64 `json:"tranId"` +} + +func (s *ManagedSubAccountQueryTransferLogForInvestorService) Email(email string) *ManagedSubAccountQueryTransferLogForInvestorService { + s.email = email + return s +} + +func (s *ManagedSubAccountQueryTransferLogForInvestorService) StartTime(startTime int64) *ManagedSubAccountQueryTransferLogForInvestorService { + s.startTime = startTime + return s +} + +func (s *ManagedSubAccountQueryTransferLogForInvestorService) EndTime(endTime int64) *ManagedSubAccountQueryTransferLogForInvestorService { + s.endTime = endTime + return s +} + +func (s *ManagedSubAccountQueryTransferLogForInvestorService) Page(page int32) *ManagedSubAccountQueryTransferLogForInvestorService { + s.page = page + return s +} + +func (s *ManagedSubAccountQueryTransferLogForInvestorService) Limit(limit int32) *ManagedSubAccountQueryTransferLogForInvestorService { + s.limit = limit + return s +} + +func (s *ManagedSubAccountQueryTransferLogForInvestorService) Transfers(transfers string) *ManagedSubAccountQueryTransferLogForInvestorService { + s.transfers = &transfers + return s +} + +func (s *ManagedSubAccountQueryTransferLogForInvestorService) TransferFunctionAccountType(transferFunctionAccountType string) *ManagedSubAccountQueryTransferLogForInvestorService { + s.transferFunctionAccountType = &transferFunctionAccountType + return s +} + +func (s *ManagedSubAccountQueryTransferLogForInvestorService) Do(ctx context.Context, opts ...RequestOption) (res *ManagedSubAccountQueryTransferLogForInvestorServiceResponse, err error) { + r := &request{ + method: http.MethodGet, + endpoint: "/sapi/v1/managed-subaccount/queryTransLogForInvestor", + secType: secTypeSigned, + } + r.setParam("email", s.email) + r.setParam("startTime", s.startTime) + r.setParam("endTime", s.endTime) + r.setParam("page", s.page) + r.setParam("limit", s.limit) + if s.transfers != nil { + r.setParam("transfers", *s.transfers) + } + if s.transferFunctionAccountType != nil { + r.setParam("transferFunctionAccountType", *s.transferFunctionAccountType) + } + + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return nil, err + } + res = new(ManagedSubAccountQueryTransferLogForInvestorServiceResponse) + err = json.Unmarshal(data, res) + if err != nil { + return nil, err + } + + return res, nil +} + +type ManagedSubAccountQueryTransferLogForTradeParentService struct { + c *Client + email string + startTime int64 + endTime int64 // The start and end time intervals cannot exceed six months + page int32 + limit int32 // max 500 + transfers *string // from/to + transferFunctionAccountType *string // SPOT/MARGIN/ISOLATED_MARGIN/USDT_FUTURE/COIN_FUTURE +} + +type ManagedSubAccountQueryTransferLogForTradeParentServiceResponse struct { + ManagerSubTransferHistoryVos []*ManagedSubTransferHistoryVo `json:"managerSubTransferHistoryVos"` + Count int32 `json:"count"` +} + +func (s *ManagedSubAccountQueryTransferLogForTradeParentService) Email(email string) *ManagedSubAccountQueryTransferLogForTradeParentService { + s.email = email + return s +} + +func (s *ManagedSubAccountQueryTransferLogForTradeParentService) StartTime(startTime int64) *ManagedSubAccountQueryTransferLogForTradeParentService { + s.startTime = startTime + return s +} + +func (s *ManagedSubAccountQueryTransferLogForTradeParentService) EndTime(endTime int64) *ManagedSubAccountQueryTransferLogForTradeParentService { + s.endTime = endTime + return s +} + +func (s *ManagedSubAccountQueryTransferLogForTradeParentService) Page(page int32) *ManagedSubAccountQueryTransferLogForTradeParentService { + s.page = page + return s +} + +func (s *ManagedSubAccountQueryTransferLogForTradeParentService) Limit(limit int32) *ManagedSubAccountQueryTransferLogForTradeParentService { + s.limit = limit + return s +} + +func (s *ManagedSubAccountQueryTransferLogForTradeParentService) Transfers(transfers string) *ManagedSubAccountQueryTransferLogForTradeParentService { + s.transfers = &transfers + return s +} + +func (s *ManagedSubAccountQueryTransferLogForTradeParentService) TransferFunctionAccountType(transferFunctionAccountType string) *ManagedSubAccountQueryTransferLogForTradeParentService { + s.transferFunctionAccountType = &transferFunctionAccountType + return s +} + +func (s *ManagedSubAccountQueryTransferLogForTradeParentService) Do(ctx context.Context, opts ...RequestOption) (res *ManagedSubAccountQueryTransferLogForTradeParentServiceResponse, err error) { + r := &request{ + method: http.MethodGet, + endpoint: "/sapi/v1/managed-subaccount/queryTransLogForTradeParent", + secType: secTypeSigned, + } + r.setParam("email", s.email) + r.setParam("startTime", s.startTime) + r.setParam("endTime", s.endTime) + r.setParam("page", s.page) + r.setParam("limit", s.limit) + if s.transfers != nil { + r.setParam("transfers", *s.transfers) + } + if s.transferFunctionAccountType != nil { + r.setParam("transferFunctionAccountType", *s.transferFunctionAccountType) + } + + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return nil, err + } + res = new(ManagedSubAccountQueryTransferLogForTradeParentServiceResponse) + err = json.Unmarshal(data, res) + if err != nil { + return nil, err + } + + return res, nil +} + +// Investor account inquiry custody account futures assets +type ManagedSubAccountQueryFuturesAssetService struct { + c *Client + email string +} + +type ManagedSubAccountQueryFuturesAssetServiceResponse struct { + Code int32 `json:"code"` + Message string `json:"message"` + SnapshotVos []*ManagedSubFuturesAccountSnapVo `json:"snapshotVos"` +} + +type ManagedSubFuturesAccountSnapVo struct { + Type string `json:"type"` + UpdateTime int64 `json:"updateTime"` + Data *ManagedSubFuturesAccountSnapVoData `json:"data"` +} + +type ManagedSubFuturesAccountSnapVoData struct { + Assets []*ManagedSubFuturesAccountSnapVoDataAsset `json:"assets"` + Position []*ManagedSubFuturesAccountSnapVoDataPosition `json:"position"` +} + +type ManagedSubFuturesAccountSnapVoDataAsset struct { + Asset string `json:"asset"` + MarginBalance string `json:"marginBalance"` + WalletBalance string `json:"walletBalance"` +} + +type ManagedSubFuturesAccountSnapVoDataPosition struct { + Symbol string `json:"symbol"` + EntryPrice string `json:"entryPrice"` + MarkPrice string `json:"markPrice"` + PositionAmt string `json:"positionAmt"` +} + +func (s *ManagedSubAccountQueryFuturesAssetService) Email(email string) *ManagedSubAccountQueryFuturesAssetService { + s.email = email + return s +} + +func (s *ManagedSubAccountQueryFuturesAssetService) Do(ctx context.Context, opts ...RequestOption) (res *ManagedSubAccountQueryFuturesAssetServiceResponse, err error) { + r := &request{ + method: http.MethodGet, + endpoint: "/sapi/v1/managed-subaccount/fetch-future-asset", + secType: secTypeSigned, + } + r.setParam("email", s.email) + + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return nil, err + } + res = new(ManagedSubAccountQueryFuturesAssetServiceResponse) + err = json.Unmarshal(data, res) + if err != nil { + return nil, err + } + + return res, nil +} + +// Investor account inquiry for leveraged assets in custodial accounts +type ManagedSubAccountQueryMarginAssetService struct { + c *Client + email string +} + +type ManagedSubAccountQueryMarginAssetServiceResponse struct { + MarginLevel string `json:"marginLevel"` + TotalAssetOfBtc string `json:"totalAssetOfBtc"` + TotalLiabilityOfBtc string `json:"totalLiabilityOfBtc"` + TotalNetAssetOfBtc string `json:"totalNetAssetOfBtc"` + UserAssets []*ManagedSubAccountMarginAsset `json:"userAssets"` +} + +type ManagedSubAccountMarginAsset struct { + Asset string `json:"asset"` + Borrowed string `json:"borrowed"` + Free string `json:"free"` + Interest string `json:"interest"` + Locked string `json:"locked"` + NetAsset string `json:"netAsset"` +} + +func (s *ManagedSubAccountQueryMarginAssetService) Email(email string) *ManagedSubAccountQueryMarginAssetService { + s.email = email + return s +} + +func (s *ManagedSubAccountQueryMarginAssetService) Do(ctx context.Context, opts ...RequestOption) (res *ManagedSubAccountQueryMarginAssetServiceResponse, err error) { + r := &request{ + method: http.MethodGet, + endpoint: "/sapi/v1/managed-subaccount/marginAsset", + secType: secTypeSigned, + } + r.setParam("email", s.email) + + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return nil, err + } + res = new(ManagedSubAccountQueryMarginAssetServiceResponse) + err = json.Unmarshal(data, res) + if err != nil { + return nil, err + } + + return res, nil +} + +// Query sub account assets, v4 interface. +type SubAccountAssetService struct { + c *Client + email string + recvWindow *int64 +} + +type SubAccountAssetServiceResponse struct { + Balances []*SubAccountAssetBalance `json:"balances"` +} + +type SubAccountAssetBalance struct { + Asset string `json:"asset"` + Free string `json:"free"` + Locked string `json:"locked"` +} + +func (s *SubAccountAssetService) Email(email string) *SubAccountAssetService { + s.email = email + return s +} + +func (s *SubAccountAssetService) RecvWindow(recvWindow int64) *SubAccountAssetService { + s.recvWindow = &recvWindow + return s +} + +func (s *SubAccountAssetService) Do(ctx context.Context, opts ...RequestOption) (res *SubAccountAssetServiceResponse, err error) { + r := &request{ + method: http.MethodGet, + endpoint: "/sapi/v4/sub-account/assets", + secType: secTypeSigned, + } + r.setParam("email", s.email) + if s.recvWindow != nil { + r.recvWindow = *s.recvWindow + } + + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return nil, err + } + res = new(SubAccountAssetServiceResponse) + err = json.Unmarshal(data, res) + if err != nil { + return nil, err + } + + return res, nil +} + +// Query the list of managed-accounts +type ManagedSubAccountInfoService struct { + c *Client + email string + page *int32 // default 1 + limit *int32 // default 20, max 20 + recvWindow *int64 +} + +type ManagedSubAccountInfoServiceResponse struct { + Total int32 `json:"total"` + ManagerSubUserInfoVoList []*ManagedSubAccountUserInfoVo `json:"managerSubUserInfoVoList"` +} + +type ManagedSubAccountUserInfoVo struct { + RootUserId int64 `json:"rootUserId"` + ManagersubUserId int64 `json:"managersubUserId"` + BindParentUserId int64 `json:"bindParentUserId"` + Email string `json:"email"` + InsertTimeStamp int64 `json:"insertTimeStamp"` + BindParentEmail string `json:"bindParentEmail"` + IsSubUserEnabled bool `json:"isSubUserEnabled"` + IsUserActive bool `json:"isUserActive"` + IsMarginEnabled bool `json:"isMarginEnabled"` + IsFutureEnabled bool `json:"isFutureEnabled"` + IsSignedLVTRiskAgreement bool `json:"isSignedLVTRiskAgreement"` +} + +func (s *ManagedSubAccountInfoService) Email(email string) *ManagedSubAccountInfoService { + s.email = email + return s +} + +func (s *ManagedSubAccountInfoService) Page(page int32) *ManagedSubAccountInfoService { + s.page = &page + return s +} + +func (s *ManagedSubAccountInfoService) Limit(limit int32) *ManagedSubAccountInfoService { + s.limit = &limit + return s +} + +func (s *ManagedSubAccountInfoService) RecvWindow(recvWindow int64) *ManagedSubAccountInfoService { + s.recvWindow = &recvWindow + return s +} + +func (s *ManagedSubAccountInfoService) Do(ctx context.Context, opts ...RequestOption) (res *ManagedSubAccountInfoServiceResponse, err error) { + r := &request{ + method: http.MethodGet, + endpoint: "/sapi/v1/managed-subaccount/info", + secType: secTypeSigned, + } + r.setParam("email", s.email) + if s.page != nil { + r.setParam("page", *s.page) + } + if s.limit != nil { + r.setParam("limit", *s.limit) + } + if s.recvWindow != nil { + r.recvWindow = *s.recvWindow + } + + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return nil, err + } + res = new(ManagedSubAccountInfoServiceResponse) + err = json.Unmarshal(data, res) + if err != nil { + return nil, err + } + + return res, nil +} + +// Query sub account transaction volume statistics list +type SubAccountTransactionStatisticsService struct { + c *Client + email string + recvWindow *int64 +} + +type SubAccountTransactionStatisticServiceResponse struct { + Recent30BtcTotal string `json:"recent30BtcTotal"` + Recent30BtcFuturesTotal string `json:"recent30BtcFuturesTotal"` + Recent30BtcMarginTotal string `json:"recent30BtcMarginTotal"` + Recent30BusdTotal string `json:"recent30BusdTotal"` + Recent30BusdFuturesTotal string `json:"recent30BusdFuturesTotal"` + Recent30BusdMarginTotal string `json:"recent30BusdMarginTotal"` + TradeInfoVos []*TradeInfoVo `json:"tradeInfoVos"` +} + +type TradeInfoVo struct { + UserId int64 `json:"userId"` + Btc float64 `json:"btc"` + BtcFutures float64 `json:"btcFutures"` + BtcMargin float64 `json:"btcMargin"` + Busd float64 `json:"busd"` + BusdFutures float64 `json:"busdFutures"` + BusdMargin float64 `json:"busdMargin"` + Date int64 `json:"date"` +} + +func (s *SubAccountTransactionStatisticsService) Email(email string) *SubAccountTransactionStatisticsService { + s.email = email + return s +} + +func (s *SubAccountTransactionStatisticsService) RecvWindow(recvWindow int64) *SubAccountTransactionStatisticsService { + s.recvWindow = &recvWindow + return s +} + +func (s *SubAccountTransactionStatisticsService) Do(ctx context.Context, opts ...RequestOption) (res *SubAccountTransactionStatisticServiceResponse, err error) { + r := &request{ + method: http.MethodGet, + endpoint: "/sapi/v1/sub-account/transaction-statistics", + secType: secTypeSigned, + } + r.setParam("email", s.email) + if s.recvWindow != nil { + r.recvWindow = *s.recvWindow + } + + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return nil, err + } + res = new(SubAccountTransactionStatisticServiceResponse) + err = json.Unmarshal(data, res) + if err != nil { + return nil, err + } + + return res, nil +} + +// Obtain the recharge address for the custody account +type ManagedSubAccountDepositAddressService struct { + c *Client + email string + coin string + network *string // The network can be obtained from GET /sapi/v1/capital/deposit/address. When the network is not transmitted, return the default network of the coin + recvWindow *int64 +} + +type ManagedSubAccountDepositAddressServiceResponse struct { + Coin string `json:"coin"` + Address string `json:"address"` + Tag string `json:"tag"` + Url string `json:"url"` +} + +func (s *ManagedSubAccountDepositAddressService) Email(email string) *ManagedSubAccountDepositAddressService { + s.email = email + return s +} + +func (s *ManagedSubAccountDepositAddressService) Coin(coin string) *ManagedSubAccountDepositAddressService { + s.coin = coin + return s +} + +func (s *ManagedSubAccountDepositAddressService) Network(network string) *ManagedSubAccountDepositAddressService { + s.network = &network + return s +} + +func (s *ManagedSubAccountDepositAddressService) RecvWindow(recvWindow int64) *ManagedSubAccountDepositAddressService { + s.recvWindow = &recvWindow + return s +} + +func (s *ManagedSubAccountDepositAddressService) Do(ctx context.Context, opts ...RequestOption) (res *ManagedSubAccountDepositAddressServiceResponse, err error) { + r := &request{ + method: http.MethodGet, + endpoint: "/sapi/v1/managed-subaccount/deposit/address", + secType: secTypeSigned, + } + r.setParam("email", s.email) + r.setParam("coin", s.coin) + if s.network != nil { + r.setParam("network", *s.network) + } + if s.recvWindow != nil { + r.recvWindow = *s.recvWindow + } + + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return nil, err + } + res = new(ManagedSubAccountDepositAddressServiceResponse) + err = json.Unmarshal(data, res) + if err != nil { + return nil, err + } + + return res, nil +} + +type SubAccountOptionsEnableService struct { + c *Client + email string + recvWindow *int64 +} + +type SubAccountOptionsEnableServiceResponse struct { + Email string `json:"email"` + IsEOptionsEnabled bool `json:"isEOptionsEnabled"` +} + +func (s *SubAccountOptionsEnableService) Email(email string) *SubAccountOptionsEnableService { + s.email = email + return s +} + +func (s *SubAccountOptionsEnableService) RecvWindow(recvWindow int64) *SubAccountOptionsEnableService { + s.recvWindow = &recvWindow + return s +} + +func (s *SubAccountOptionsEnableService) Do(ctx context.Context, opts ...RequestOption) (res *SubAccountOptionsEnableServiceResponse, err error) { + r := &request{ + method: http.MethodPost, + endpoint: "/sapi/v1/sub-account/eoptions/enable", + secType: secTypeSigned, + } + r.setFormParam("email", s.email) + if s.recvWindow != nil { + r.recvWindow = *s.recvWindow + } + + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return nil, err + } + res = new(SubAccountOptionsEnableServiceResponse) + err = json.Unmarshal(data, res) + if err != nil { + return nil, err + } + + return res, nil +} + +// Query transfer records of managed-sub accounts +type ManagedSubAccountQueryTransferLogService struct { + c *Client + startTime int64 + endTime int64 // End time (start time end time interval cannot exceed six months) + page int32 + limit int32 // max 500 + transfers *string // from/to + transferFunctionAccountType *string // SPOT/MARGIN/ISOLATED_MARGIN/USDT_FUTURE/COIN_FUTURE + recvWindow *int64 +} + +type ManagedSubAccountQueryTransferLogServiceResponse struct { + ManagerSubTransferHistoryVos []*ManagedSubTransferHistoryVo `json:"managerSubTransferHistoryVos"` + Count int32 `json:"count"` +} + +func (s *ManagedSubAccountQueryTransferLogService) StartTime(startTime int64) *ManagedSubAccountQueryTransferLogService { + s.startTime = startTime + return s +} + +func (s *ManagedSubAccountQueryTransferLogService) EndTime(endTime int64) *ManagedSubAccountQueryTransferLogService { + s.endTime = endTime + return s +} + +func (s *ManagedSubAccountQueryTransferLogService) Page(page int32) *ManagedSubAccountQueryTransferLogService { + s.page = page + return s +} + +func (s *ManagedSubAccountQueryTransferLogService) Limit(limit int32) *ManagedSubAccountQueryTransferLogService { + s.limit = limit + return s +} + +func (s *ManagedSubAccountQueryTransferLogService) Transfers(transfers string) *ManagedSubAccountQueryTransferLogService { + s.transfers = &transfers + return s +} + +func (s *ManagedSubAccountQueryTransferLogService) TransferFunctionAccountType(transferFunctionAccountType string) *ManagedSubAccountQueryTransferLogService { + s.transferFunctionAccountType = &transferFunctionAccountType + return s +} + +func (s *ManagedSubAccountQueryTransferLogService) RecvWindow(recvWindow int64) *ManagedSubAccountQueryTransferLogService { + s.recvWindow = &recvWindow + return s +} + +func (s *ManagedSubAccountQueryTransferLogService) Do(ctx context.Context, opts ...RequestOption) (res *ManagedSubAccountQueryTransferLogServiceResponse, err error) { + r := &request{ + method: http.MethodGet, + endpoint: "/sapi/v1/managed-subaccount/query-trans-log", + secType: secTypeSigned, + } + r.setParam("startTime", s.startTime) + r.setParam("endTime", s.endTime) + r.setParam("page", s.page) + r.setParam("limit", s.limit) + if s.transfers != nil { + r.setParam("transfers", *s.transfers) + } + if s.transferFunctionAccountType != nil { + r.setParam("transferFunctionAccountType", *s.transferFunctionAccountType) + } + if s.recvWindow != nil { + r.recvWindow = *s.recvWindow + } + + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return nil, err + } + res = new(ManagedSubAccountQueryTransferLogServiceResponse) + err = json.Unmarshal(data, res) + if err != nil { + return nil, err + } + + return res, nil +} diff --git a/v2/subaccount_service_test.go b/v2/subaccount_service_test.go index 6e0ca96b..d610c7fa 100644 --- a/v2/subaccount_service_test.go +++ b/v2/subaccount_service_test.go @@ -415,3 +415,2462 @@ func (s *subAccountServiceTestSuite) assertSubAccountTransferHistoryEqual(e, a * r.Equal(e.TranID, a.TranID, "TranId") r.Equal(e.Time, a.Time, "Time") } + +type createVirtualSubAccountServiceTestSuite struct { + baseTestSuite +} + +func TestCreateVirtualSubAccountService(t *testing.T) { + suite.Run(t, new(createVirtualSubAccountServiceTestSuite)) +} + +func (s *createVirtualSubAccountServiceTestSuite) TestCreateVirtualSubAccount() { + data := []byte(`{"email": "addsdd_virtual@aasaixwqnoemail.com"}`) + s.mockDo(data, nil) + defer s.assertDo() + var subAccountString string = "testSubAccount" + s.assertReq(func(r *request) { + e := newSignedRequest().setFormParam("subAccountString", subAccountString) + s.assertRequestEqual(e, r) + }) + res, err := s.client.NewCreateVirtualSubAccountService().SubAccountString(subAccountString).Do(newContext()) + s.r().NoError(err) + + e := &CreateVirtualSubAccountResponse{ + Email: "addsdd_virtual@aasaixwqnoemail.com"} + s.assertCreateVirtualSubAccountResponseEqual(e, res) +} + +func (s *createVirtualSubAccountServiceTestSuite) assertCreateVirtualSubAccountResponseEqual(e, a *CreateVirtualSubAccountResponse) { + r := s.r() + r.Equal(e.Email, a.Email, "Email") +} + +type subAccountSpotTransferHistoryServiceTestSuite struct { + baseTestSuite +} + +func TestSubAccountSpotTransferHistoryService(t *testing.T) { + suite.Run(t, new(subAccountSpotTransferHistoryServiceTestSuite)) +} + +func (s *subAccountSpotTransferHistoryServiceTestSuite) TestSubAccountSpotTransferHistory() { + data := []byte(`[{ + "from": "aaa@test.com", + "to": "bbb@test.com", + "asset": "BTC", + "qty": "10", + "status": "SUCCESS", + "tranId": 6489943656, + "time": 1544433328000 + }, + { + "from": "bbb@test.com", + "to": "ccc@test.com", + "asset": "ETH", + "qty": "2", + "status": "SUCCESS", + "tranId": 6489938713, + "time": 1544433328000 + } +]`) + s.mockDo(data, nil) + defer s.assertDo() + var fromEmail string = "xxyyzz@gmail.com" + var toEmail string = "aabb@gmail.com" + var limit int32 = 20 + s.assertReq(func(r *request) { + e := newSignedRequest().setParam("fromEmail", fromEmail).setParam("toEmail", toEmail).setParam("limit", limit) + s.assertRequestEqual(e, r) + }) + res, err := s.client.NewSubAccountSpotTransferHistoryService().FromEmail(fromEmail).ToEmail(toEmail).Limit(limit).Do(newContext()) + s.r().NoError(err) + + e := []*SubAccountSpotTransfer{ + { + From: "aaa@test.com", + To: "bbb@test.com", + Asset: "BTC", + Qty: "10", + Status: "SUCCESS", + TranId: 6489943656, + Time: 1544433328000}, + { + From: "bbb@test.com", + To: "ccc@test.com", + Asset: "ETH", + Qty: "2", + Status: "SUCCESS", + TranId: 6489938713, + Time: 1544433328000}} + + s.assertSubAccountSpotTransfersEqual(e, res) +} + +func (s *subAccountSpotTransferHistoryServiceTestSuite) assertSubAccountSpotTransferEqual(e, a *SubAccountSpotTransfer) { + r := s.r() + r.Equal(e.From, a.From, "From") + r.Equal(e.To, a.To, "To") + r.Equal(e.Asset, a.Asset, "Asset") + r.Equal(e.Qty, a.Qty, "Qty") + r.Equal(e.Status, a.Status, "Status") + r.Equal(e.TranId, a.TranId, "TranId") + r.Equal(e.Time, a.Time, "Time") +} + +func (s *subAccountSpotTransferHistoryServiceTestSuite) assertSubAccountSpotTransfersEqual(e, a []*SubAccountSpotTransfer) { + s.r().Len(e, len(a)) + for i := range e { + s.assertSubAccountSpotTransferEqual(e[i], a[i]) + } +} + +type subAccountFuturesTransferHistoryServiceTestSuite struct { + baseTestSuite +} + +func TestSubAccountFuturesTransferHistoryService(t *testing.T) { + suite.Run(t, new(subAccountFuturesTransferHistoryServiceTestSuite)) +} + +func (s *subAccountFuturesTransferHistoryServiceTestSuite) TestSubAccountFuturesTransferHistory() { + data := []byte(`{ + "success": true, + "futuresType": 2, + "transfers": [{ + "from": "aaa@test.com", + "to": "bbb@test.com", + "asset": "BTC", + "qty": "1", + "tranId": 11897001102, + "time": 1544433328000 + }, + { + "from": "bbb@test.com", + "to": "ccc@test.com", + "asset": "ETH", + "qty": "2", + "tranId": 11631474902, + "time": 1544433328000 + } + ] +}`) + s.mockDo(data, nil) + defer s.assertDo() + var email string = "xxyyzz@gmail.com" + var futuresType int64 = 1 + var limit int32 = 20 + s.assertReq(func(r *request) { + e := newSignedRequest().setParam("email", email).setParam("futuresType", futuresType).setParam("limit", limit) + s.assertRequestEqual(e, r) + }) + res, err := s.client.NewSubAccountFuturesTransferHistoryService().Email(email).FuturesType(futuresType).Limit(limit).Do(newContext()) + s.r().NoError(err) + + e := &SubAccountFuturesTransferHistoryResponse{ + Success: true, + FuturesType: 2, + Transfers: []*SubAccountFuturesTransfer{{ + From: "aaa@test.com", + To: "bbb@test.com", + Asset: "BTC", + Qty: "1", + TranId: 11897001102, + Time: 1544433328000}, + { + From: "bbb@test.com", + To: "ccc@test.com", + Asset: "ETH", + Qty: "2", + TranId: 11631474902, + Time: 1544433328000}}} + s.assertSubAccountFuturesTransferHistoryResponseEqual(e, res) +} + +func (s *subAccountFuturesTransferHistoryServiceTestSuite) assertSubAccountFuturesTransferHistoryResponseEqual(e, a *SubAccountFuturesTransferHistoryResponse) { + r := s.r() + r.Equal(e.Success, a.Success, "Success") + r.Equal(e.FuturesType, a.FuturesType, "FuturesType") + r.Len(e.Transfers, len(a.Transfers)) + for i := range e.Transfers { + r.Equal(e.Transfers[i].From, a.Transfers[i].From, "Transfers[i].From") + r.Equal(e.Transfers[i].To, a.Transfers[i].To, "Transfers[i].To") + r.Equal(e.Transfers[i].Asset, a.Transfers[i].Asset, "Transfers[i].Asset") + r.Equal(e.Transfers[i].Qty, a.Transfers[i].Qty, "Transfers[i].Qty") + r.Equal(e.Transfers[i].Status, a.Transfers[i].Status, "Transfers[i].Status") + r.Equal(e.Transfers[i].TranId, a.Transfers[i].TranId, "Transfers[i].TranId") + r.Equal(e.Transfers[i].Time, a.Transfers[i].Time, "Transfers[i].Time") + } + +} + +type subAccountFuturesInternalTransferServiceTestSuite struct { + baseTestSuite +} + +func TestSubAccountFuturesInternalTransferService(t *testing.T) { + suite.Run(t, new(subAccountFuturesInternalTransferServiceTestSuite)) +} + +func (s *subAccountFuturesInternalTransferServiceTestSuite) TestSubAccountFuturesInternalTransfer() { + data := []byte(`{ + "success": true, + "txnId": "2934662589" +}`) + s.mockDo(data, nil) + defer s.assertDo() + var fromEmail string = "xxyyzz@gmail.com" + var toEmail string = "jjkk@gmail.com" + var futuresType int64 = 1 + var asset string = "USDT" + var amount string = "1.000085" + s.assertReq(func(r *request) { + e := newSignedRequest().setFormParam("fromEmail", fromEmail).setFormParam("toEmail", toEmail).setFormParam("futuresType", futuresType).setFormParam("asset", asset).setFormParam("amount", amount) + s.assertRequestEqual(e, r) + }) + res, err := s.client.NewSubAccountFuturesInternalTransferService().FromEmail(fromEmail).ToEmail(toEmail).FuturesType(futuresType).Asset(asset).Amount(amount).Do(newContext()) + s.r().NoError(err) + + e := &SubAccountFuturesInternalTransferResponse{ + Success: true, + TxnId: "2934662589"} + s.assertSubAccountFuturesInternalTransferResponseEqual(e, res) +} + +func (s *subAccountFuturesInternalTransferServiceTestSuite) assertSubAccountFuturesInternalTransferResponseEqual(e, a *SubAccountFuturesInternalTransferResponse) { + r := s.r() + r.Equal(e.Success, a.Success, "Success") + r.Equal(e.TxnId, a.TxnId, "TxnId") +} + +type subAccountDepositRecordServiceTestSuite struct { + baseTestSuite +} + +func TestSubAccountDepositRecordService(t *testing.T) { + suite.Run(t, new(subAccountDepositRecordServiceTestSuite)) +} + +func (s *subAccountDepositRecordServiceTestSuite) TestSubAccountDepositRecord() { + data := []byte(`[{ + "id": "769800519366885376", + "amount": "0.001", + "coin": "BNB", + "network": "BNB", + "status": 0, + "address": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", + "addressTag": "101764890", + "txId": "98A3EA560C6B3336D348B6C83F0F95ECE4F1F5919E94BD006E5BF3BF264FACFC", + "insertTime": 1661493146000, + "transferType": 0, + "confirmTimes": "1/1", + "unlockConfirm": 0, + "walletType": 0 + }, + { + "id": "769754833590042625", + "amount": "0.50000000", + "coin": "IOTA", + "network": "IOTA", + "status": 1, + "address": "SIZ9VLMHWATXKV99LH99CIGFJFUMLEHGWVZVNNZXRJJVWBPHYWPPBOSDORZ9EQSHCZAMPVAPGFYQAUUV9DROOXJLNW", + "addressTag": "", + "txId": "ESBFVQUTPIWQNJSPXFNHNYHSQNTGKRVKPRABQWTAXCDWOAKDKYWPTVG9BGXNVNKTLEJGESAVXIKIZ9999", + "insertTime": 1599620082000, + "transferType": 0, + "confirmTimes": "1/1", + "unlockConfirm": 0, + "walletType": 0 + } +]`) + s.mockDo(data, nil) + defer s.assertDo() + var email string = "xxyyzz@gmail.com" + var coin string = "USDT" + var status int32 = 6 + s.assertReq(func(r *request) { + e := newSignedRequest().setParam("email", email).setParam("coin", coin).setParam("status", status) + s.assertRequestEqual(e, r) + }) + res, err := s.client.NewSubAccountDepositRecordService().Email(email).Coin(coin).Status(status).Do(newContext()) + s.r().NoError(err) + + e := []*SubAccountDepositRecord{ + { + Id: "769800519366885376", + Amount: "0.001", + Coin: "BNB", + Network: "BNB", + Status: 0, + Address: "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", + AddressTag: "101764890", + TxId: "98A3EA560C6B3336D348B6C83F0F95ECE4F1F5919E94BD006E5BF3BF264FACFC", + InsertTime: 1661493146000, + TransferType: 0, + ConfirmTimes: "1/1", + UnlockConfirm: 0, + WalletType: 0}, + { + Id: "769754833590042625", + Amount: "0.50000000", + Coin: "IOTA", + Network: "IOTA", + Status: 1, + Address: "SIZ9VLMHWATXKV99LH99CIGFJFUMLEHGWVZVNNZXRJJVWBPHYWPPBOSDORZ9EQSHCZAMPVAPGFYQAUUV9DROOXJLNW", + AddressTag: "", + TxId: "ESBFVQUTPIWQNJSPXFNHNYHSQNTGKRVKPRABQWTAXCDWOAKDKYWPTVG9BGXNVNKTLEJGESAVXIKIZ9999", + InsertTime: 1599620082000, + TransferType: 0, + ConfirmTimes: "1/1", + UnlockConfirm: 0, + WalletType: 0}} + + s.assertSubAccountDepositRecordsEqual(e, res) +} + +func (s *subAccountDepositRecordServiceTestSuite) assertSubAccountDepositRecordEqual(e, a *SubAccountDepositRecord) { + r := s.r() + r.Equal(e.Id, a.Id, "Id") + r.Equal(e.Amount, a.Amount, "Amount") + r.Equal(e.Coin, a.Coin, "Coin") + r.Equal(e.Network, a.Network, "Network") + r.Equal(e.Status, a.Status, "Status") + r.Equal(e.Address, a.Address, "Address") + r.Equal(e.TxId, a.TxId, "TxId") + r.Equal(e.AddressTag, a.AddressTag, "AddressTag") + r.Equal(e.InsertTime, a.InsertTime, "InsertTime") + r.Equal(e.TransferType, a.TransferType, "TransferType") + r.Equal(e.ConfirmTimes, a.ConfirmTimes, "ConfirmTimes") + r.Equal(e.UnlockConfirm, a.UnlockConfirm, "UnlockConfirm") + r.Equal(e.WalletType, a.WalletType, "WalletType") +} + +func (s *subAccountDepositRecordServiceTestSuite) assertSubAccountDepositRecordsEqual(e, a []*SubAccountDepositRecord) { + s.r().Len(e, len(a)) + for i := range e { + s.assertSubAccountDepositRecordEqual(e[i], a[i]) + } +} + +type subAccountMarginFuturesStatusServiceTestSuite struct { + baseTestSuite +} + +func TestSubAccountMarginFuturesStatusService(t *testing.T) { + suite.Run(t, new(subAccountMarginFuturesStatusServiceTestSuite)) +} + +func (s *subAccountMarginFuturesStatusServiceTestSuite) TestSubAccountMarginFuturesStatus() { + data := []byte(`[{ + "email": "123@test.com", + "isSubUserEnabled": true, + "isUserActive": true, + "insertTime": 1570791523523, + "isMarginEnabled": true, + "isFutureEnabled": true, + "mobile": 1570791523523 +}]`) + s.mockDo(data, nil) + defer s.assertDo() + var email string = "xxyyzz@gmail.com" + s.assertReq(func(r *request) { + e := newSignedRequest().setParam("email", email) + s.assertRequestEqual(e, r) + }) + res, err := s.client.NewSubAccountMarginFuturesStatusService().Email(email).Do(newContext()) + s.r().NoError(err) + + e := []*SubAccountMarginFuturesStatus{ + { + Email: "123@test.com", + IsSubUserEnabled: true, + IsUserActive: true, + InsertTime: 1570791523523, + IsMarginEnabled: true, + IsFutureEnabled: true, + Mobile: 1570791523523}} + + s.assertSubAccountMarginFuturesStatusesEqual(e, res) +} + +func (s *subAccountMarginFuturesStatusServiceTestSuite) assertSubAccountMarginFuturesStatusEqual(e, a *SubAccountMarginFuturesStatus) { + r := s.r() + r.Equal(e.Email, a.Email, "Email") + r.Equal(e.IsSubUserEnabled, a.IsSubUserEnabled, "IsSubUserEnabled") + r.Equal(e.IsUserActive, a.IsUserActive, "IsUserActive") + r.Equal(e.InsertTime, a.InsertTime, "InsertTime") + r.Equal(e.IsMarginEnabled, a.IsMarginEnabled, "IsMarginEnabled") + r.Equal(e.IsFutureEnabled, a.IsFutureEnabled, "IsFutureEnabled") + r.Equal(e.Mobile, a.Mobile, "Mobile") +} + +func (s *subAccountMarginFuturesStatusServiceTestSuite) assertSubAccountMarginFuturesStatusesEqual(e, a []*SubAccountMarginFuturesStatus) { + s.r().Len(e, len(a)) + for i := range e { + s.assertSubAccountMarginFuturesStatusEqual(e[i], a[i]) + } +} + +type subAccountMarginEnableServiceTestSuite struct { + baseTestSuite +} + +func TestSubAccountMarginEnableService(t *testing.T) { + suite.Run(t, new(subAccountMarginEnableServiceTestSuite)) +} + +func (s *subAccountMarginEnableServiceTestSuite) TestSubAccountMarginEnable() { + data := []byte(`{ + + "email": "123@test.com", + "isMarginEnabled": true + +}`) + s.mockDo(data, nil) + defer s.assertDo() + var email string = "xxyyzz@gmail.com" + s.assertReq(func(r *request) { + e := newSignedRequest().setFormParam("email", email) + s.assertRequestEqual(e, r) + }) + res, err := s.client.NewSubAccountMarginEnableService().Email(email).Do(newContext()) + s.r().NoError(err) + + e := &SubAccountMarginEnableResponse{ + Email: "123@test.com", + IsMarginEnabled: true} + s.assertSubAccountMarginEnableResponseEqual(e, res) +} + +func (s *subAccountMarginEnableServiceTestSuite) assertSubAccountMarginEnableResponseEqual(e, a *SubAccountMarginEnableResponse) { + r := s.r() + r.Equal(e.Email, a.Email, "Email") + r.Equal(e.IsMarginEnabled, a.IsMarginEnabled, "IsMarginEnabled") +} + +type subAccountMarginAccountInfoServiceTestSuite struct { + baseTestSuite +} + +func TestSubAccountMarginAccountInfoService(t *testing.T) { + suite.Run(t, new(subAccountMarginAccountInfoServiceTestSuite)) +} + +func (s *subAccountMarginAccountInfoServiceTestSuite) TestSubAccountMarginAccountInfo() { + data := []byte(`{ + "email": "123@test.com", + "marginLevel": "11.64405625", + "totalAssetOfBtc": "6.82728457", + "totalLiabilityOfBtc": "0.58633215", + "totalNetAssetOfBtc": "6.24095242", + "marginTradeCoeffVo": { + "forceLiquidationBar": "1.10000000", + "marginCallBar": "1.50000000", + "normalBar": "2.00000000" + }, + "marginUserAssetVoList": [{ + "asset": "BTC", + "borrowed": "0.00000000", + "free": "0.00499500", + "interest": "0.00000000", + "locked": "0.00000000", + "netAsset": "0.00499500" + }, + { + "asset": "BNB", + "borrowed": "201.66666672", + "free": "2346.50000000", + "interest": "0.00000000", + "locked": "0.00000000", + "netAsset": "2144.83333328" + }, + { + "asset": "ETH", + "borrowed": "0.00000000", + "free": "0.00000000", + "interest": "0.00000000", + "locked": "0.00000000", + "netAsset": "0.00000000" + }, + { + "asset": "USDT", + "borrowed": "0.00000000", + "free": "0.00000000", + "interest": "0.00000000", + "locked": "0.00000000", + "netAsset": "0.00000000" + } + ] +}`) + s.mockDo(data, nil) + defer s.assertDo() + var email string = "xxyyzz@gmail.com" + s.assertReq(func(r *request) { + e := newSignedRequest().setParam("email", email) + s.assertRequestEqual(e, r) + }) + res, err := s.client.NewSubAccountMarginAccountInfoService().Email(email).Do(newContext()) + s.r().NoError(err) + + e := &SubAccountMarginAccountInfo{ + Email: "123@test.com", + MarginLevel: "11.64405625", + TotalAssetOfBtc: "6.82728457", + TotalLiabilityOfBtc: "0.58633215", + TotalNetAssetOfBtc: "6.24095242", + MarginTradeCoeffVo: &MarginTradeCoeffVo{ + ForceLiquidationBar: "1.10000000", + MarginCallBar: "1.50000000", + NormalBar: "2.00000000"}, + MarginUserAssetVoList: []*MarginUserAssetVo{{ + Asset: "BTC", + Borrowed: "0.00000000", + Free: "0.00499500", + Interest: "0.00000000", + Locked: "0.00000000", + NetAsset: "0.00499500"}, + { + Asset: "BNB", + Borrowed: "201.66666672", + Free: "2346.50000000", + Interest: "0.00000000", + Locked: "0.00000000", + NetAsset: "2144.83333328"}, + { + Asset: "ETH", + Borrowed: "0.00000000", + Free: "0.00000000", + Interest: "0.00000000", + Locked: "0.00000000", + NetAsset: "0.00000000"}, + { + Asset: "USDT", + Borrowed: "0.00000000", + Free: "0.00000000", + Interest: "0.00000000", + Locked: "0.00000000", + NetAsset: "0.00000000"}}} + s.assertSubAccountMarginAccountInfoEqual(e, res) +} + +func (s *subAccountMarginAccountInfoServiceTestSuite) assertSubAccountMarginAccountInfoEqual(e, a *SubAccountMarginAccountInfo) { + r := s.r() + r.Equal(e.Email, a.Email, "Email") + r.Equal(e.MarginLevel, a.MarginLevel, "MarginLevel") + r.Equal(e.TotalAssetOfBtc, a.TotalAssetOfBtc, "TotalAssetOfBtc") + r.Equal(e.TotalLiabilityOfBtc, a.TotalLiabilityOfBtc, "TotalLiabilityOfBtc") + r.Equal(e.TotalNetAssetOfBtc, a.TotalNetAssetOfBtc, "TotalNetAssetOfBtc") + r.Equal(e.MarginTradeCoeffVo.ForceLiquidationBar, a.MarginTradeCoeffVo.ForceLiquidationBar, "MarginTradeCoeffVo.ForceLiquidationBar") + r.Equal(e.MarginTradeCoeffVo.MarginCallBar, a.MarginTradeCoeffVo.MarginCallBar, "MarginTradeCoeffVo.MarginCallBar") + r.Equal(e.MarginTradeCoeffVo.NormalBar, a.MarginTradeCoeffVo.NormalBar, "MarginTradeCoeffVo.NormalBar") + r.Len(e.MarginUserAssetVoList, len(a.MarginUserAssetVoList)) + for i := range e.MarginUserAssetVoList { + r.Equal(e.MarginUserAssetVoList[i].Asset, a.MarginUserAssetVoList[i].Asset, "MarginUserAssetVoList[i].Asset") + r.Equal(e.MarginUserAssetVoList[i].Borrowed, a.MarginUserAssetVoList[i].Borrowed, "MarginUserAssetVoList[i].Borrowed") + r.Equal(e.MarginUserAssetVoList[i].Free, a.MarginUserAssetVoList[i].Free, "MarginUserAssetVoList[i].Free") + r.Equal(e.MarginUserAssetVoList[i].Interest, a.MarginUserAssetVoList[i].Interest, "MarginUserAssetVoList[i].Interest") + r.Equal(e.MarginUserAssetVoList[i].Locked, a.MarginUserAssetVoList[i].Locked, "MarginUserAssetVoList[i].Locked") + r.Equal(e.MarginUserAssetVoList[i].NetAsset, a.MarginUserAssetVoList[i].NetAsset, "MarginUserAssetVoList[i].NetAsset") + } + +} + +type subAccountMarginAccountSummaryServiceTestSuite struct { + baseTestSuite +} + +func TestSubAccountMarginAccountSummaryService(t *testing.T) { + suite.Run(t, new(subAccountMarginAccountSummaryServiceTestSuite)) +} + +func (s *subAccountMarginAccountSummaryServiceTestSuite) TestSubAccountMarginAccountSummary() { + data := []byte(`{ + "totalAssetOfBtc": "4.33333333", + "totalLiabilityOfBtc": "2.11111112", + "totalNetAssetOfBtc": "2.22222221", + "subAccountList": [{ + "email": "123@test.com", + "totalAssetOfBtc": "2.11111111", + "totalLiabilityOfBtc": "1.11111111", + "totalNetAssetOfBtc": "1.00000000" + }, + { + "email": "345@test.com", + "totalAssetOfBtc": "2.22222222", + "totalLiabilityOfBtc": "1.00000001", + "totalNetAssetOfBtc": "1.22222221" + } + ] +}`) + s.mockDo(data, nil) + defer s.assertDo() + + s.assertReq(func(r *request) { + e := newSignedRequest() + s.assertRequestEqual(e, r) + }) + res, err := s.client.NewSubAccountMarginAccountSummaryService().Do(newContext()) + s.r().NoError(err) + + e := &SubAccountMarginAccountSummary{ + TotalAssetOfBtc: "4.33333333", + TotalLiabilityOfBtc: "2.11111112", + TotalNetAssetOfBtc: "2.22222221", + SubAccountList: []*MarginSubAccount{{ + Email: "123@test.com", + TotalAssetOfBtc: "2.11111111", + TotalLiabilityOfBtc: "1.11111111", + TotalNetAssetOfBtc: "1.00000000"}, + { + Email: "345@test.com", + TotalAssetOfBtc: "2.22222222", + TotalLiabilityOfBtc: "1.00000001", + TotalNetAssetOfBtc: "1.22222221"}}} + s.assertSubAccountMarginAccountSummaryEqual(e, res) +} + +func (s *subAccountMarginAccountSummaryServiceTestSuite) assertSubAccountMarginAccountSummaryEqual(e, a *SubAccountMarginAccountSummary) { + r := s.r() + r.Equal(e.TotalAssetOfBtc, a.TotalAssetOfBtc, "TotalAssetOfBtc") + r.Equal(e.TotalLiabilityOfBtc, a.TotalLiabilityOfBtc, "TotalLiabilityOfBtc") + r.Equal(e.TotalNetAssetOfBtc, a.TotalNetAssetOfBtc, "TotalNetAssetOfBtc") + r.Len(e.SubAccountList, len(a.SubAccountList)) + for i := range e.SubAccountList { + r.Equal(e.SubAccountList[i].Email, a.SubAccountList[i].Email, "SubAccountList[i].Email") + r.Equal(e.SubAccountList[i].TotalAssetOfBtc, a.SubAccountList[i].TotalAssetOfBtc, "SubAccountList[i].TotalAssetOfBtc") + r.Equal(e.SubAccountList[i].TotalLiabilityOfBtc, a.SubAccountList[i].TotalLiabilityOfBtc, "SubAccountList[i].TotalLiabilityOfBtc") + r.Equal(e.SubAccountList[i].TotalNetAssetOfBtc, a.SubAccountList[i].TotalNetAssetOfBtc, "SubAccountList[i].TotalNetAssetOfBtc") + } + +} + +type subAccountFuturesEnableServiceTestSuite struct { + baseTestSuite +} + +func TestSubAccountFuturesEnableService(t *testing.T) { + suite.Run(t, new(subAccountFuturesEnableServiceTestSuite)) +} + +func (s *subAccountFuturesEnableServiceTestSuite) TestSubAccountFuturesEnable() { + data := []byte(`{ + + "email": "123@test.com", + "isFuturesEnabled": true + +}`) + s.mockDo(data, nil) + defer s.assertDo() + var email string = "xxyyzz@gmail.com" + s.assertReq(func(r *request) { + e := newSignedRequest().setFormParam("email", email) + s.assertRequestEqual(e, r) + }) + res, err := s.client.NewSubAccountFuturesEnableService().Email(email).Do(newContext()) + s.r().NoError(err) + + e := &SubAccountFuturesEnableResponse{ + Email: "123@test.com", + IsFuturesEnabled: true} + s.assertSubAccountFuturesEnableResponseEqual(e, res) +} + +func (s *subAccountFuturesEnableServiceTestSuite) assertSubAccountFuturesEnableResponseEqual(e, a *SubAccountFuturesEnableResponse) { + r := s.r() + r.Equal(e.Email, a.Email, "Email") + r.Equal(e.IsFuturesEnabled, a.IsFuturesEnabled, "IsFuturesEnabled") +} + +type subAccountFuturesAccountV2ServiceTestSuite struct { + baseTestSuite +} + +func TestSubAccountFuturesAccountV2Service(t *testing.T) { + suite.Run(t, new(subAccountFuturesAccountV2ServiceTestSuite)) +} + +func (s *subAccountFuturesAccountV2ServiceTestSuite) TestSubAccountFuturesAccountV2() { + data := []byte(`{ + "futureAccountResp": { + "email": "abc@test.com", + "assets": [{ + "asset": "USDT", + "initialMargin": "0.00000000", + "maintenanceMargin": "0.00000000", + "marginBalance": "0.88308000", + "maxWithdrawAmount": "0.88308000", + "openOrderInitialMargin": "0.00000000", + "positionInitialMargin": "0.00000000", + "unrealizedProfit": "0.00000000", + "walletBalance": "0.88308000" + }], + "canDeposit": true, + "canTrade": true, + "canWithdraw": true, + "feeTier": 2, + "maxWithdrawAmount": "0.88308000", + "totalInitialMargin": "0.00000000", + "totalMaintenanceMargin": "0.00000000", + "totalMarginBalance": "0.88308000", + "totalOpenOrderInitialMargin": "0.00000000", + "totalPositionInitialMargin": "0.00000000", + "totalUnrealizedProfit": "0.00000000", + "totalWalletBalance": "0.88308000", + "updateTime": 1576756674610 + }, + "deliveryAccountResp": { + "email": "abc@test.com", + "assets": [{ + "asset": "BTC", + "initialMargin": "0.00000000", + "maintenanceMargin": "0.00000000", + "marginBalance": "0.88308000", + "maxWithdrawAmount": "0.88308000", + "openOrderInitialMargin": "0.00000000", + "positionInitialMargin": "0.00000000", + "unrealizedProfit": "0.00000000", + "walletBalance": "0.88308000" + }], + "canDeposit": true, + "canTrade": true, + "canWithdraw": true, + "feeTier": 2, + "updateTime": 1598959682001 + } +}`) + s.mockDo(data, nil) + defer s.assertDo() + var email string = "xxyyzz@gmail.com" + var futuresType int32 = 1 + s.assertReq(func(r *request) { + e := newSignedRequest().setParam("email", email).setParam("futuresType", futuresType) + s.assertRequestEqual(e, r) + }) + res, err := s.client.NewSubAccountFuturesAccountV2Service().Email(email).FuturesType(futuresType).Do(newContext()) + s.r().NoError(err) + + e := &SubAccountFuturesAccountV2ServiceResponse{ + FutureAccountResp: &SubAccountFuturesAccountV2{ + Email: "abc@test.com", + Assets: []*FuturesAsset{{ + Asset: "USDT", + InitialMargin: "0.00000000", + MaintenanceMargin: "0.00000000", + MarginBalance: "0.88308000", + MaxWithdrawAmount: "0.88308000", + OpenOrderInitialMargin: "0.00000000", + PositionInitialMargin: "0.00000000", + UnrealizedProfit: "0.00000000", + WalletBalance: "0.88308000"}}, + CanDeposit: true, + CanTrade: true, + CanWithdraw: true, + FeeTier: 2, + MaxWithdrawAmount: "0.88308000", + TotalInitialMargin: "0.00000000", + TotalMaintenanceMargin: "0.00000000", + TotalMarginBalance: "0.88308000", + TotalOpenOrderInitialMargin: "0.00000000", + TotalPositionInitialMargin: "0.00000000", + TotalUnrealizedProfit: "0.00000000", + TotalWalletBalance: "0.88308000", + UpdateTime: 1576756674610}, + DeliveryAccountResp: &SubAccountDeliveryAccountV2{ + Email: "abc@test.com", + Assets: []*FuturesAsset{{ + Asset: "BTC", + InitialMargin: "0.00000000", + MaintenanceMargin: "0.00000000", + MarginBalance: "0.88308000", + MaxWithdrawAmount: "0.88308000", + OpenOrderInitialMargin: "0.00000000", + PositionInitialMargin: "0.00000000", + UnrealizedProfit: "0.00000000", + WalletBalance: "0.88308000"}}, + CanDeposit: true, + CanTrade: true, + CanWithdraw: true, + FeeTier: 2, + UpdateTime: 1598959682001}} + s.assertSubAccountFuturesAccountV2ServiceResponseEqual(e, res) +} + +func (s *subAccountFuturesAccountV2ServiceTestSuite) assertSubAccountFuturesAccountV2ServiceResponseEqual(e, a *SubAccountFuturesAccountV2ServiceResponse) { + r := s.r() + r.Equal(e.FutureAccountResp.Email, a.FutureAccountResp.Email, "FutureAccountResp.Email") + r.Equal(e.FutureAccountResp.Asset, a.FutureAccountResp.Asset, "FutureAccountResp.Asset") + r.Len(e.FutureAccountResp.Assets, len(a.FutureAccountResp.Assets)) + for j := range e.FutureAccountResp.Assets { + r.Equal(e.FutureAccountResp.Assets[j].Asset, a.FutureAccountResp.Assets[j].Asset, "FutureAccountResp.Assets[j].Asset") + r.Equal(e.FutureAccountResp.Assets[j].InitialMargin, a.FutureAccountResp.Assets[j].InitialMargin, "FutureAccountResp.Assets[j].InitialMargin") + r.Equal(e.FutureAccountResp.Assets[j].MaintenanceMargin, a.FutureAccountResp.Assets[j].MaintenanceMargin, "FutureAccountResp.Assets[j].MaintenanceMargin") + r.Equal(e.FutureAccountResp.Assets[j].MarginBalance, a.FutureAccountResp.Assets[j].MarginBalance, "FutureAccountResp.Assets[j].MarginBalance") + r.Equal(e.FutureAccountResp.Assets[j].MaxWithdrawAmount, a.FutureAccountResp.Assets[j].MaxWithdrawAmount, "FutureAccountResp.Assets[j].MaxWithdrawAmount") + r.Equal(e.FutureAccountResp.Assets[j].OpenOrderInitialMargin, a.FutureAccountResp.Assets[j].OpenOrderInitialMargin, "FutureAccountResp.Assets[j].OpenOrderInitialMargin") + r.Equal(e.FutureAccountResp.Assets[j].PositionInitialMargin, a.FutureAccountResp.Assets[j].PositionInitialMargin, "FutureAccountResp.Assets[j].PositionInitialMargin") + r.Equal(e.FutureAccountResp.Assets[j].UnrealizedProfit, a.FutureAccountResp.Assets[j].UnrealizedProfit, "FutureAccountResp.Assets[j].UnrealizedProfit") + r.Equal(e.FutureAccountResp.Assets[j].WalletBalance, a.FutureAccountResp.Assets[j].WalletBalance, "FutureAccountResp.Assets[j].WalletBalance") + } + + r.Equal(e.FutureAccountResp.CanDeposit, a.FutureAccountResp.CanDeposit, "FutureAccountResp.CanDeposit") + r.Equal(e.FutureAccountResp.CanTrade, a.FutureAccountResp.CanTrade, "FutureAccountResp.CanTrade") + r.Equal(e.FutureAccountResp.CanWithdraw, a.FutureAccountResp.CanWithdraw, "FutureAccountResp.CanWithdraw") + r.Equal(e.FutureAccountResp.FeeTier, a.FutureAccountResp.FeeTier, "FutureAccountResp.FeeTier") + r.Equal(e.FutureAccountResp.MaxWithdrawAmount, a.FutureAccountResp.MaxWithdrawAmount, "FutureAccountResp.MaxWithdrawAmount") + r.Equal(e.FutureAccountResp.TotalInitialMargin, a.FutureAccountResp.TotalInitialMargin, "FutureAccountResp.TotalInitialMargin") + r.Equal(e.FutureAccountResp.TotalMaintenanceMargin, a.FutureAccountResp.TotalMaintenanceMargin, "FutureAccountResp.TotalMaintenanceMargin") + r.Equal(e.FutureAccountResp.TotalMarginBalance, a.FutureAccountResp.TotalMarginBalance, "FutureAccountResp.TotalMarginBalance") + r.Equal(e.FutureAccountResp.TotalOpenOrderInitialMargin, a.FutureAccountResp.TotalOpenOrderInitialMargin, "FutureAccountResp.TotalOpenOrderInitialMargin") + r.Equal(e.FutureAccountResp.TotalPositionInitialMargin, a.FutureAccountResp.TotalPositionInitialMargin, "FutureAccountResp.TotalPositionInitialMargin") + r.Equal(e.FutureAccountResp.TotalUnrealizedProfit, a.FutureAccountResp.TotalUnrealizedProfit, "FutureAccountResp.TotalUnrealizedProfit") + r.Equal(e.FutureAccountResp.TotalWalletBalance, a.FutureAccountResp.TotalWalletBalance, "FutureAccountResp.TotalWalletBalance") + r.Equal(e.FutureAccountResp.UpdateTime, a.FutureAccountResp.UpdateTime, "FutureAccountResp.UpdateTime") + r.Equal(e.DeliveryAccountResp.Email, a.DeliveryAccountResp.Email, "DeliveryAccountResp.Email") + r.Len(e.DeliveryAccountResp.Assets, len(a.DeliveryAccountResp.Assets)) + for j := range e.DeliveryAccountResp.Assets { + r.Equal(e.DeliveryAccountResp.Assets[j].Asset, a.DeliveryAccountResp.Assets[j].Asset, "DeliveryAccountResp.Assets[j].Asset") + r.Equal(e.DeliveryAccountResp.Assets[j].InitialMargin, a.DeliveryAccountResp.Assets[j].InitialMargin, "DeliveryAccountResp.Assets[j].InitialMargin") + r.Equal(e.DeliveryAccountResp.Assets[j].MaintenanceMargin, a.DeliveryAccountResp.Assets[j].MaintenanceMargin, "DeliveryAccountResp.Assets[j].MaintenanceMargin") + r.Equal(e.DeliveryAccountResp.Assets[j].MarginBalance, a.DeliveryAccountResp.Assets[j].MarginBalance, "DeliveryAccountResp.Assets[j].MarginBalance") + r.Equal(e.DeliveryAccountResp.Assets[j].MaxWithdrawAmount, a.DeliveryAccountResp.Assets[j].MaxWithdrawAmount, "DeliveryAccountResp.Assets[j].MaxWithdrawAmount") + r.Equal(e.DeliveryAccountResp.Assets[j].OpenOrderInitialMargin, a.DeliveryAccountResp.Assets[j].OpenOrderInitialMargin, "DeliveryAccountResp.Assets[j].OpenOrderInitialMargin") + r.Equal(e.DeliveryAccountResp.Assets[j].PositionInitialMargin, a.DeliveryAccountResp.Assets[j].PositionInitialMargin, "DeliveryAccountResp.Assets[j].PositionInitialMargin") + r.Equal(e.DeliveryAccountResp.Assets[j].UnrealizedProfit, a.DeliveryAccountResp.Assets[j].UnrealizedProfit, "DeliveryAccountResp.Assets[j].UnrealizedProfit") + r.Equal(e.DeliveryAccountResp.Assets[j].WalletBalance, a.DeliveryAccountResp.Assets[j].WalletBalance, "DeliveryAccountResp.Assets[j].WalletBalance") + } + + r.Equal(e.DeliveryAccountResp.CanDeposit, a.DeliveryAccountResp.CanDeposit, "DeliveryAccountResp.CanDeposit") + r.Equal(e.DeliveryAccountResp.CanTrade, a.DeliveryAccountResp.CanTrade, "DeliveryAccountResp.CanTrade") + r.Equal(e.DeliveryAccountResp.CanWithdraw, a.DeliveryAccountResp.CanWithdraw, "DeliveryAccountResp.CanWithdraw") + r.Equal(e.DeliveryAccountResp.FeeTier, a.DeliveryAccountResp.FeeTier, "DeliveryAccountResp.FeeTier") + r.Equal(e.DeliveryAccountResp.UpdateTime, a.DeliveryAccountResp.UpdateTime, "DeliveryAccountResp.UpdateTime") +} + +type subAccountFuturesAccountSummaryServiceTestSuite struct { + baseTestSuite +} + +func TestSubAccountFuturesAccountSummaryService(t *testing.T) { + suite.Run(t, new(subAccountFuturesAccountSummaryServiceTestSuite)) +} + +func (s *subAccountFuturesAccountSummaryServiceTestSuite) TestSubAccountFuturesAccountSummary() { + data := []byte(`{ + "futureAccountSummaryResp": { + "totalInitialMargin": "9.83137400", + "totalMaintenanceMargin": "0.41568700", + "totalMarginBalance": "23.03235621", + "totalOpenOrderInitialMargin": "9.00000000", + "totalPositionInitialMargin": "0.83137400", + "totalUnrealizedProfit": "0.03219710", + "totalWalletBalance": "22.15879444", + "asset": "USD", + "subAccountList": [{ + "email": "123@test.com", + "totalInitialMargin": "9.00000000", + "totalMaintenanceMargin": "0.00000000", + "totalMarginBalance": "22.12659734", + "totalOpenOrderInitialMargin": "9.00000000", + "totalPositionInitialMargin": "0.00000000", + "totalUnrealizedProfit": "0.00000000", + "totalWalletBalance": "22.12659734", + "asset": "USD" + }, + { + "email": "345@test.com", + "totalInitialMargin": "0.83137400", + "totalMaintenanceMargin": "0.41568700", + "totalMarginBalance": "0.90575887", + "totalOpenOrderInitialMargin": "0.00000000", + "totalPositionInitialMargin": "0.83137400", + "totalUnrealizedProfit": "0.03219710", + "totalWalletBalance": "0.87356177", + "asset": "USD" + } + ] + }, + + "deliveryAccountSummaryResp": { + "totalMarginBalanceOfBTC": "25.03221121", + "totalUnrealizedProfitOfBTC": "0.12233410", + "totalWalletBalanceOfBTC": "22.15879444", + "asset": "BTC", + "subAccountList": [{ + "email": "123@test.com", + "totalMarginBalance": "22.12659734", + "totalUnrealizedProfit": "0.00000000", + "totalWalletBalance": "22.12659734", + "asset": "BTC" + }, + { + "email": "345@test.com", + "totalMarginBalance": "0.90575887", + "totalUnrealizedProfit": "0.03219710", + "totalWalletBalance": "0.87356177", + "asset": "BTC" + } + ] + } +}`) + s.mockDo(data, nil) + defer s.assertDo() + var futuresType int32 = 1 + s.assertReq(func(r *request) { + e := newSignedRequest().setParam("futuresType", futuresType) + s.assertRequestEqual(e, r) + }) + res, err := s.client.NewSubAccountFuturesAccountSummaryService().FuturesType(futuresType).Do(newContext()) + s.r().NoError(err) + + e := &SubAccountFuturesAccountSummaryServiceResponse{ + FutureAccountSummaryResp: &SubAccountFuturesAccountSummary{ + TotalInitialMargin: "9.83137400", + TotalMaintenanceMargin: "0.41568700", + TotalMarginBalance: "23.03235621", + TotalOpenOrderInitialMargin: "9.00000000", + TotalPositionInitialMargin: "0.83137400", + TotalUnrealizedProfit: "0.03219710", + TotalWalletBalance: "22.15879444", + Asset: "USD", + SubAccountList: []*FuturesSubAccount{{ + Email: "123@test.com", + TotalInitialMargin: "9.00000000", + TotalMaintenanceMargin: "0.00000000", + TotalMarginBalance: "22.12659734", + TotalOpenOrderInitialMargin: "9.00000000", + TotalPositionInitialMargin: "0.00000000", + TotalUnrealizedProfit: "0.00000000", + TotalWalletBalance: "22.12659734", + Asset: "USD"}, + { + Email: "345@test.com", + TotalInitialMargin: "0.83137400", + TotalMaintenanceMargin: "0.41568700", + TotalMarginBalance: "0.90575887", + TotalOpenOrderInitialMargin: "0.00000000", + TotalPositionInitialMargin: "0.83137400", + TotalUnrealizedProfit: "0.03219710", + TotalWalletBalance: "0.87356177", + Asset: "USD"}}}, + DeliveryAccountSummaryResp: &SubAccountDeliveryAccountSummary{ + TotalMarginBalanceOfBTC: "25.03221121", + TotalUnrealizedProfitOfBTC: "0.12233410", + TotalWalletBalanceOfBTC: "22.15879444", + Asset: "BTC", + SubAccountList: []*DeliverySubAccount{{ + Email: "123@test.com", + TotalMarginBalance: "22.12659734", + TotalUnrealizedProfit: "0.00000000", + TotalWalletBalance: "22.12659734", + Asset: "BTC"}, + { + Email: "345@test.com", + TotalMarginBalance: "0.90575887", + TotalUnrealizedProfit: "0.03219710", + TotalWalletBalance: "0.87356177", + Asset: "BTC"}}}} + s.assertSubAccountFuturesAccountSummaryServiceResponseEqual(e, res) +} + +func (s *subAccountFuturesAccountSummaryServiceTestSuite) assertSubAccountFuturesAccountSummaryServiceResponseEqual(e, a *SubAccountFuturesAccountSummaryServiceResponse) { + r := s.r() + r.Equal(e.FutureAccountSummaryResp.TotalInitialMargin, a.FutureAccountSummaryResp.TotalInitialMargin, "FutureAccountSummaryResp.TotalInitialMargin") + r.Equal(e.FutureAccountSummaryResp.TotalMaintenanceMargin, a.FutureAccountSummaryResp.TotalMaintenanceMargin, "FutureAccountSummaryResp.TotalMaintenanceMargin") + r.Equal(e.FutureAccountSummaryResp.TotalMarginBalance, a.FutureAccountSummaryResp.TotalMarginBalance, "FutureAccountSummaryResp.TotalMarginBalance") + r.Equal(e.FutureAccountSummaryResp.TotalOpenOrderInitialMargin, a.FutureAccountSummaryResp.TotalOpenOrderInitialMargin, "FutureAccountSummaryResp.TotalOpenOrderInitialMargin") + r.Equal(e.FutureAccountSummaryResp.TotalPositionInitialMargin, a.FutureAccountSummaryResp.TotalPositionInitialMargin, "FutureAccountSummaryResp.TotalPositionInitialMargin") + r.Equal(e.FutureAccountSummaryResp.TotalUnrealizedProfit, a.FutureAccountSummaryResp.TotalUnrealizedProfit, "FutureAccountSummaryResp.TotalUnrealizedProfit") + r.Equal(e.FutureAccountSummaryResp.TotalWalletBalance, a.FutureAccountSummaryResp.TotalWalletBalance, "FutureAccountSummaryResp.TotalWalletBalance") + r.Equal(e.FutureAccountSummaryResp.Asset, a.FutureAccountSummaryResp.Asset, "FutureAccountSummaryResp.Asset") + r.Len(e.FutureAccountSummaryResp.SubAccountList, len(a.FutureAccountSummaryResp.SubAccountList)) + for j := range e.FutureAccountSummaryResp.SubAccountList { + r.Equal(e.FutureAccountSummaryResp.SubAccountList[j].Email, a.FutureAccountSummaryResp.SubAccountList[j].Email, "FutureAccountSummaryResp.SubAccountList[j].Email") + r.Equal(e.FutureAccountSummaryResp.SubAccountList[j].TotalInitialMargin, a.FutureAccountSummaryResp.SubAccountList[j].TotalInitialMargin, "FutureAccountSummaryResp.SubAccountList[j].TotalInitialMargin") + r.Equal(e.FutureAccountSummaryResp.SubAccountList[j].TotalMaintenanceMargin, a.FutureAccountSummaryResp.SubAccountList[j].TotalMaintenanceMargin, "FutureAccountSummaryResp.SubAccountList[j].TotalMaintenanceMargin") + r.Equal(e.FutureAccountSummaryResp.SubAccountList[j].TotalMarginBalance, a.FutureAccountSummaryResp.SubAccountList[j].TotalMarginBalance, "FutureAccountSummaryResp.SubAccountList[j].TotalMarginBalance") + r.Equal(e.FutureAccountSummaryResp.SubAccountList[j].TotalOpenOrderInitialMargin, a.FutureAccountSummaryResp.SubAccountList[j].TotalOpenOrderInitialMargin, "FutureAccountSummaryResp.SubAccountList[j].TotalOpenOrderInitialMargin") + r.Equal(e.FutureAccountSummaryResp.SubAccountList[j].TotalPositionInitialMargin, a.FutureAccountSummaryResp.SubAccountList[j].TotalPositionInitialMargin, "FutureAccountSummaryResp.SubAccountList[j].TotalPositionInitialMargin") + r.Equal(e.FutureAccountSummaryResp.SubAccountList[j].TotalUnrealizedProfit, a.FutureAccountSummaryResp.SubAccountList[j].TotalUnrealizedProfit, "FutureAccountSummaryResp.SubAccountList[j].TotalUnrealizedProfit") + r.Equal(e.FutureAccountSummaryResp.SubAccountList[j].TotalWalletBalance, a.FutureAccountSummaryResp.SubAccountList[j].TotalWalletBalance, "FutureAccountSummaryResp.SubAccountList[j].TotalWalletBalance") + r.Equal(e.FutureAccountSummaryResp.SubAccountList[j].Asset, a.FutureAccountSummaryResp.SubAccountList[j].Asset, "FutureAccountSummaryResp.SubAccountList[j].Asset") + } + + r.Equal(e.DeliveryAccountSummaryResp.TotalMarginBalanceOfBTC, a.DeliveryAccountSummaryResp.TotalMarginBalanceOfBTC, "DeliveryAccountSummaryResp.TotalMarginBalanceOfBTC") + r.Equal(e.DeliveryAccountSummaryResp.TotalUnrealizedProfitOfBTC, a.DeliveryAccountSummaryResp.TotalUnrealizedProfitOfBTC, "DeliveryAccountSummaryResp.TotalUnrealizedProfitOfBTC") + r.Equal(e.DeliveryAccountSummaryResp.TotalWalletBalanceOfBTC, a.DeliveryAccountSummaryResp.TotalWalletBalanceOfBTC, "DeliveryAccountSummaryResp.TotalWalletBalanceOfBTC") + r.Equal(e.DeliveryAccountSummaryResp.Asset, a.DeliveryAccountSummaryResp.Asset, "DeliveryAccountSummaryResp.Asset") + r.Len(e.DeliveryAccountSummaryResp.SubAccountList, len(a.DeliveryAccountSummaryResp.SubAccountList)) + for j := range e.DeliveryAccountSummaryResp.SubAccountList { + r.Equal(e.DeliveryAccountSummaryResp.SubAccountList[j].Email, a.DeliveryAccountSummaryResp.SubAccountList[j].Email, "DeliveryAccountSummaryResp.SubAccountList[j].Email") + r.Equal(e.DeliveryAccountSummaryResp.SubAccountList[j].TotalMarginBalance, a.DeliveryAccountSummaryResp.SubAccountList[j].TotalMarginBalance, "DeliveryAccountSummaryResp.SubAccountList[j].TotalMarginBalance") + r.Equal(e.DeliveryAccountSummaryResp.SubAccountList[j].TotalUnrealizedProfit, a.DeliveryAccountSummaryResp.SubAccountList[j].TotalUnrealizedProfit, "DeliveryAccountSummaryResp.SubAccountList[j].TotalUnrealizedProfit") + r.Equal(e.DeliveryAccountSummaryResp.SubAccountList[j].TotalWalletBalance, a.DeliveryAccountSummaryResp.SubAccountList[j].TotalWalletBalance, "DeliveryAccountSummaryResp.SubAccountList[j].TotalWalletBalance") + r.Equal(e.DeliveryAccountSummaryResp.SubAccountList[j].Asset, a.DeliveryAccountSummaryResp.SubAccountList[j].Asset, "DeliveryAccountSummaryResp.SubAccountList[j].Asset") + } + +} + +type subAccountFuturesPositionsServiceTestSuite struct { + baseTestSuite +} + +func TestSubAccountFuturesPositionsService(t *testing.T) { + suite.Run(t, new(subAccountFuturesPositionsServiceTestSuite)) +} + +func (s *subAccountFuturesPositionsServiceTestSuite) TestSubAccountFuturesPositions() { + data := []byte(`{ + "futurePositionRiskVos": [{ + "entryPrice": "9975.12000", + "leverage": "50", + "maxNotional": "1000000", + "liquidationPrice": "7963.54", + "markPrice": "9973.50770517", + "positionAmount": "0.010", + "symbol": "BTCUSDT", + "unrealizedProfit": "-0.01612295" + }], + "deliveryPositionRiskVos": [{ + "entryPrice": "9975.12000", + "markPrice": "9973.50770517", + "leverage": "20", + "isolated": "false", + "isolatedWallet": "9973.50770517", + "isolatedMargin": "0.00000000", + "isAutoAddMargin": "false", + "positionSide": "BOTH", + "positionAmount": "1.230", + "symbol": "BTCUSD_201225", + "unrealizedProfit": "-0.01612295" + }] +}`) + s.mockDo(data, nil) + defer s.assertDo() + var email string = "xxyyzz@gmail.com" + var futuresType int32 = 1 + s.assertReq(func(r *request) { + e := newSignedRequest().setParam("email", email).setParam("futuresType", futuresType) + s.assertRequestEqual(e, r) + }) + res, err := s.client.NewSubAccountFuturesPositionsService().Email(email).FuturesType(futuresType).Do(newContext()) + s.r().NoError(err) + + e := &SubAccountFuturesPositionsServiceResponse{ + FuturePositionRiskVos: []*SubAccountFuturesPosition{{ + EntryPrice: "9975.12000", + Leverage: "50", + MaxNotional: "1000000", + LiquidationPrice: "7963.54", + MarkPrice: "9973.50770517", + PositionAmount: "0.010", + Symbol: "BTCUSDT", + UnrealizedProfit: "-0.01612295"}}, + DeliveryPositionRiskVos: []*SubAccountDeliveryPosition{{ + EntryPrice: "9975.12000", + MarkPrice: "9973.50770517", + Leverage: "20", + Isolated: "false", + IsolatedWallet: "9973.50770517", + IsolatedMargin: "0.00000000", + IsAutoAddMargin: "false", + PositionSide: "BOTH", + PositionAmount: "1.230", + Symbol: "BTCUSD_201225", + UnrealizedProfit: "-0.01612295"}}} + s.assertSubAccountFuturesPositionsServiceResponseEqual(e, res) +} + +func (s *subAccountFuturesPositionsServiceTestSuite) assertSubAccountFuturesPositionsServiceResponseEqual(e, a *SubAccountFuturesPositionsServiceResponse) { + r := s.r() + r.Len(e.FuturePositionRiskVos, len(a.FuturePositionRiskVos)) + for i := range e.FuturePositionRiskVos { + r.Equal(e.FuturePositionRiskVos[i].EntryPrice, a.FuturePositionRiskVos[i].EntryPrice, "FuturePositionRiskVos[i].EntryPrice") + r.Equal(e.FuturePositionRiskVos[i].Leverage, a.FuturePositionRiskVos[i].Leverage, "FuturePositionRiskVos[i].Leverage") + r.Equal(e.FuturePositionRiskVos[i].MaxNotional, a.FuturePositionRiskVos[i].MaxNotional, "FuturePositionRiskVos[i].MaxNotional") + r.Equal(e.FuturePositionRiskVos[i].LiquidationPrice, a.FuturePositionRiskVos[i].LiquidationPrice, "FuturePositionRiskVos[i].LiquidationPrice") + r.Equal(e.FuturePositionRiskVos[i].MarkPrice, a.FuturePositionRiskVos[i].MarkPrice, "FuturePositionRiskVos[i].MarkPrice") + r.Equal(e.FuturePositionRiskVos[i].PositionAmount, a.FuturePositionRiskVos[i].PositionAmount, "FuturePositionRiskVos[i].PositionAmount") + r.Equal(e.FuturePositionRiskVos[i].Symbol, a.FuturePositionRiskVos[i].Symbol, "FuturePositionRiskVos[i].Symbol") + r.Equal(e.FuturePositionRiskVos[i].UnrealizedProfit, a.FuturePositionRiskVos[i].UnrealizedProfit, "FuturePositionRiskVos[i].UnrealizedProfit") + } + + r.Len(e.DeliveryPositionRiskVos, len(a.DeliveryPositionRiskVos)) + for i := range e.DeliveryPositionRiskVos { + r.Equal(e.DeliveryPositionRiskVos[i].EntryPrice, a.DeliveryPositionRiskVos[i].EntryPrice, "DeliveryPositionRiskVos[i].EntryPrice") + r.Equal(e.DeliveryPositionRiskVos[i].MarkPrice, a.DeliveryPositionRiskVos[i].MarkPrice, "DeliveryPositionRiskVos[i].MarkPrice") + r.Equal(e.DeliveryPositionRiskVos[i].Leverage, a.DeliveryPositionRiskVos[i].Leverage, "DeliveryPositionRiskVos[i].Leverage") + r.Equal(e.DeliveryPositionRiskVos[i].Isolated, a.DeliveryPositionRiskVos[i].Isolated, "DeliveryPositionRiskVos[i].Isolated") + r.Equal(e.DeliveryPositionRiskVos[i].IsolatedWallet, a.DeliveryPositionRiskVos[i].IsolatedWallet, "DeliveryPositionRiskVos[i].IsolatedWallet") + r.Equal(e.DeliveryPositionRiskVos[i].IsolatedMargin, a.DeliveryPositionRiskVos[i].IsolatedMargin, "DeliveryPositionRiskVos[i].IsolatedMargin") + r.Equal(e.DeliveryPositionRiskVos[i].IsAutoAddMargin, a.DeliveryPositionRiskVos[i].IsAutoAddMargin, "DeliveryPositionRiskVos[i].IsAutoAddMargin") + r.Equal(e.DeliveryPositionRiskVos[i].PositionSide, a.DeliveryPositionRiskVos[i].PositionSide, "DeliveryPositionRiskVos[i].PositionSide") + r.Equal(e.DeliveryPositionRiskVos[i].PositionAmount, a.DeliveryPositionRiskVos[i].PositionAmount, "DeliveryPositionRiskVos[i].PositionAmount") + r.Equal(e.DeliveryPositionRiskVos[i].Symbol, a.DeliveryPositionRiskVos[i].Symbol, "DeliveryPositionRiskVos[i].Symbol") + r.Equal(e.DeliveryPositionRiskVos[i].UnrealizedProfit, a.DeliveryPositionRiskVos[i].UnrealizedProfit, "DeliveryPositionRiskVos[i].UnrealizedProfit") + } + +} + +type subAccountMarginTransferServiceTestSuite struct { + baseTestSuite +} + +func TestSubAccountMarginTransferService(t *testing.T) { + suite.Run(t, new(subAccountMarginTransferServiceTestSuite)) +} + +func (s *subAccountMarginTransferServiceTestSuite) TestSubAccountMarginTransfer() { + data := []byte(`{ + "txnId":"2966662589" +}`) + s.mockDo(data, nil) + defer s.assertDo() + var email string = "xxyyzz@gmail.com" + var asset string = "USDT" + var amount string = "0.0125586" + var transferType int32 = 1 + s.assertReq(func(r *request) { + e := newSignedRequest().setFormParam("email", email).setFormParam("asset", asset).setFormParam("amount", amount).setFormParam("type", transferType) + s.assertRequestEqual(e, r) + }) + res, err := s.client.NewSubAccountMarginTransferService().Email(email).Asset(asset).Amount(amount).TransferType(transferType).Do(newContext()) + s.r().NoError(err) + + e := &SubAccountMarginTransferResponse{ + TxnId: "2966662589"} + s.assertSubAccountMarginTransferResponseEqual(e, res) +} + +func (s *subAccountMarginTransferServiceTestSuite) assertSubAccountMarginTransferResponseEqual(e, a *SubAccountMarginTransferResponse) { + r := s.r() + r.Equal(e.TxnId, a.TxnId, "TxnId") +} + +type subAccountTransferSubToMasterServiceTestSuite struct { + baseTestSuite +} + +func TestSubAccountTransferSubToMasterService(t *testing.T) { + suite.Run(t, new(subAccountTransferSubToMasterServiceTestSuite)) +} + +func (s *subAccountTransferSubToMasterServiceTestSuite) TestSubAccountTransferSubToMaster() { + data := []byte(`{ + "txnId":"2966662589" +}`) + s.mockDo(data, nil) + defer s.assertDo() + var asset string = "USDT" + var amount string = "0.0125586" + s.assertReq(func(r *request) { + e := newSignedRequest().setFormParam("asset", asset).setFormParam("amount", amount) + s.assertRequestEqual(e, r) + }) + res, err := s.client.NewSubAccountTransferSubToMasterService().Asset(asset).Amount(amount).Do(newContext()) + s.r().NoError(err) + + e := &SubAccountTransferSubToMasterResponse{ + TxnId: "2966662589"} + s.assertSubAccountTransferSubToMasterResponseEqual(e, res) +} + +func (s *subAccountTransferSubToMasterServiceTestSuite) assertSubAccountTransferSubToMasterResponseEqual(e, a *SubAccountTransferSubToMasterResponse) { + r := s.r() + r.Equal(e.TxnId, a.TxnId, "TxnId") +} + +type subAccountUniversalTransferServiceTestSuite struct { + baseTestSuite +} + +func TestSubAccountUniversalTransferService(t *testing.T) { + suite.Run(t, new(subAccountUniversalTransferServiceTestSuite)) +} + +func (s *subAccountUniversalTransferServiceTestSuite) TestSubAccountUniversalTransfer() { + data := []byte(`{ + "tranId":11945860693, + "clientTranId":"test" +}`) + s.mockDo(data, nil) + defer s.assertDo() + var fromAccountType string = "SPOT" + var toAccountType string = "USDT_FUTURE" + var asset string = "USDT" + var amount string = "0.0125586" + s.assertReq(func(r *request) { + e := newSignedRequest().setFormParam("fromAccountType", fromAccountType).setFormParam("toAccountType", toAccountType).setFormParam("asset", asset).setFormParam("amount", amount) + s.assertRequestEqual(e, r) + }) + res, err := s.client.NewSubAccountUniversalTransferService().FromAccountType(fromAccountType).ToAccountType(toAccountType).Asset(asset).Amount(amount).Do(newContext()) + s.r().NoError(err) + + e := &SubAccountUniversalTransferResponse{ + TranId: 11945860693, + ClientTranId: "test"} + s.assertSubAccountUniversalTransferResponseEqual(e, res) +} + +func (s *subAccountUniversalTransferServiceTestSuite) assertSubAccountUniversalTransferResponseEqual(e, a *SubAccountUniversalTransferResponse) { + r := s.r() + r.Equal(e.TranId, a.TranId, "TranId") + r.Equal(e.ClientTranId, a.ClientTranId, "ClientTranId") +} + +type subAccUniversalTransferHistoryServiceTestSuite struct { + baseTestSuite +} + +func TestSubAccUniversalTransferHistoryService(t *testing.T) { + suite.Run(t, new(subAccUniversalTransferHistoryServiceTestSuite)) +} + +func (s *subAccUniversalTransferHistoryServiceTestSuite) TestSubAccUniversalTransferHistory() { + data := []byte(`{ + "result": [{ + "tranId": 92275823339, + "fromEmail": "abctest@gmail.com", + "toEmail": "deftest@gmail.com", + "asset": "BNB", + "amount": "0.01", + "createTimeStamp": 1640317374000, + "fromAccountType": "USDT_FUTURE", + "toAccountType": "SPOT", + "status": "SUCCESS", + "clientTranId": "test" + }], + "totalCount": 1 +}`) + s.mockDo(data, nil) + defer s.assertDo() + var fromEmail string = "xxyyzz@gmail.com" + s.assertReq(func(r *request) { + e := newSignedRequest().setParam("fromEmail", fromEmail) + s.assertRequestEqual(e, r) + }) + res, err := s.client.NewSubAccUniversalTransferHistoryService().FromEmail(fromEmail).Do(newContext()) + s.r().NoError(err) + + e := &SubAccountUniversalTransferHistoryServiceResponse{ + Result: []*SubAccountUniversalTransferRecord{{ + TranId: 92275823339, + FromEmail: "abctest@gmail.com", + ToEmail: "deftest@gmail.com", + Asset: "BNB", + Amount: "0.01", + CreateTimeStamp: 1640317374000, + FromAccountType: "USDT_FUTURE", + ToAccountType: "SPOT", + Status: "SUCCESS", + ClientTranId: "test"}}, + TotalCount: 1} + s.assertSubAccountUniversalTransferHistoryServiceResponseEqual(e, res) +} + +func (s *subAccUniversalTransferHistoryServiceTestSuite) assertSubAccountUniversalTransferHistoryServiceResponseEqual(e, a *SubAccountUniversalTransferHistoryServiceResponse) { + r := s.r() + r.Len(e.Result, len(a.Result)) + for i := range e.Result { + r.Equal(e.Result[i].TranId, a.Result[i].TranId, "Result[i].TranId") + r.Equal(e.Result[i].FromEmail, a.Result[i].FromEmail, "Result[i].FromEmail") + r.Equal(e.Result[i].ToEmail, a.Result[i].ToEmail, "Result[i].ToEmail") + r.Equal(e.Result[i].Asset, a.Result[i].Asset, "Result[i].Asset") + r.Equal(e.Result[i].Amount, a.Result[i].Amount, "Result[i].Amount") + r.Equal(e.Result[i].CreateTimeStamp, a.Result[i].CreateTimeStamp, "Result[i].CreateTimeStamp") + r.Equal(e.Result[i].FromAccountType, a.Result[i].FromAccountType, "Result[i].FromAccountType") + r.Equal(e.Result[i].ToAccountType, a.Result[i].ToAccountType, "Result[i].ToAccountType") + r.Equal(e.Result[i].Status, a.Result[i].Status, "Result[i].Status") + r.Equal(e.Result[i].ClientTranId, a.Result[i].ClientTranId, "Result[i].ClientTranId") + } + + r.Equal(e.TotalCount, a.TotalCount, "TotalCount") +} + +type subAccountBlvtEnableServiceTestSuite struct { + baseTestSuite +} + +func TestSubAccountBlvtEnableService(t *testing.T) { + suite.Run(t, new(subAccountBlvtEnableServiceTestSuite)) +} + +func (s *subAccountBlvtEnableServiceTestSuite) TestSubAccountBlvtEnable() { + data := []byte(`{ + "email":"123@test.com", + "enableBlvt":true +}`) + s.mockDo(data, nil) + defer s.assertDo() + var email string = "xxyyzz@gmail.com" + var enableBlvt bool = true + s.assertReq(func(r *request) { + e := newSignedRequest().setFormParam("email", email).setFormParam("enableBlvt", enableBlvt) + s.assertRequestEqual(e, r) + }) + res, err := s.client.NewSubAccountBlvtEnableService().Email(email).EnableBlvt(enableBlvt).Do(newContext()) + s.r().NoError(err) + + e := &SubAccountBlvtEnableServiceResponse{ + Email: "123@test.com", + EnableBlvt: true} + s.assertSubAccountBlvtEnableServiceResponseEqual(e, res) +} + +func (s *subAccountBlvtEnableServiceTestSuite) assertSubAccountBlvtEnableServiceResponseEqual(e, a *SubAccountBlvtEnableServiceResponse) { + r := s.r() + r.Equal(e.Email, a.Email, "Email") + r.Equal(e.EnableBlvt, a.EnableBlvt, "EnableBlvt") +} + +type subAccountApiIpRestrictionServiceTestSuite struct { + baseTestSuite +} + +func TestSubAccountApiIpRestrictionService(t *testing.T) { + suite.Run(t, new(subAccountApiIpRestrictionServiceTestSuite)) +} + +func (s *subAccountApiIpRestrictionServiceTestSuite) TestSubAccountApiIpRestriction() { + data := []byte(`{ + "ipRestrict": "true", + "ipList": [ + "69.210.67.14", + "8.34.21.10" + ], + "updateTime": 1636371437000, + "apiKey": "k5V49ldtn4tszj6W3hystegdfvmGbqDzjmkCtpTvC0G74WhK7yd4rfCTo4lShf" +}`) + s.mockDo(data, nil) + defer s.assertDo() + var email string = "xxyyzz@gmail.com" + var subAccountApiKey string = "aabb" + s.assertReq(func(r *request) { + e := newSignedRequest().setParam("email", email).setParam("subAccountApiKey", subAccountApiKey) + s.assertRequestEqual(e, r) + }) + res, err := s.client.NewSubAccountApiIpRestrictionService().Email(email).SubAccountApiKey(subAccountApiKey).Do(newContext()) + s.r().NoError(err) + + e := &SubAccountApiIpRestrictServiceResponse{ + IpRestrict: "true", + IpList: []string{"69.210.67.14", + "8.34.21.10"}, + UpdateTime: 1636371437000, + ApiKey: "k5V49ldtn4tszj6W3hystegdfvmGbqDzjmkCtpTvC0G74WhK7yd4rfCTo4lShf"} + s.assertSubAccountApiIpRestrictServiceResponseEqual(e, res) +} + +func (s *subAccountApiIpRestrictionServiceTestSuite) assertSubAccountApiIpRestrictServiceResponseEqual(e, a *SubAccountApiIpRestrictServiceResponse) { + r := s.r() + r.Equal(e.IpRestrict, a.IpRestrict, "IpRestrict") + for i := range e.IpList { + r.Equal(e.IpList[i], a.IpList[i], "IpList[i]") + } + + r.Equal(e.UpdateTime, a.UpdateTime, "UpdateTime") + r.Equal(e.ApiKey, a.ApiKey, "ApiKey") +} + +type subAccountApiDeleteIpRestrictionServiceTestSuite struct { + baseTestSuite +} + +func TestSubAccountApiDeleteIpRestrictionService(t *testing.T) { + suite.Run(t, new(subAccountApiDeleteIpRestrictionServiceTestSuite)) +} + +func (s *subAccountApiDeleteIpRestrictionServiceTestSuite) TestSubAccountApiDeleteIpRestriction() { + data := []byte(`{ + "ipRestrict": "true", + "ipList": [ + "69.210.67.14", + "8.34.21.10" + ], + "updateTime": 1636371437000, + "apiKey": "k5V49ldtn4tszj6W3hystegdfvmGbqDzjmkCtpTvC0G74WhK7yd4rfCTo4lShf" +}`) + s.mockDo(data, nil) + defer s.assertDo() + var email string = "xxyyzz@gmail.com" + var subAccountApiKey string = "aabb" + var ipAddress string = "1.2.3.4" + s.assertReq(func(r *request) { + e := newSignedRequest().setFormParam("email", email).setFormParam("subAccountApiKey", subAccountApiKey).setFormParam("ipAddress", ipAddress) + s.assertRequestEqual(e, r) + }) + res, err := s.client.NewSubAccountApiDeleteIpRestrictionService().Email(email).SubAccountApiKey(subAccountApiKey).IpAddress(ipAddress).Do(newContext()) + s.r().NoError(err) + + e := &SubAccountApiDeleteIpRestrictServiceResponse{ + IpRestrict: "true", + IpList: []string{"69.210.67.14", + "8.34.21.10"}, + UpdateTime: 1636371437000, + ApiKey: "k5V49ldtn4tszj6W3hystegdfvmGbqDzjmkCtpTvC0G74WhK7yd4rfCTo4lShf"} + s.assertSubAccountApiDeleteIpRestrictServiceResponseEqual(e, res) +} + +func (s *subAccountApiDeleteIpRestrictionServiceTestSuite) assertSubAccountApiDeleteIpRestrictServiceResponseEqual(e, a *SubAccountApiDeleteIpRestrictServiceResponse) { + r := s.r() + r.Equal(e.IpRestrict, a.IpRestrict, "IpRestrict") + for i := range e.IpList { + r.Equal(e.IpList[i], a.IpList[i], "IpList[i]") + } + + r.Equal(e.UpdateTime, a.UpdateTime, "UpdateTime") + r.Equal(e.ApiKey, a.ApiKey, "ApiKey") +} + +type subAccountApiAddIpRestrictionServiceTestSuite struct { + baseTestSuite +} + +func TestSubAccountApiAddIpRestrictionService(t *testing.T) { + suite.Run(t, new(subAccountApiAddIpRestrictionServiceTestSuite)) +} + +func (s *subAccountApiAddIpRestrictionServiceTestSuite) TestSubAccountApiAddIpRestriction() { + data := []byte(`{ + "ipRestrict": "true", + "ipList": [ + "69.210.67.14", + "8.34.21.10" + ], + "updateTime": 1636371437000, + "apiKey": "k5V49ldtn4tszj6W3hystegdfvmGbqDzjmkCtpTvC0G74WhK7yd4rfCTo4lShf" +}`) + s.mockDo(data, nil) + defer s.assertDo() + var email string = "xxyyzz@gmail.com" + var subAccountApiKey string = "aabb" + var status string = "1" + var ipAddress string = "1.2.3.4" + s.assertReq(func(r *request) { + e := newSignedRequest().setFormParam("email", email).setFormParam("subAccountApiKey", subAccountApiKey).setFormParam("status", status).setFormParam("ipAddress", ipAddress) + s.assertRequestEqual(e, r) + }) + res, err := s.client.NewSubAccountApiAddIpRestrictionService().Email(email).SubAccountApiKey(subAccountApiKey).Status(status).IpAddress(ipAddress).Do(newContext()) + s.r().NoError(err) + + e := &SubAccountApiAddIpRestrictServiceResponse{ + IpRestrict: "true", + IpList: []string{"69.210.67.14", + "8.34.21.10"}, + UpdateTime: 1636371437000, + ApiKey: "k5V49ldtn4tszj6W3hystegdfvmGbqDzjmkCtpTvC0G74WhK7yd4rfCTo4lShf"} + s.assertSubAccountApiAddIpRestrictServiceResponseEqual(e, res) +} + +func (s *subAccountApiAddIpRestrictionServiceTestSuite) assertSubAccountApiAddIpRestrictServiceResponseEqual(e, a *SubAccountApiAddIpRestrictServiceResponse) { + r := s.r() + r.Equal(e.IpRestrict, a.IpRestrict, "IpRestrict") + for i := range e.IpList { + r.Equal(e.IpList[i], a.IpList[i], "IpList[i]") + } + + r.Equal(e.UpdateTime, a.UpdateTime, "UpdateTime") + r.Equal(e.ApiKey, a.ApiKey, "ApiKey") +} + +type managedSubAccountWithdrawServiceTestSuite struct { + baseTestSuite +} + +func TestManagedSubAccountWithdrawService(t *testing.T) { + suite.Run(t, new(managedSubAccountWithdrawServiceTestSuite)) +} + +func (s *managedSubAccountWithdrawServiceTestSuite) TestManagedSubAccountWithdraw() { + data := []byte(`{ + "tranId":66157362489 +}`) + s.mockDo(data, nil) + defer s.assertDo() + var fromEmail string = "xxyyzz@gmail.com" + var asset string = "USDT" + var amount string = "1.000548036" + s.assertReq(func(r *request) { + e := newSignedRequest().setFormParam("fromEmail", fromEmail).setFormParam("asset", asset).setFormParam("amount", amount) + s.assertRequestEqual(e, r) + }) + res, err := s.client.NewManagedSubAccountWithdrawService().FromEmail(fromEmail).Asset(asset).Amount(amount).Do(newContext()) + s.r().NoError(err) + + e := &ManagedSubAccountWithdrawServiceResponse{ + TranId: 66157362489} + s.assertManagedSubAccountWithdrawServiceResponseEqual(e, res) +} + +func (s *managedSubAccountWithdrawServiceTestSuite) assertManagedSubAccountWithdrawServiceResponseEqual(e, a *ManagedSubAccountWithdrawServiceResponse) { + r := s.r() + r.Equal(e.TranId, a.TranId, "TranId") +} + +type managedSubAccountSnapshotServiceTestSuite struct { + baseTestSuite +} + +func TestManagedSubAccountSnapshotService(t *testing.T) { + suite.Run(t, new(managedSubAccountSnapshotServiceTestSuite)) +} + +func (s *managedSubAccountSnapshotServiceTestSuite) TestManagedSubAccountSnapshot() { + data := []byte(`{ + "code": 200, + "msg": "", + "snapshotVos": [{ + "data": { + "balances": [{ + "asset": "BTC", + "free": "0.09905021", + "locked": "0.00000000" + }, + { + "asset": "USDT", + "free": "1.89109409", + "locked": "0.00000000" + } + ], + "totalAssetOfBtc": "0.09942700", + + "marginLevel": "2748.02909813", + "totalLiabilityOfBtc": "0.00000100", + "totalNetAssetOfBtc": "0.00274750", + "userAssets": [{ + "asset": "XRP", + "borrowed": "0.00000000", + "free": "1.00000000", + "interest": "0.00000000", + "locked": "0.00000000", + "netAsset": "1.00000000" + }], + + "assets": [{ + "asset": "USDT", + "marginBalance": "118.99782335", + "walletBalance": "120.23811389" + }], + "position": [{ + "entryPrice": "7130.41000000", + "markPrice": "7257.66239673", + "positionAmt": "0.01000000", + "symbol": "BTCUSDT", + "unRealizedProfit": "1.24029054" + }] + }, + "type": "spot", + "updateTime": 1576281599000 + }] +}`) + s.mockDo(data, nil) + defer s.assertDo() + var email string = "xxyyzz@gmail.com" + var accType string = "USDT" + var limit int32 = 10 + s.assertReq(func(r *request) { + e := newSignedRequest().setParam("email", email).setParam("type", accType).setParam("limit", limit) + s.assertRequestEqual(e, r) + }) + res, err := s.client.NewManagedSubAccountSnapshotService().Email(email).AccType(accType).Limit(limit).Do(newContext()) + s.r().NoError(err) + + e := &ManagedSubAccountSnapshotServiceResponse{ + Code: 200, + Msg: "", + SnapshotVos: []*SnapshotVo{{ + Data: SnapshotVoData{ + Balances: []*SnapShotSpotBalance{{ + Asset: "BTC", + Free: "0.09905021", + Locked: "0.00000000"}, + { + Asset: "USDT", + Free: "1.89109409", + Locked: "0.00000000"}}, + TotalAssetOfBtc: "0.09942700", + MarginLevel: "2748.02909813", + TotalLiabilityOfBtc: "0.00000100", + TotalNetAssetOfBtc: "0.00274750", + UserAssets: []*MarginUserAsset{{ + Asset: "XRP", + Borrowed: "0.00000000", + Free: "1.00000000", + Interest: "0.00000000", + Locked: "0.00000000", + NetAsset: "1.00000000"}}, + Assets: []*FuturesUserAsset{{ + Asset: "USDT", + MarginBalance: "118.99782335", + WalletBalance: "120.23811389"}}, + Position: []*FuturesUserPosition{{ + EntryPrice: "7130.41000000", + MarkPrice: "7257.66239673", + PositionAmt: "0.01000000", + Symbol: "BTCUSDT", + UnRealizedProfit: "1.24029054"}}}, + Type: "spot", + UpdateTime: 1576281599000}}} + s.assertManagedSubAccountSnapshotServiceResponseEqual(e, res) +} + +func (s *managedSubAccountSnapshotServiceTestSuite) assertManagedSubAccountSnapshotServiceResponseEqual(e, a *ManagedSubAccountSnapshotServiceResponse) { + r := s.r() + r.Equal(e.Code, a.Code, "Code") + r.Equal(e.Msg, a.Msg, "Msg") + r.Len(e.SnapshotVos, len(a.SnapshotVos)) + for i := range e.SnapshotVos { + r.Len(e.SnapshotVos[i].Data.Balances, len(a.SnapshotVos[i].Data.Balances)) + for k := range e.SnapshotVos[i].Data.Balances { + r.Equal(e.SnapshotVos[i].Data.Balances[k].Asset, a.SnapshotVos[i].Data.Balances[k].Asset, "SnapshotVos[i].Data.Balances[k].Asset") + r.Equal(e.SnapshotVos[i].Data.Balances[k].Free, a.SnapshotVos[i].Data.Balances[k].Free, "SnapshotVos[i].Data.Balances[k].Free") + r.Equal(e.SnapshotVos[i].Data.Balances[k].Locked, a.SnapshotVos[i].Data.Balances[k].Locked, "SnapshotVos[i].Data.Balances[k].Locked") + } + + r.Equal(e.SnapshotVos[i].Data.TotalAssetOfBtc, a.SnapshotVos[i].Data.TotalAssetOfBtc, "SnapshotVos[i].Data.TotalAssetOfBtc") + r.Equal(e.SnapshotVos[i].Data.MarginLevel, a.SnapshotVos[i].Data.MarginLevel, "SnapshotVos[i].Data.MarginLevel") + r.Equal(e.SnapshotVos[i].Data.TotalLiabilityOfBtc, a.SnapshotVos[i].Data.TotalLiabilityOfBtc, "SnapshotVos[i].Data.TotalLiabilityOfBtc") + r.Equal(e.SnapshotVos[i].Data.TotalNetAssetOfBtc, a.SnapshotVos[i].Data.TotalNetAssetOfBtc, "SnapshotVos[i].Data.TotalNetAssetOfBtc") + r.Len(e.SnapshotVos[i].Data.UserAssets, len(a.SnapshotVos[i].Data.UserAssets)) + for k := range e.SnapshotVos[i].Data.UserAssets { + r.Equal(e.SnapshotVos[i].Data.UserAssets[k].Asset, a.SnapshotVos[i].Data.UserAssets[k].Asset, "SnapshotVos[i].Data.UserAssets[k].Asset") + r.Equal(e.SnapshotVos[i].Data.UserAssets[k].Borrowed, a.SnapshotVos[i].Data.UserAssets[k].Borrowed, "SnapshotVos[i].Data.UserAssets[k].Borrowed") + r.Equal(e.SnapshotVos[i].Data.UserAssets[k].Free, a.SnapshotVos[i].Data.UserAssets[k].Free, "SnapshotVos[i].Data.UserAssets[k].Free") + r.Equal(e.SnapshotVos[i].Data.UserAssets[k].Interest, a.SnapshotVos[i].Data.UserAssets[k].Interest, "SnapshotVos[i].Data.UserAssets[k].Interest") + r.Equal(e.SnapshotVos[i].Data.UserAssets[k].Locked, a.SnapshotVos[i].Data.UserAssets[k].Locked, "SnapshotVos[i].Data.UserAssets[k].Locked") + r.Equal(e.SnapshotVos[i].Data.UserAssets[k].NetAsset, a.SnapshotVos[i].Data.UserAssets[k].NetAsset, "SnapshotVos[i].Data.UserAssets[k].NetAsset") + } + + r.Len(e.SnapshotVos[i].Data.Assets, len(a.SnapshotVos[i].Data.Assets)) + for k := range e.SnapshotVos[i].Data.Assets { + r.Equal(e.SnapshotVos[i].Data.Assets[k].Asset, a.SnapshotVos[i].Data.Assets[k].Asset, "SnapshotVos[i].Data.Assets[k].Asset") + r.Equal(e.SnapshotVos[i].Data.Assets[k].MarginBalance, a.SnapshotVos[i].Data.Assets[k].MarginBalance, "SnapshotVos[i].Data.Assets[k].MarginBalance") + r.Equal(e.SnapshotVos[i].Data.Assets[k].WalletBalance, a.SnapshotVos[i].Data.Assets[k].WalletBalance, "SnapshotVos[i].Data.Assets[k].WalletBalance") + } + + r.Len(e.SnapshotVos[i].Data.Position, len(a.SnapshotVos[i].Data.Position)) + for k := range e.SnapshotVos[i].Data.Position { + r.Equal(e.SnapshotVos[i].Data.Position[k].EntryPrice, a.SnapshotVos[i].Data.Position[k].EntryPrice, "SnapshotVos[i].Data.Position[k].EntryPrice") + r.Equal(e.SnapshotVos[i].Data.Position[k].MarkPrice, a.SnapshotVos[i].Data.Position[k].MarkPrice, "SnapshotVos[i].Data.Position[k].MarkPrice") + r.Equal(e.SnapshotVos[i].Data.Position[k].PositionAmt, a.SnapshotVos[i].Data.Position[k].PositionAmt, "SnapshotVos[i].Data.Position[k].PositionAmt") + r.Equal(e.SnapshotVos[i].Data.Position[k].Symbol, a.SnapshotVos[i].Data.Position[k].Symbol, "SnapshotVos[i].Data.Position[k].Symbol") + r.Equal(e.SnapshotVos[i].Data.Position[k].UnRealizedProfit, a.SnapshotVos[i].Data.Position[k].UnRealizedProfit, "SnapshotVos[i].Data.Position[k].UnRealizedProfit") + } + + r.Equal(e.SnapshotVos[i].Type, a.SnapshotVos[i].Type, "SnapshotVos[i].Type") + r.Equal(e.SnapshotVos[i].UpdateTime, a.SnapshotVos[i].UpdateTime, "SnapshotVos[i].UpdateTime") + } + +} + +type managedSubAccountQueryTransferLogForInvestorServiceTestSuite struct { + baseTestSuite +} + +func TestManagedSubAccountQueryTransferLogForInvestorService(t *testing.T) { + suite.Run(t, new(managedSubAccountQueryTransferLogForInvestorServiceTestSuite)) +} + +func (s *managedSubAccountQueryTransferLogForInvestorServiceTestSuite) TestManagedSubAccountQueryTransferLogForInvestor() { + data := []byte(`{ + "managerSubTransferHistoryVos": [{ + "fromEmail": "test_0_virtual@kq3kno9imanagedsub.com", + "fromAccountType": "SPOT", + "toEmail": "wdywl0lddakh@test.com", + "toAccountType": "SPOT", + "asset": "BNB", + "amount": "0.01", + "scheduledData": 1679416673000, + "createTime": 1679416673000, + "status": "SUCCESS", + "tranId": 91077779 + }, + { + "fromEmail": "wdywl0lddakh@test.com", + "fromAccountType": "SPOT", + "toEmail": "test_0_virtual@kq3kno9imanagedsub.com", + "toAccountType": "SPOT", + "asset": "BNB", + "amount": "1", + "scheduledData": 1679416616000, + "createTime": 1679416616000, + "status": "SUCCESS", + "tranId": 91077676 + } + ], + "count": 2 +}`) + s.mockDo(data, nil) + defer s.assertDo() + var email string = "xxyyzz@gmail.com" + var startTime int64 = 1111111235466 + var endTime int64 = 2222233355456 + var page int32 = 1 + var limit int32 = 20 + s.assertReq(func(r *request) { + e := newSignedRequest().setParam("email", email).setParam("startTime", startTime).setParam("endTime", endTime).setParam("page", page).setParam("limit", limit) + s.assertRequestEqual(e, r) + }) + res, err := s.client.NewManagedSubAccountQueryTransferLogForInvestorService().Email(email).StartTime(startTime).EndTime(endTime).Page(page).Limit(limit).Do(newContext()) + s.r().NoError(err) + + e := &ManagedSubAccountQueryTransferLogForInvestorServiceResponse{ + ManagerSubTransferHistoryVos: []*ManagedSubTransferHistoryVo{{ + FromEmail: "test_0_virtual@kq3kno9imanagedsub.com", + FromAccountType: "SPOT", + ToEmail: "wdywl0lddakh@test.com", + ToAccountType: "SPOT", + Asset: "BNB", + Amount: "0.01", + ScheduledData: 1679416673000, + CreateTime: 1679416673000, + Status: "SUCCESS", + TranId: 91077779}, + { + FromEmail: "wdywl0lddakh@test.com", + FromAccountType: "SPOT", + ToEmail: "test_0_virtual@kq3kno9imanagedsub.com", + ToAccountType: "SPOT", + Asset: "BNB", + Amount: "1", + ScheduledData: 1679416616000, + CreateTime: 1679416616000, + Status: "SUCCESS", + TranId: 91077676}}, + Count: 2} + s.assertManagedSubAccountQueryTransferLogForInvestorServiceResponseEqual(e, res) +} + +func (s *managedSubAccountQueryTransferLogForInvestorServiceTestSuite) assertManagedSubAccountQueryTransferLogForInvestorServiceResponseEqual(e, a *ManagedSubAccountQueryTransferLogForInvestorServiceResponse) { + r := s.r() + r.Len(e.ManagerSubTransferHistoryVos, len(a.ManagerSubTransferHistoryVos)) + for i := range e.ManagerSubTransferHistoryVos { + r.Equal(e.ManagerSubTransferHistoryVos[i].FromEmail, a.ManagerSubTransferHistoryVos[i].FromEmail, "ManagerSubTransferHistoryVos[i].FromEmail") + r.Equal(e.ManagerSubTransferHistoryVos[i].FromAccountType, a.ManagerSubTransferHistoryVos[i].FromAccountType, "ManagerSubTransferHistoryVos[i].FromAccountType") + r.Equal(e.ManagerSubTransferHistoryVos[i].ToEmail, a.ManagerSubTransferHistoryVos[i].ToEmail, "ManagerSubTransferHistoryVos[i].ToEmail") + r.Equal(e.ManagerSubTransferHistoryVos[i].ToAccountType, a.ManagerSubTransferHistoryVos[i].ToAccountType, "ManagerSubTransferHistoryVos[i].ToAccountType") + r.Equal(e.ManagerSubTransferHistoryVos[i].Asset, a.ManagerSubTransferHistoryVos[i].Asset, "ManagerSubTransferHistoryVos[i].Asset") + r.Equal(e.ManagerSubTransferHistoryVos[i].Amount, a.ManagerSubTransferHistoryVos[i].Amount, "ManagerSubTransferHistoryVos[i].Amount") + r.Equal(e.ManagerSubTransferHistoryVos[i].ScheduledData, a.ManagerSubTransferHistoryVos[i].ScheduledData, "ManagerSubTransferHistoryVos[i].ScheduledData") + r.Equal(e.ManagerSubTransferHistoryVos[i].CreateTime, a.ManagerSubTransferHistoryVos[i].CreateTime, "ManagerSubTransferHistoryVos[i].CreateTime") + r.Equal(e.ManagerSubTransferHistoryVos[i].Status, a.ManagerSubTransferHistoryVos[i].Status, "ManagerSubTransferHistoryVos[i].Status") + r.Equal(e.ManagerSubTransferHistoryVos[i].TranId, a.ManagerSubTransferHistoryVos[i].TranId, "ManagerSubTransferHistoryVos[i].TranId") + } + + r.Equal(e.Count, a.Count, "Count") +} + +type managedSubAccountQueryTransferLogForTradeParentServiceTestSuite struct { + baseTestSuite +} + +func TestManagedSubAccountQueryTransferLogForTradeParentService(t *testing.T) { + suite.Run(t, new(managedSubAccountQueryTransferLogForTradeParentServiceTestSuite)) +} + +func (s *managedSubAccountQueryTransferLogForTradeParentServiceTestSuite) TestManagedSubAccountQueryTransferLogForTradeParent() { + data := []byte(`{ + "managerSubTransferHistoryVos": [{ + "fromEmail": "test_0_virtual@kq3kno9imanagedsub.com", + "fromAccountType": "SPOT", + "toEmail": "wdywl0lddakh@test.com", + "toAccountType": "SPOT", + "asset": "BNB", + "amount": "0.01", + "scheduledData": 1679416673000, + "createTime": 1679416673000, + "status": "SUCCESS", + "tranId": 91077779 + }, + { + "fromEmail": "wdywl0lddakh@test.com", + "fromAccountType": "SPOT", + "toEmail": "test_0_virtual@kq3kno9imanagedsub.com", + "toAccountType": "SPOT", + "asset": "BNB", + "amount": "1", + "scheduledData": 1679416616000, + "createTime": 1679416616000, + "status": "SUCCESS", + "tranId": 91077676 + } + ], + "count": 2 +}`) + s.mockDo(data, nil) + defer s.assertDo() + var email string = "xxyyzz@gmail.com" + var startTime int64 = 1111111235466 + var endTime int64 = 2222233355456 + var page int32 = 1 + var limit int32 = 20 + s.assertReq(func(r *request) { + e := newSignedRequest().setParam("email", email).setParam("startTime", startTime).setParam("endTime", endTime).setParam("page", page).setParam("limit", limit) + s.assertRequestEqual(e, r) + }) + res, err := s.client.NewManagedSubAccountQueryTransferLogForTradeParentService().Email(email).StartTime(startTime).EndTime(endTime).Page(page).Limit(limit).Do(newContext()) + s.r().NoError(err) + + e := &ManagedSubAccountQueryTransferLogForTradeParentServiceResponse{ + ManagerSubTransferHistoryVos: []*ManagedSubTransferHistoryVo{{ + FromEmail: "test_0_virtual@kq3kno9imanagedsub.com", + FromAccountType: "SPOT", + ToEmail: "wdywl0lddakh@test.com", + ToAccountType: "SPOT", + Asset: "BNB", + Amount: "0.01", + ScheduledData: 1679416673000, + CreateTime: 1679416673000, + Status: "SUCCESS", + TranId: 91077779}, + { + FromEmail: "wdywl0lddakh@test.com", + FromAccountType: "SPOT", + ToEmail: "test_0_virtual@kq3kno9imanagedsub.com", + ToAccountType: "SPOT", + Asset: "BNB", + Amount: "1", + ScheduledData: 1679416616000, + CreateTime: 1679416616000, + Status: "SUCCESS", + TranId: 91077676}}, + Count: 2} + s.assertManagedSubAccountQueryTransferLogForTradeParentServiceResponseEqual(e, res) +} + +func (s *managedSubAccountQueryTransferLogForTradeParentServiceTestSuite) assertManagedSubAccountQueryTransferLogForTradeParentServiceResponseEqual(e, a *ManagedSubAccountQueryTransferLogForTradeParentServiceResponse) { + r := s.r() + r.Len(e.ManagerSubTransferHistoryVos, len(a.ManagerSubTransferHistoryVos)) + for i := range e.ManagerSubTransferHistoryVos { + r.Equal(e.ManagerSubTransferHistoryVos[i].FromEmail, a.ManagerSubTransferHistoryVos[i].FromEmail, "ManagerSubTransferHistoryVos[i].FromEmail") + r.Equal(e.ManagerSubTransferHistoryVos[i].FromAccountType, a.ManagerSubTransferHistoryVos[i].FromAccountType, "ManagerSubTransferHistoryVos[i].FromAccountType") + r.Equal(e.ManagerSubTransferHistoryVos[i].ToEmail, a.ManagerSubTransferHistoryVos[i].ToEmail, "ManagerSubTransferHistoryVos[i].ToEmail") + r.Equal(e.ManagerSubTransferHistoryVos[i].ToAccountType, a.ManagerSubTransferHistoryVos[i].ToAccountType, "ManagerSubTransferHistoryVos[i].ToAccountType") + r.Equal(e.ManagerSubTransferHistoryVos[i].Asset, a.ManagerSubTransferHistoryVos[i].Asset, "ManagerSubTransferHistoryVos[i].Asset") + r.Equal(e.ManagerSubTransferHistoryVos[i].Amount, a.ManagerSubTransferHistoryVos[i].Amount, "ManagerSubTransferHistoryVos[i].Amount") + r.Equal(e.ManagerSubTransferHistoryVos[i].ScheduledData, a.ManagerSubTransferHistoryVos[i].ScheduledData, "ManagerSubTransferHistoryVos[i].ScheduledData") + r.Equal(e.ManagerSubTransferHistoryVos[i].CreateTime, a.ManagerSubTransferHistoryVos[i].CreateTime, "ManagerSubTransferHistoryVos[i].CreateTime") + r.Equal(e.ManagerSubTransferHistoryVos[i].Status, a.ManagerSubTransferHistoryVos[i].Status, "ManagerSubTransferHistoryVos[i].Status") + r.Equal(e.ManagerSubTransferHistoryVos[i].TranId, a.ManagerSubTransferHistoryVos[i].TranId, "ManagerSubTransferHistoryVos[i].TranId") + } + + r.Equal(e.Count, a.Count, "Count") +} + +type managedSubAccountQueryFuturesAssetServiceTestSuite struct { + baseTestSuite +} + +func TestManagedSubAccountQueryFuturesAssetService(t *testing.T) { + suite.Run(t, new(managedSubAccountQueryFuturesAssetServiceTestSuite)) +} + +func (s *managedSubAccountQueryFuturesAssetServiceTestSuite) TestManagedSubAccountQueryFuturesAsset() { + data := []byte(`{ + "code": 200, + "message": "OK", + "snapshotVos": [ + { + "type": "FUTURES", + "updateTime": 1672893855394, + "data": { + "assets": [ + { + "asset": "USDT", + "marginBalance": "100", + "walletBalance": "120" + } + ], + "position": [ + { + "symbol": "BTCUSDT", + "entryPrice": "17000", + "markPrice": "17000", + "positionAmt": "0.0001" + } + ] + } + } + ] +}`) + s.mockDo(data, nil) + defer s.assertDo() + var email string = "xxyyzz@gmail.com" + s.assertReq(func(r *request) { + e := newSignedRequest().setParam("email", email) + s.assertRequestEqual(e, r) + }) + res, err := s.client.NewManagedSubAccountQueryFuturesAssetService().Email(email).Do(newContext()) + s.r().NoError(err) + + e := &ManagedSubAccountQueryFuturesAssetServiceResponse{ + Code: 200, + Message: "OK", + SnapshotVos: []*ManagedSubFuturesAccountSnapVo{{ + Type: "FUTURES", + UpdateTime: 1672893855394, + Data: &ManagedSubFuturesAccountSnapVoData{ + Assets: []*ManagedSubFuturesAccountSnapVoDataAsset{{ + Asset: "USDT", + MarginBalance: "100", + WalletBalance: "120"}}, + Position: []*ManagedSubFuturesAccountSnapVoDataPosition{{ + Symbol: "BTCUSDT", + EntryPrice: "17000", + MarkPrice: "17000", + PositionAmt: "0.0001"}}}}}} + s.assertManagedSubAccountQueryFuturesAssetServiceResponseEqual(e, res) +} + +func (s *managedSubAccountQueryFuturesAssetServiceTestSuite) assertManagedSubAccountQueryFuturesAssetServiceResponseEqual(e, a *ManagedSubAccountQueryFuturesAssetServiceResponse) { + r := s.r() + r.Equal(e.Code, a.Code, "Code") + r.Equal(e.Message, a.Message, "Message") + r.Len(e.SnapshotVos, len(a.SnapshotVos)) + for i := range e.SnapshotVos { + r.Equal(e.SnapshotVos[i].Type, a.SnapshotVos[i].Type, "SnapshotVos[i].Type") + r.Equal(e.SnapshotVos[i].UpdateTime, a.SnapshotVos[i].UpdateTime, "SnapshotVos[i].UpdateTime") + r.Len(e.SnapshotVos[i].Data.Assets, len(a.SnapshotVos[i].Data.Assets)) + for k := range e.SnapshotVos[i].Data.Assets { + r.Equal(e.SnapshotVos[i].Data.Assets[k].Asset, a.SnapshotVos[i].Data.Assets[k].Asset, "SnapshotVos[i].Data.Assets[k].Asset") + r.Equal(e.SnapshotVos[i].Data.Assets[k].MarginBalance, a.SnapshotVos[i].Data.Assets[k].MarginBalance, "SnapshotVos[i].Data.Assets[k].MarginBalance") + r.Equal(e.SnapshotVos[i].Data.Assets[k].WalletBalance, a.SnapshotVos[i].Data.Assets[k].WalletBalance, "SnapshotVos[i].Data.Assets[k].WalletBalance") + } + + r.Len(e.SnapshotVos[i].Data.Position, len(a.SnapshotVos[i].Data.Position)) + for k := range e.SnapshotVos[i].Data.Position { + r.Equal(e.SnapshotVos[i].Data.Position[k].Symbol, a.SnapshotVos[i].Data.Position[k].Symbol, "SnapshotVos[i].Data.Position[k].Symbol") + r.Equal(e.SnapshotVos[i].Data.Position[k].EntryPrice, a.SnapshotVos[i].Data.Position[k].EntryPrice, "SnapshotVos[i].Data.Position[k].EntryPrice") + r.Equal(e.SnapshotVos[i].Data.Position[k].MarkPrice, a.SnapshotVos[i].Data.Position[k].MarkPrice, "SnapshotVos[i].Data.Position[k].MarkPrice") + r.Equal(e.SnapshotVos[i].Data.Position[k].PositionAmt, a.SnapshotVos[i].Data.Position[k].PositionAmt, "SnapshotVos[i].Data.Position[k].PositionAmt") + } + + } + +} + +type managedSubAccountQueryMarginAssetServiceTestSuite struct { + baseTestSuite +} + +func TestManagedSubAccountQueryMarginAssetService(t *testing.T) { + suite.Run(t, new(managedSubAccountQueryMarginAssetServiceTestSuite)) +} + +func (s *managedSubAccountQueryMarginAssetServiceTestSuite) TestManagedSubAccountQueryMarginAsset() { + data := []byte(`{ + "marginLevel": "999", + "totalAssetOfBtc": "0", + "totalLiabilityOfBtc": "0", + "totalNetAssetOfBtc": "0", + "userAssets": [{ + "asset": "MATIC", + "borrowed": "0", + "free": "0", + "interest": "0", + "locked": "0", + "netAsset": "0" + }] +}`) + s.mockDo(data, nil) + defer s.assertDo() + var email string = "xxyyzz@gmail.com" + s.assertReq(func(r *request) { + e := newSignedRequest().setParam("email", email) + s.assertRequestEqual(e, r) + }) + res, err := s.client.NewManagedSubAccountQueryMarginAssetService().Email(email).Do(newContext()) + s.r().NoError(err) + + e := &ManagedSubAccountQueryMarginAssetServiceResponse{ + MarginLevel: "999", + TotalAssetOfBtc: "0", + TotalLiabilityOfBtc: "0", + TotalNetAssetOfBtc: "0", + UserAssets: []*ManagedSubAccountMarginAsset{{ + Asset: "MATIC", + Borrowed: "0", + Free: "0", + Interest: "0", + Locked: "0", + NetAsset: "0"}}} + s.assertManagedSubAccountQueryMarginAssetServiceResponseEqual(e, res) +} + +func (s *managedSubAccountQueryMarginAssetServiceTestSuite) assertManagedSubAccountQueryMarginAssetServiceResponseEqual(e, a *ManagedSubAccountQueryMarginAssetServiceResponse) { + r := s.r() + r.Equal(e.MarginLevel, a.MarginLevel, "MarginLevel") + r.Equal(e.TotalAssetOfBtc, a.TotalAssetOfBtc, "TotalAssetOfBtc") + r.Equal(e.TotalLiabilityOfBtc, a.TotalLiabilityOfBtc, "TotalLiabilityOfBtc") + r.Equal(e.TotalNetAssetOfBtc, a.TotalNetAssetOfBtc, "TotalNetAssetOfBtc") + r.Len(e.UserAssets, len(a.UserAssets)) + for i := range e.UserAssets { + r.Equal(e.UserAssets[i].Asset, a.UserAssets[i].Asset, "UserAssets[i].Asset") + r.Equal(e.UserAssets[i].Borrowed, a.UserAssets[i].Borrowed, "UserAssets[i].Borrowed") + r.Equal(e.UserAssets[i].Free, a.UserAssets[i].Free, "UserAssets[i].Free") + r.Equal(e.UserAssets[i].Interest, a.UserAssets[i].Interest, "UserAssets[i].Interest") + r.Equal(e.UserAssets[i].Locked, a.UserAssets[i].Locked, "UserAssets[i].Locked") + r.Equal(e.UserAssets[i].NetAsset, a.UserAssets[i].NetAsset, "UserAssets[i].NetAsset") + } + +} + +type subAccountAssetServiceTestSuite struct { + baseTestSuite +} + +func TestSubAccountAssetService(t *testing.T) { + suite.Run(t, new(subAccountAssetServiceTestSuite)) +} + +func (s *subAccountAssetServiceTestSuite) TestSubAccountAsset() { + data := []byte(`{ + "balances":[ + { + "asset":"ADA", + "free":"10000", + "locked":"0" + }, + { + "asset":"BNB", + "free":"10003", + "locked":"0" + }, + { + "asset":"BTC", + "free":"11467.6399", + "locked":"0" + } + ] +}`) + s.mockDo(data, nil) + defer s.assertDo() + var email string = "xxyyzz@gmail.com" + s.assertReq(func(r *request) { + e := newSignedRequest().setParam("email", email) + s.assertRequestEqual(e, r) + }) + res, err := s.client.NewSubAccountAssetService().Email(email).Do(newContext()) + s.r().NoError(err) + + e := &SubAccountAssetServiceResponse{ + Balances: []*SubAccountAssetBalance{{ + Asset: "ADA", + Free: "10000", + Locked: "0"}, + { + Asset: "BNB", + Free: "10003", + Locked: "0"}, + { + Asset: "BTC", + Free: "11467.6399", + Locked: "0"}}} + s.assertSubAccountAssetServiceResponseEqual(e, res) +} + +func (s *subAccountAssetServiceTestSuite) assertSubAccountAssetServiceResponseEqual(e, a *SubAccountAssetServiceResponse) { + r := s.r() + r.Len(e.Balances, len(a.Balances)) + for i := range e.Balances { + r.Equal(e.Balances[i].Asset, a.Balances[i].Asset, "Balances[i].Asset") + r.Equal(e.Balances[i].Free, a.Balances[i].Free, "Balances[i].Free") + r.Equal(e.Balances[i].Locked, a.Balances[i].Locked, "Balances[i].Locked") + } + +} + +type managedSubAccountInfoServiceTestSuite struct { + baseTestSuite +} + +func TestManagedSubAccountInfoService(t *testing.T) { + suite.Run(t, new(managedSubAccountInfoServiceTestSuite)) +} + +func (s *managedSubAccountInfoServiceTestSuite) TestManagedSubAccountInfo() { + data := []byte(`{ + "total": 3, + "managerSubUserInfoVoList": [ + { + "rootUserId": 1000138475670, + "managersubUserId": 1000137842513, + "bindParentUserId": 1000138475669, + "email": "test_0_virtual@kq3kno9imanagedsub.com", + "insertTimeStamp": 1678435149000, + "bindParentEmail": "wdyw8xsh8pey@test.com", + "isSubUserEnabled": true, + "isUserActive": true, + "isMarginEnabled": false, + "isFutureEnabled": false, + "isSignedLVTRiskAgreement": false + }, + { + "rootUserId": 1000138475670, + "managersubUserId": 1000137842514, + "bindParentUserId": 1000138475669, + "email": "test_1_virtual@4qd2u7zxmanagedsub.com", + "insertTimeStamp": 1678435152000, + "bindParentEmail": "wdyw8xsh8pey@test.com", + "isSubUserEnabled": true, + "isUserActive": true, + "isMarginEnabled": false, + "isFutureEnabled": false, + "isSignedLVTRiskAgreement": false + }, + { + "rootUserId": 1000138475670, + "managersubUserId": 1000137842515, + "bindParentUserId": 1000138475669, + "email": "test_2_virtual@akc05o8hmanagedsub.com", + "insertTimeStamp": 1678435153000, + "bindParentEmail": "wdyw8xsh8pey@test.com", + "isSubUserEnabled": true, + "isUserActive": true, + "isMarginEnabled": false, + "isFutureEnabled": false, + "isSignedLVTRiskAgreement": false + } + ] +}`) + s.mockDo(data, nil) + defer s.assertDo() + var email string = "xxyyzz@gmail.com" + s.assertReq(func(r *request) { + e := newSignedRequest().setParam("email", email) + s.assertRequestEqual(e, r) + }) + res, err := s.client.NewManagedSubAccountInfoService().Email(email).Do(newContext()) + s.r().NoError(err) + + e := &ManagedSubAccountInfoServiceResponse{ + Total: 3, + ManagerSubUserInfoVoList: []*ManagedSubAccountUserInfoVo{{ + RootUserId: 1000138475670, + ManagersubUserId: 1000137842513, + BindParentUserId: 1000138475669, + Email: "test_0_virtual@kq3kno9imanagedsub.com", + InsertTimeStamp: 1678435149000, + BindParentEmail: "wdyw8xsh8pey@test.com", + IsSubUserEnabled: true, + IsUserActive: true, + IsMarginEnabled: false, + IsFutureEnabled: false, + IsSignedLVTRiskAgreement: false}, + { + RootUserId: 1000138475670, + ManagersubUserId: 1000137842514, + BindParentUserId: 1000138475669, + Email: "test_1_virtual@4qd2u7zxmanagedsub.com", + InsertTimeStamp: 1678435152000, + BindParentEmail: "wdyw8xsh8pey@test.com", + IsSubUserEnabled: true, + IsUserActive: true, + IsMarginEnabled: false, + IsFutureEnabled: false, + IsSignedLVTRiskAgreement: false}, + { + RootUserId: 1000138475670, + ManagersubUserId: 1000137842515, + BindParentUserId: 1000138475669, + Email: "test_2_virtual@akc05o8hmanagedsub.com", + InsertTimeStamp: 1678435153000, + BindParentEmail: "wdyw8xsh8pey@test.com", + IsSubUserEnabled: true, + IsUserActive: true, + IsMarginEnabled: false, + IsFutureEnabled: false, + IsSignedLVTRiskAgreement: false}}} + s.assertManagedSubAccountInfoServiceResponseEqual(e, res) +} + +func (s *managedSubAccountInfoServiceTestSuite) assertManagedSubAccountInfoServiceResponseEqual(e, a *ManagedSubAccountInfoServiceResponse) { + r := s.r() + r.Equal(e.Total, a.Total, "Total") + r.Len(e.ManagerSubUserInfoVoList, len(a.ManagerSubUserInfoVoList)) + for i := range e.ManagerSubUserInfoVoList { + r.Equal(e.ManagerSubUserInfoVoList[i].RootUserId, a.ManagerSubUserInfoVoList[i].RootUserId, "ManagerSubUserInfoVoList[i].RootUserId") + r.Equal(e.ManagerSubUserInfoVoList[i].ManagersubUserId, a.ManagerSubUserInfoVoList[i].ManagersubUserId, "ManagerSubUserInfoVoList[i].ManagersubUserId") + r.Equal(e.ManagerSubUserInfoVoList[i].BindParentUserId, a.ManagerSubUserInfoVoList[i].BindParentUserId, "ManagerSubUserInfoVoList[i].BindParentUserId") + r.Equal(e.ManagerSubUserInfoVoList[i].Email, a.ManagerSubUserInfoVoList[i].Email, "ManagerSubUserInfoVoList[i].Email") + r.Equal(e.ManagerSubUserInfoVoList[i].InsertTimeStamp, a.ManagerSubUserInfoVoList[i].InsertTimeStamp, "ManagerSubUserInfoVoList[i].InsertTimeStamp") + r.Equal(e.ManagerSubUserInfoVoList[i].BindParentEmail, a.ManagerSubUserInfoVoList[i].BindParentEmail, "ManagerSubUserInfoVoList[i].BindParentEmail") + r.Equal(e.ManagerSubUserInfoVoList[i].IsSubUserEnabled, a.ManagerSubUserInfoVoList[i].IsSubUserEnabled, "ManagerSubUserInfoVoList[i].IsSubUserEnabled") + r.Equal(e.ManagerSubUserInfoVoList[i].IsUserActive, a.ManagerSubUserInfoVoList[i].IsUserActive, "ManagerSubUserInfoVoList[i].IsUserActive") + r.Equal(e.ManagerSubUserInfoVoList[i].IsMarginEnabled, a.ManagerSubUserInfoVoList[i].IsMarginEnabled, "ManagerSubUserInfoVoList[i].IsMarginEnabled") + r.Equal(e.ManagerSubUserInfoVoList[i].IsFutureEnabled, a.ManagerSubUserInfoVoList[i].IsFutureEnabled, "ManagerSubUserInfoVoList[i].IsFutureEnabled") + r.Equal(e.ManagerSubUserInfoVoList[i].IsSignedLVTRiskAgreement, a.ManagerSubUserInfoVoList[i].IsSignedLVTRiskAgreement, "ManagerSubUserInfoVoList[i].IsSignedLVTRiskAgreement") + } + +} + +type subAccountTransactionStatisticsServiceTestSuite struct { + baseTestSuite +} + +func TestSubAccountTransactionStatisticsService(t *testing.T) { + suite.Run(t, new(subAccountTransactionStatisticsServiceTestSuite)) +} + +func (s *subAccountTransactionStatisticsServiceTestSuite) TestSubAccountTransactionStatistics() { + data := []byte(`{ + "recent30BtcTotal": "0", + "recent30BtcFuturesTotal": "0", + "recent30BtcMarginTotal": "0", + "recent30BusdTotal": "0", + "recent30BusdFuturesTotal": "0", + "recent30BusdMarginTotal": "0", + "tradeInfoVos": [ + { + "userId": 1000138138384, + "btc": 0, + "btcFutures": 0, + "btcMargin": 0, + "busd": 0, + "busdFutures": 0, + "busdMargin": 0, + "date": 1676851200000 + }, + { + "userId": 1000138138384, + "btc": 0, + "btcFutures": 0, + "btcMargin": 0, + "busd": 0, + "busdFutures": 0, + "busdMargin": 0, + "date": 1676937600000 + }]} + `) + s.mockDo(data, nil) + defer s.assertDo() + var email string = "xxyyzz@gmail.com" + s.assertReq(func(r *request) { + e := newSignedRequest().setParam("email", email) + s.assertRequestEqual(e, r) + }) + res, err := s.client.NewSubAccountTransactionStatisticsService().Email(email).Do(newContext()) + s.r().NoError(err) + + e := &SubAccountTransactionStatisticServiceResponse{ + Recent30BtcTotal: "0", + Recent30BtcFuturesTotal: "0", + Recent30BtcMarginTotal: "0", + Recent30BusdTotal: "0", + Recent30BusdFuturesTotal: "0", + Recent30BusdMarginTotal: "0", + TradeInfoVos: []*TradeInfoVo{{ + UserId: 1000138138384, + Btc: 0, + BtcFutures: 0, + BtcMargin: 0, + Busd: 0, + BusdFutures: 0, + BusdMargin: 0, + Date: 1676851200000}, + { + UserId: 1000138138384, + Btc: 0, + BtcFutures: 0, + BtcMargin: 0, + Busd: 0, + BusdFutures: 0, + BusdMargin: 0, + Date: 1676937600000}}} + s.assertSubAccountTransactionStatisticServiceResponseEqual(e, res) +} + +func (s *subAccountTransactionStatisticsServiceTestSuite) assertSubAccountTransactionStatisticServiceResponseEqual(e, a *SubAccountTransactionStatisticServiceResponse) { + r := s.r() + r.Equal(e.Recent30BtcTotal, a.Recent30BtcTotal, "Recent30BtcTotal") + r.Equal(e.Recent30BtcFuturesTotal, a.Recent30BtcFuturesTotal, "Recent30BtcFuturesTotal") + r.Equal(e.Recent30BtcMarginTotal, a.Recent30BtcMarginTotal, "Recent30BtcMarginTotal") + r.Equal(e.Recent30BusdTotal, a.Recent30BusdTotal, "Recent30BusdTotal") + r.Equal(e.Recent30BusdFuturesTotal, a.Recent30BusdFuturesTotal, "Recent30BusdFuturesTotal") + r.Equal(e.Recent30BusdMarginTotal, a.Recent30BusdMarginTotal, "Recent30BusdMarginTotal") + r.Len(e.TradeInfoVos, len(a.TradeInfoVos)) + for i := range e.TradeInfoVos { + r.Equal(e.TradeInfoVos[i].UserId, a.TradeInfoVos[i].UserId, "TradeInfoVos[i].UserId") + r.Equal(e.TradeInfoVos[i].Btc, a.TradeInfoVos[i].Btc, "TradeInfoVos[i].Btc") + r.Equal(e.TradeInfoVos[i].BtcFutures, a.TradeInfoVos[i].BtcFutures, "TradeInfoVos[i].BtcFutures") + r.Equal(e.TradeInfoVos[i].BtcMargin, a.TradeInfoVos[i].BtcMargin, "TradeInfoVos[i].BtcMargin") + r.Equal(e.TradeInfoVos[i].Busd, a.TradeInfoVos[i].Busd, "TradeInfoVos[i].Busd") + r.Equal(e.TradeInfoVos[i].BusdFutures, a.TradeInfoVos[i].BusdFutures, "TradeInfoVos[i].BusdFutures") + r.Equal(e.TradeInfoVos[i].BusdMargin, a.TradeInfoVos[i].BusdMargin, "TradeInfoVos[i].BusdMargin") + r.Equal(e.TradeInfoVos[i].Date, a.TradeInfoVos[i].Date, "TradeInfoVos[i].Date") + } + +} + +type managedSubAccountDepositAddressServiceTestSuite struct { + baseTestSuite +} + +func TestManagedSubAccountDepositAddressService(t *testing.T) { + suite.Run(t, new(managedSubAccountDepositAddressServiceTestSuite)) +} + +func (s *managedSubAccountDepositAddressServiceTestSuite) TestManagedSubAccountDepositAddress() { + data := []byte(`{ + "coin": "USDT", + "address": "0x206c22d833bb0bb2102da6b7c7d4c3eb14bcf73d", + "tag": "", + "url": "https://etherscan.io/address/0x206c22d833bb0bb2102da6b7c7d4c3eb14bcf73d" +}`) + s.mockDo(data, nil) + defer s.assertDo() + var email string = "xxyyzz@gmail.com" + var coin string = "USDT" + s.assertReq(func(r *request) { + e := newSignedRequest().setParam("email", email).setParam("coin", coin) + s.assertRequestEqual(e, r) + }) + res, err := s.client.NewManagedSubAccountDepositAddressService().Email(email).Coin(coin).Do(newContext()) + s.r().NoError(err) + + e := &ManagedSubAccountDepositAddressServiceResponse{ + Coin: "USDT", + Address: "0x206c22d833bb0bb2102da6b7c7d4c3eb14bcf73d", + Tag: "", + Url: "https://etherscan.io/address/0x206c22d833bb0bb2102da6b7c7d4c3eb14bcf73d"} + s.assertManagedSubAccountDepositAddressServiceResponseEqual(e, res) +} + +func (s *managedSubAccountDepositAddressServiceTestSuite) assertManagedSubAccountDepositAddressServiceResponseEqual(e, a *ManagedSubAccountDepositAddressServiceResponse) { + r := s.r() + r.Equal(e.Coin, a.Coin, "Coin") + r.Equal(e.Address, a.Address, "Address") + r.Equal(e.Tag, a.Tag, "Tag") + r.Equal(e.Url, a.Url, "Url") +} + +type subAccountOptionsEnableServiceTestSuite struct { + baseTestSuite +} + +func TestSubAccountOptionsEnableService(t *testing.T) { + suite.Run(t, new(subAccountOptionsEnableServiceTestSuite)) +} + +func (s *subAccountOptionsEnableServiceTestSuite) TestSubAccountOptionsEnable() { + data := []byte(`{ + "email": "123@test.com", + "isEOptionsEnabled": true +}`) + s.mockDo(data, nil) + defer s.assertDo() + var email string = "xxyyzz@gmail.com" + s.assertReq(func(r *request) { + e := newSignedRequest().setFormParam("email", email) + s.assertRequestEqual(e, r) + }) + res, err := s.client.NewSubAccountOptionsEnableService().Email(email).Do(newContext()) + s.r().NoError(err) + + e := &SubAccountOptionsEnableServiceResponse{ + Email: "123@test.com", + IsEOptionsEnabled: true} + s.assertSubAccountOptionsEnableServiceResponseEqual(e, res) +} + +func (s *subAccountOptionsEnableServiceTestSuite) assertSubAccountOptionsEnableServiceResponseEqual(e, a *SubAccountOptionsEnableServiceResponse) { + r := s.r() + r.Equal(e.Email, a.Email, "Email") + r.Equal(e.IsEOptionsEnabled, a.IsEOptionsEnabled, "IsEOptionsEnabled") +} + +type managedSubAccountQueryTransferLogServiceTestSuite struct { + baseTestSuite +} + +func TestManagedSubAccountQueryTransferLogService(t *testing.T) { + suite.Run(t, new(managedSubAccountQueryTransferLogServiceTestSuite)) +} + +func (s *managedSubAccountQueryTransferLogServiceTestSuite) TestManagedSubAccountQueryTransferLog() { + data := []byte(`{ + "managerSubTransferHistoryVos": [ + { + "fromEmail": "test_0_virtual@kq3kno9imanagedsub.com", + "fromAccountType": "SPOT", + "toEmail": "wdywl0lddakh@test.com", + "toAccountType": "SPOT", + "asset": "BNB", + "amount": "0.01", + "scheduledData": 1679416673000, + "createTime": 1679416673000, + "status": "SUCCESS", + "tranId": 91077779 + }, + { + "fromEmail": "wdywl0lddakh@test.com", + "fromAccountType": "SPOT", + "toEmail": "test_0_virtual@kq3kno9imanagedsub.com", + "toAccountType": "SPOT", + "asset": "BNB", + "amount": "1", + "scheduledData": 1679416616000, + "createTime": 1679416616000, + "status": "SUCCESS", + "tranId": 91077676 + } + ], + "count": 2 +}`) + s.mockDo(data, nil) + defer s.assertDo() + var startTime int64 = 1122334455 + var endTime int64 = 223344558899 + var page int32 = 1 + var limit int32 = 20 + s.assertReq(func(r *request) { + e := newSignedRequest().setParam("startTime", startTime).setParam("endTime", endTime).setParam("page", page).setParam("limit", limit) + s.assertRequestEqual(e, r) + }) + res, err := s.client.NewManagedSubAccountQueryTransferLogService().StartTime(startTime).EndTime(endTime).Page(page).Limit(limit).Do(newContext()) + s.r().NoError(err) + + e := &ManagedSubAccountQueryTransferLogServiceResponse{ + ManagerSubTransferHistoryVos: []*ManagedSubTransferHistoryVo{{ + FromEmail: "test_0_virtual@kq3kno9imanagedsub.com", + FromAccountType: "SPOT", + ToEmail: "wdywl0lddakh@test.com", + ToAccountType: "SPOT", + Asset: "BNB", + Amount: "0.01", + ScheduledData: 1679416673000, + CreateTime: 1679416673000, + Status: "SUCCESS", + TranId: 91077779}, + { + FromEmail: "wdywl0lddakh@test.com", + FromAccountType: "SPOT", + ToEmail: "test_0_virtual@kq3kno9imanagedsub.com", + ToAccountType: "SPOT", + Asset: "BNB", + Amount: "1", + ScheduledData: 1679416616000, + CreateTime: 1679416616000, + Status: "SUCCESS", + TranId: 91077676}}, + Count: 2} + s.assertManagedSubAccountQueryTransferLogServiceResponseEqual(e, res) +} + +func (s *managedSubAccountQueryTransferLogServiceTestSuite) assertManagedSubAccountQueryTransferLogServiceResponseEqual(e, a *ManagedSubAccountQueryTransferLogServiceResponse) { + r := s.r() + r.Len(e.ManagerSubTransferHistoryVos, len(a.ManagerSubTransferHistoryVos)) + for i := range e.ManagerSubTransferHistoryVos { + r.Equal(e.ManagerSubTransferHistoryVos[i].FromEmail, a.ManagerSubTransferHistoryVos[i].FromEmail, "ManagerSubTransferHistoryVos[i].FromEmail") + r.Equal(e.ManagerSubTransferHistoryVos[i].FromAccountType, a.ManagerSubTransferHistoryVos[i].FromAccountType, "ManagerSubTransferHistoryVos[i].FromAccountType") + r.Equal(e.ManagerSubTransferHistoryVos[i].ToEmail, a.ManagerSubTransferHistoryVos[i].ToEmail, "ManagerSubTransferHistoryVos[i].ToEmail") + r.Equal(e.ManagerSubTransferHistoryVos[i].ToAccountType, a.ManagerSubTransferHistoryVos[i].ToAccountType, "ManagerSubTransferHistoryVos[i].ToAccountType") + r.Equal(e.ManagerSubTransferHistoryVos[i].Asset, a.ManagerSubTransferHistoryVos[i].Asset, "ManagerSubTransferHistoryVos[i].Asset") + r.Equal(e.ManagerSubTransferHistoryVos[i].Amount, a.ManagerSubTransferHistoryVos[i].Amount, "ManagerSubTransferHistoryVos[i].Amount") + r.Equal(e.ManagerSubTransferHistoryVos[i].ScheduledData, a.ManagerSubTransferHistoryVos[i].ScheduledData, "ManagerSubTransferHistoryVos[i].ScheduledData") + r.Equal(e.ManagerSubTransferHistoryVos[i].CreateTime, a.ManagerSubTransferHistoryVos[i].CreateTime, "ManagerSubTransferHistoryVos[i].CreateTime") + r.Equal(e.ManagerSubTransferHistoryVos[i].Status, a.ManagerSubTransferHistoryVos[i].Status, "ManagerSubTransferHistoryVos[i].Status") + r.Equal(e.ManagerSubTransferHistoryVos[i].TranId, a.ManagerSubTransferHistoryVos[i].TranId, "ManagerSubTransferHistoryVos[i].TranId") + } + + r.Equal(e.Count, a.Count, "Count") +} diff --git a/v2/tradingDayTicker.go b/v2/tradingDayTicker.go new file mode 100644 index 00000000..85c1b5a8 --- /dev/null +++ b/v2/tradingDayTicker.go @@ -0,0 +1,86 @@ +package binance + +import ( + "context" + + "net/http" + + "github.com/adshao/go-binance/v2/common" +) + +type TradingDayTickerService struct { + c *Client + symbol *string + symbols []string + timeZone *string // Hours and minutes (e.g. -1:00, 05:45); Only hours (e.g. 0, 8, 4); + tickerType *string // [FULL, MINT]. default FULL +} + +type TradingDayTicker struct { + Symbol string `json:"symbol"` + PriceChange string `json:"priceChange"` + PriceChangePercent string `json:"priceChangePercent"` + WeightedAvgPrice string `json:"weightedAvgPrice"` + OpenPrice string `json:"openPrice"` + HighPrice string `json:"highPrice"` + LowPrice string `json:"lowPrice"` + LastPrice string `json:"lastPrice"` + Volume string `json:"volume"` + QuoteVolume string `json:"quoteVolume"` + OpenTime uint64 `json:"openTime"` + CloseTime uint64 `json:"closeTime"` + FirstId uint64 `json:"firstId"` + LastId uint64 `json:"lastId"` + Count uint64 `json:"count"` +} + +func (s *TradingDayTickerService) Symbol(symbol string) *TradingDayTickerService { + s.symbol = &symbol + return s +} + +func (s *TradingDayTickerService) Symbols(symbols []string) *TradingDayTickerService { + s.symbols = symbols + return s +} + +func (s *TradingDayTickerService) TimeZone(timeZone string) *TradingDayTickerService { + s.timeZone = &timeZone + return s +} + +func (s *TradingDayTickerService) TickerType(tickerType string) *TradingDayTickerService { + s.tickerType = &tickerType + return s +} + +func (s *TradingDayTickerService) Do(ctx context.Context, opts ...RequestOption) (res []*TradingDayTicker, err error) { + r := &request{ + method: http.MethodGet, + endpoint: "/api/v3/ticker/tradingDay", + } + if s.symbol != nil { + r.setParam("symbol", *s.symbol) + } + if s.symbols != nil { + r.setParam("symbols", s.symbols) + } + if s.timeZone != nil { + r.setParam("timeZone", *s.timeZone) + } + if s.tickerType != nil { + r.setParam("type", *s.tickerType) + } + + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return nil, err + } + data = common.ToJSONList(data) + res = make([]*TradingDayTicker, 0) + err = json.Unmarshal(data, &res) + if err != nil { + return nil, err + } + return res, nil +} diff --git a/v2/tradingDayTicker_test.go b/v2/tradingDayTicker_test.go new file mode 100644 index 00000000..41efe4c1 --- /dev/null +++ b/v2/tradingDayTicker_test.go @@ -0,0 +1,90 @@ +package binance + +import ( + "testing" + + "github.com/stretchr/testify/suite" +) + +type tradingDayTickerServiceTestSuite struct { + baseTestSuite +} + +func TestTradingDayTickerService(t *testing.T) { + suite.Run(t, new(tradingDayTickerServiceTestSuite)) +} + +func (s *tradingDayTickerServiceTestSuite) TestTradingDayTicker() { + data := []byte(`{ + "symbol": "BTCUSDT", + "priceChange": "-25.63000000", + "priceChangePercent": "-0.042", + "weightedAvgPrice": "60989.95178227", + "openPrice": "60986.68000000", + "highPrice": "61078.01000000", + "lowPrice": "60922.00000000", + "lastPrice": "60961.05000000", + "volume": "707.02697000", + "quoteVolume": "43121540.80906740", + "openTime": 1719705600000, + "closeTime": 1719791999999, + "firstId": 3655222498, + "lastId": 3655289744, + "count": 67247 +}`) + s.mockDo(data, nil) + defer s.assertDo() + var symbols = []string{"BTCUSDT", "ETHUSDT"} + s.assertReq(func(r *request) { + e := newRequest().setParam("symbols", symbols) + s.assertRequestEqual(e, r) + }) + res, err := s.client.NewTradingDayTickerService().Symbols(symbols).Do(newContext()) + s.r().NoError(err) + + e := []*TradingDayTicker{ + { + Symbol: "BTCUSDT", + PriceChange: "-25.63000000", + PriceChangePercent: "-0.042", + WeightedAvgPrice: "60989.95178227", + OpenPrice: "60986.68000000", + HighPrice: "61078.01000000", + LowPrice: "60922.00000000", + LastPrice: "60961.05000000", + Volume: "707.02697000", + QuoteVolume: "43121540.80906740", + OpenTime: 1719705600000, + CloseTime: 1719791999999, + FirstId: 3655222498, + LastId: 3655289744, + Count: 67247}} + + s.assertTradingDayTickersEqual(e, res) +} + +func (s *tradingDayTickerServiceTestSuite) assertTradingDayTickerEqual(e, a *TradingDayTicker) { + r := s.r() + r.Equal(e.Symbol, a.Symbol, "Symbol") + r.Equal(e.PriceChange, a.PriceChange, "PriceChange") + r.Equal(e.PriceChangePercent, a.PriceChangePercent, "PriceChangePercent") + r.Equal(e.WeightedAvgPrice, a.WeightedAvgPrice, "WeightedAvgPrice") + r.Equal(e.OpenPrice, a.OpenPrice, "OpenPrice") + r.Equal(e.HighPrice, a.HighPrice, "HighPrice") + r.Equal(e.LowPrice, a.LowPrice, "LowPrice") + r.Equal(e.LastPrice, a.LastPrice, "LastPrice") + r.Equal(e.Volume, a.Volume, "Volume") + r.Equal(e.QuoteVolume, a.QuoteVolume, "QuoteVolume") + r.Equal(e.OpenTime, a.OpenTime, "OpenTime") + r.Equal(e.CloseTime, a.CloseTime, "CloseTime") + r.Equal(e.FirstId, a.FirstId, "FirstId") + r.Equal(e.LastId, a.LastId, "LastId") + r.Equal(e.Count, a.Count, "Count") +} + +func (s *tradingDayTickerServiceTestSuite) assertTradingDayTickersEqual(e, a []*TradingDayTicker) { + s.r().Len(e, len(a)) + for i := range e { + s.assertTradingDayTickerEqual(e[i], a[i]) + } +} diff --git a/v2/uiKlines_service.go b/v2/uiKlines_service.go new file mode 100644 index 00000000..d314ab1c --- /dev/null +++ b/v2/uiKlines_service.go @@ -0,0 +1,114 @@ +package binance + +import ( + "context" + "fmt" + "net/http" +) + +type UiKlinesService struct { + c *Client + symbol string + interval string + startTime *uint64 + endTime *uint64 + timeZone *string // default: 0(utc) + limit *uint32 // default 500, max 1000 +} + +type UiKline struct { + OpenTime uint64 + Open string + High string + Low string + Close string + Volume string + CloseTime uint64 + QuoteVolume string + TradeNum uint64 + TakerBuyBaseAssetVolume string + TakerBuyQuoteAssetVolume string +} + +func (s *UiKlinesService) Symbol(symbol string) *UiKlinesService { + s.symbol = symbol + return s +} + +func (s *UiKlinesService) Interval(interval string) *UiKlinesService { + s.interval = interval + return s +} + +func (s *UiKlinesService) StartTime(startTime uint64) *UiKlinesService { + s.startTime = &startTime + return s +} + +func (s *UiKlinesService) EndTime(endTime uint64) *UiKlinesService { + s.endTime = &endTime + return s +} + +func (s *UiKlinesService) TimeZone(timeZone string) *UiKlinesService { + s.timeZone = &timeZone + return s +} + +func (s *UiKlinesService) Limit(limit uint32) *UiKlinesService { + s.limit = &limit + return s +} + +func (s *UiKlinesService) Do(ctx context.Context, opts ...RequestOption) (res []*UiKline, err error) { + r := &request{ + method: http.MethodGet, + endpoint: "/api/v3/uiKlines", + } + r.setParam("symbol", s.symbol) + r.setParam("interval", s.interval) + if s.startTime != nil { + r.setParam("startTime", *s.startTime) + } + if s.endTime != nil { + r.setParam("endTime", *s.endTime) + } + if s.timeZone != nil { + r.setParam("timeZone", *s.timeZone) + } + if s.limit != nil { + r.setParam("limit", *s.limit) + } + + data, err := s.c.callAPI(ctx, r, opts...) + if err != nil { + return nil, err + } + j, err := newJSON(data) + if err != nil { + return []*UiKline{}, err + } + num := len(j.MustArray()) + res = make([]*UiKline, num) + for i := 0; i < num; i++ { + item := j.GetIndex(i) + if len(item.MustArray()) < 12 { + err = fmt.Errorf("invalid UiKline response") + return []*UiKline{}, err + } + res[i] = &UiKline{ + OpenTime: item.GetIndex(0).MustUint64(), + Open: item.GetIndex(1).MustString(), + High: item.GetIndex(2).MustString(), + Low: item.GetIndex(3).MustString(), + Close: item.GetIndex(4).MustString(), + Volume: item.GetIndex(5).MustString(), + CloseTime: item.GetIndex(6).MustUint64(), + QuoteVolume: item.GetIndex(7).MustString(), + TradeNum: item.GetIndex(8).MustUint64(), + TakerBuyBaseAssetVolume: item.GetIndex(9).MustString(), + TakerBuyQuoteAssetVolume: item.GetIndex(10).MustString(), + } + } + return res, nil +} diff --git a/v2/uiKlines_service_test.go b/v2/uiKlines_service_test.go new file mode 100644 index 00000000..7f0d8743 --- /dev/null +++ b/v2/uiKlines_service_test.go @@ -0,0 +1,83 @@ +package binance + +import ( + "testing" + + "github.com/stretchr/testify/suite" +) + +type uiKlinesServiceTestSuite struct { + baseTestSuite +} + +func TestUiKlinesService(t *testing.T) { + suite.Run(t, new(uiKlinesServiceTestSuite)) +} + +func (s *uiKlinesServiceTestSuite) TestUiKlines() { + data := []byte(`[ + [ + + 1499040000000, + "0.01634790", + "0.80000000", + "0.01575800", + "0.01577100", + "148976.11427815", + 1499644799999, + "2434.19055334", + 308, + "1756.87402397", + "28.46694368", + "0" + ] +]`) + s.mockDo(data, nil) + defer s.assertDo() + var symbol string = "BTCUSDT" + var interval string = "15m" + s.assertReq(func(r *request) { + e := newRequest().setParam("symbol", symbol).setParam("interval", interval) + s.assertRequestEqual(e, r) + }) + res, err := s.client.NewUiKlinesService().Symbol(symbol).Interval(interval).Do(newContext()) + s.r().NoError(err) + s.Len(res, 1) + e := []*UiKline{ + { + OpenTime: 1499040000000, + Open: "0.01634790", + High: "0.80000000", + Low: "0.01575800", + Close: "0.01577100", + Volume: "148976.11427815", + CloseTime: 1499644799999, + QuoteVolume: "2434.19055334", + TradeNum: 308, + TakerBuyBaseAssetVolume: "1756.87402397", + TakerBuyQuoteAssetVolume: "28.46694368"}} + + s.assertUiKlinesEqual(e, res) +} + +func (s *uiKlinesServiceTestSuite) assertUiKlineEqual(e, a *UiKline) { + r := s.r() + r.Equal(e.OpenTime, a.OpenTime, "OpenTime") + r.Equal(e.Open, a.Open, "Open") + r.Equal(e.High, a.High, "High") + r.Equal(e.Low, a.Low, "Low") + r.Equal(e.Close, a.Close, "Close") + r.Equal(e.Volume, a.Volume, "Volume") + r.Equal(e.CloseTime, a.CloseTime, "CloseTime") + r.Equal(e.QuoteVolume, a.QuoteVolume, "QuoteVolume") + r.Equal(e.TradeNum, a.TradeNum, "TradeNum") + r.Equal(e.TakerBuyBaseAssetVolume, a.TakerBuyBaseAssetVolume, "TakerBuyBaseAssetVolume") + r.Equal(e.TakerBuyQuoteAssetVolume, a.TakerBuyQuoteAssetVolume, "TakerBuyQuoteAssetVolume") +} + +func (s *uiKlinesServiceTestSuite) assertUiKlinesEqual(e, a []*UiKline) { + s.r().Len(e, len(a)) + for i := range e { + s.assertUiKlineEqual(e[i], a[i]) + } +}