diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c27f2be..5cba118 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -25,7 +25,6 @@ jobs: with: go-version: '^1.18' - run: go test ./... -coverpkg=./... -coverprofile=coverage.out - - run: go test ./... -json > test.out - run: go vet ./... 2> govet.out || true # Ignore go vet status code lint-check: diff --git a/.version b/.version index a92e827..254a9f2 100644 --- a/.version +++ b/.version @@ -1 +1 @@ -v0.0.4 \ No newline at end of file +v0.0.6 \ No newline at end of file diff --git a/README.md b/README.md index 301c090..7997dd2 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ go get -u github.com/cksidharthan/go-bybit | USDT Perpetual | [Wallet Data](https://bybit-exchange.github.io/docs/futuresV2/linear/#t-wallet) | :heavy_check_mark: | :heavy_check_mark: | | Inverse Perpetual | [Market Data](https://bybit-exchange.github.io/docs/futuresV2/inverse/#t-marketdata) | :heavy_check_mark: | :heavy_check_mark: | | Inverse Perpetual | [Account Data](https://bybit-exchange.github.io/docs/futuresV2/inverse/#t-accountdata) | :construction: | :construction: | -| Inverse Perpetual | [Wallet Data](https://bybit-exchange.github.io/docs/futuresV2/inverse/#t-wallet) | :construction: | :construction: | +| Inverse Perpetual | [Wallet Data](https://bybit-exchange.github.io/docs/futuresV2/inverse/#t-wallet) | :heavy_check_mark: | :heavy_check_mark: | ### Contributing diff --git a/bybit/constants.go b/bybit/constants.go index 0cad18a..d93f82c 100644 --- a/bybit/constants.go +++ b/bybit/constants.go @@ -92,4 +92,9 @@ const ( PublicInversePerpetualOpenInterestPath = "/v2/public/open-interest" PublicInversePerpetualLatestBigDealPath = "/v2/public/big-deal" PublicInversePerpetualLongShortRatioPath = "/v2/public/account-ratio" + + PrivateInversePerpetualWalletBalancePath = "/v2/private/wallet/balance" + PrivateInversePerpetualWalletFundRecordsPath = "/v2/private/wallet/fund/records" + PrivateInversePerpetualWithdrawRecordsPath = "/v2/private/wallet/withdraw/list" + PrivateInversePerpetualAssetExchangeRecords = "/v2/private/exchange-order/list" ) diff --git a/rest/domain/inverse_perpetual/wallet_methods.go b/rest/domain/inverse_perpetual/wallet_methods.go index 4f89ea1..68d4c00 100644 --- a/rest/domain/inverse_perpetual/wallet_methods.go +++ b/rest/domain/inverse_perpetual/wallet_methods.go @@ -1,4 +1,10 @@ package inverseperp +import "context" + type WalletInterface interface { + GetWalletBalance(ctx context.Context, params *WalletBalanceParams) (*WalletBalanceResponse, error) + GetWalletFundRecords(ctx context.Context, params *WalletFundRecordsParams) (*WalletFundRecordsResponse, error) + GetWithdrawRecords(ctx context.Context, params *WithdrawRecordsParams) (*WithdrawRecordsResponse, error) + GetAssetExchangeRecords(ctx context.Context, params *AssetExchangeRecordsParams) (*AssetExchangeRecordsResponse, error) } diff --git a/rest/domain/inverse_perpetual/wallet_types.go b/rest/domain/inverse_perpetual/wallet_types.go index 98658b4..bd56e2c 100644 --- a/rest/domain/inverse_perpetual/wallet_types.go +++ b/rest/domain/inverse_perpetual/wallet_types.go @@ -1 +1,115 @@ package inverseperp + +import "github.com/cksidharthan/go-bybit/rest/domain" + +type WalletBalanceParams struct { + Coin string `url:"coin" json:"coin,omitempty" description:"currency alias. Returns all wallet balances if not passed."` +} + +type WalletBalanceResponse struct { + domain.BaseResponse `json:",inline"` + Result map[string]WalletBalanceResult `json:"result"` +} + +type WalletBalanceResult struct { + Equity float64 `url:"equity" json:"equity"` + AvailableBalance float64 `url:"available_balance" json:"available_balance"` + UsedMargin float64 `url:"used_margin" json:"used_margin"` + OrderMargin float64 `url:"order_margin" json:"order_margin"` + PositionMargin float64 `url:"position_margin" json:"position_margin"` + OccClosingFee float64 `url:"occ_closing_fee" json:"occ_closing_fee"` + OccFundingFee float64 `url:"occ_funding_fee" json:"occ_funding_fee"` + WalletBalance float64 `url:"wallet_balance" json:"wallet_balance"` + RealisedPnl float64 `url:"realised_pnl" json:"realised_pnl"` + UnrealisedPnl float64 `url:"unrealised_pnl" json:"unrealised_pnl"` + CumRealisedPnl float64 `url:"cum_realised_pnl" json:"cum_realised_pnl"` + GivenCash float64 `url:"given_cash" json:"given_cash"` + ServiceCash float64 `url:"service_cash" json:"service_cash"` +} + +type WalletFundRecordsParams struct { + StartDate string `url:"start_date" json:"start_date,omitempty" description:"start date of the query"` + EndDate string `url:"end_date" json:"end_date,omitempty" description:"end date of the query"` + Currency string `url:"currency" json:"currency,omitempty" description:"currency alias"` + Coin string `url:"coin" json:"coin,omitempty" description:"currency alias"` + WalletFundType string `url:"wallet_fund_type" json:"wallet_fund_type,omitempty" description:"wallet fund type"` + Limit int64 `url:"limit" json:"limit,omitempty" description:"number of records to return"` + Page int64 `url:"page" json:"page,omitempty" description:"page number"` +} + +type WalletFundRecordsResponse struct { + domain.BaseResponse `json:",inline"` + Result WalletFundRecordsResult `json:"result"` +} + +type WalletFundRecordsResult struct { + Data []WalletFundRecordsData `json:"data"` +} + +type WalletFundRecordsData struct { + UserID int64 `url:"user_id" json:"user_id"` + ID int64 `url:"id" json:"id"` + Coin string `url:"coin" json:"coin"` + WalletID int64 `url:"wallet_id" json:"wallet_id"` + Type string `url:"type" json:"type"` + Amount float64 `url:"amount" json:"amount"` + TxID string `url:"tx_id" json:"tx_id"` + Address string `url:"address" json:"address"` + WalletBalance string `url:"wallet_balance" json:"wallet_balance"` + ExecTime string `url:"exec_time" json:"exec_time"` + CrossSeq int64 `url:"cross_seq" json:"cross_seq"` +} + +type WithdrawRecordsParams struct { + StartDate string `url:"start_date" json:"start_date,omitempty" description:"start date of the query"` + EndDate string `url:"end_date" json:"end_date,omitempty" description:"end date of the query"` + Coin string `url:"coin" json:"coin,omitempty" description:"currency alias"` + Status string `url:"status" json:"status,omitempty" description:"status of the withdrawal"` + Limit int64 `url:"limit" json:"limit,omitempty" description:"number of records to return"` + Page int64 `url:"page" json:"page,omitempty" description:"page number"` +} + +type WithdrawRecordsResponse struct { + domain.BaseResponse `json:",inline"` + Result WithdrawRecordsResult `json:"result"` +} + +type WithdrawRecordsResult struct { + Data []WithdrawRecordsData `json:"data"` + CurrentPage int64 `json:"current_page"` + LastPage int64 `json:"last_page"` +} + +type WithdrawRecordsData struct { + ID int64 `url:"id" json:"id"` + UserID int64 `url:"user_id" json:"user_id"` + Coin string `url:"coin" json:"coin"` + Status string `url:"status" json:"status"` + Amount string `url:"amount" json:"amount"` + Fee string `url:"fee" json:"fee"` + Address string `url:"address" json:"address"` + TxID string `url:"tx_id" json:"tx_id"` + SubmittedAt string `url:"submitted_at" json:"submitted_at"` + UpdatedAt string `url:"updated_at" json:"updated_at"` +} + +type AssetExchangeRecordsParams struct { + Limit int64 `url:"limit" json:"limit,omitempty" description:"number of records to return"` + From int64 `url:"from" json:"from,omitempty" description:"from id"` + Direction string `url:"direction" json:"direction,omitempty" description:"direction of the query"` +} + +type AssetExchangeRecordsResponse struct { + domain.BaseResponse `json:",inline"` + Result []AssetExchangeRecordsResult `json:"result"` +} + +type AssetExchangeRecordsResult struct { + FromCoin string `url:"from_coin" json:"from_coin"` + FromAmount float64 `url:"from_amount" json:"from_amount"` + ToCoin string `url:"to_coin" json:"to_coin"` + ToAmount float64 `url:"to_amount" json:"to_amount"` + ExchangeRate float64 `url:"exchange_rate" json:"exchange_rate"` + FromFee float64 `url:"from_fee" json:"from_fee"` + CreatedAt string `url:"created_at" json:"created_at"` +} diff --git a/rest/domain/linear/account_types.go b/rest/domain/linear/account_types.go index 30ef281..5cc96c3 100644 --- a/rest/domain/linear/account_types.go +++ b/rest/domain/linear/account_types.go @@ -500,9 +500,9 @@ type AddReduceMarginResult struct { } type SetLeverageParams struct { - Symbol string `url:"symbol" json:"symbol"` - BuyLeverage int `url:"buy_leverage" json:"buy_leverage"` - SellLeverage int `url:"sell_leverage" json:"sell_leverage"` + Symbol string `url:"symbol" json:"symbol"` + BuyLeverage float64 `url:"buy_leverage" json:"buy_leverage"` + SellLeverage float64 `url:"sell_leverage" json:"sell_leverage"` } type SetLeverageResponse struct { diff --git a/rest/inverse_perpetual/market/market.go b/rest/inverse_perpetual/market/market.go index 9511ec8..91eafe7 100644 --- a/rest/inverse_perpetual/market/market.go +++ b/rest/inverse_perpetual/market/market.go @@ -106,7 +106,7 @@ func (c *InversePerpetualMarketClient) QueryPremiumIndexKline(ctx context.Contex // // docs - https://bybit-exchange.github.io/docs/futuresV2/inverse/#t-marketopeninterest func (c *InversePerpetualMarketClient) OpenInterest(ctx context.Context, params *inverseperp.OpenInterestParams) (response *inverseperp.OpenInterestResponse, err error) { - err = c.Transporter.UnsignedRequest(ctx, http.MethodGet, bybit.PublicInversePerpetualOrderBookPath, params, &response) + err = c.Transporter.UnsignedRequest(ctx, http.MethodGet, bybit.PublicInversePerpetualOpenInterestPath, params, &response) if err != nil { return } diff --git a/rest/inverse_perpetual/market/market_test.go b/rest/inverse_perpetual/market/market_test.go index 3335326..47fd5f1 100644 --- a/rest/inverse_perpetual/market/market_test.go +++ b/rest/inverse_perpetual/market/market_test.go @@ -139,7 +139,7 @@ func TestClient_InversePerpetual_Market(t *testing.T) { t.Parallel() response, err := bybitClient.Market().OpenInterest(context.Background(), &domain.OpenInterestParams{ Symbol: "BTCUSD", - Limit: 50, + Period: "5min", }) assert.NoError(t, err) assert.Equal(t, 0, response.RetCode) diff --git a/rest/inverse_perpetual/wallet/client.go b/rest/inverse_perpetual/wallet/client.go index 99ce867..b07a088 100644 --- a/rest/inverse_perpetual/wallet/client.go +++ b/rest/inverse_perpetual/wallet/client.go @@ -6,12 +6,12 @@ import ( ) type InversePerpetualWalletClient struct { - transporter transport.Transporter + Transporter transport.Transporter } func NewInversePerpetualWalletClient(url, apiKey, apiSecret string) *InversePerpetualWalletClient { transporter := httpTransport.New(url, apiKey, apiSecret) return &InversePerpetualWalletClient{ - transporter: transporter, + Transporter: transporter, } } diff --git a/rest/inverse_perpetual/wallet/wallet.go b/rest/inverse_perpetual/wallet/wallet.go new file mode 100644 index 0000000..5e3e9a8 --- /dev/null +++ b/rest/inverse_perpetual/wallet/wallet.go @@ -0,0 +1,79 @@ +package wallet + +import ( + "context" + "net/http" + + "github.com/cksidharthan/go-bybit/bybit" + inverseperp "github.com/cksidharthan/go-bybit/rest/domain/inverse_perpetual" +) + +/* +GetWalletBalance - get wallet balance. [ /v2/private/wallet/balance - GET ] + +# Get wallet balance info + +docs - https://bybit-exchange.github.io/docs/futuresV2/inverse/#t-balance +*/ +func (c *InversePerpetualWalletClient) GetWalletBalance(ctx context.Context, params *inverseperp.WalletBalanceParams) (response *inverseperp.WalletBalanceResponse, err error) { + err = c.Transporter.SignedRequest(ctx, http.MethodGet, bybit.PrivateInversePerpetualWalletBalancePath, params, &response) + if err != nil { + return + } + return +} + +/* +GetWalletFundRecords - get wallet fund records. [ /v2/private/wallet/fund/records - GET ] + +Get wallet fund records. This endpoint also shows exchanges from the Asset Exchange, where the types for the exchange are ExchangeOrderWithdraw and ExchangeOrderDeposit. + +This endpoint returns incomplete information for transfers involving the derivatives wallet. Use the account asset API for creating and querying internal transfers. + +docs - https://bybit-exchange.github.io/docs/futuresV2/inverse/#t-walletrecords +*/ +func (c *InversePerpetualWalletClient) GetWalletFundRecords(ctx context.Context, params *inverseperp.WalletFundRecordsParams) (response *inverseperp.WalletFundRecordsResponse, err error) { + err = c.Transporter.SignedRequest(ctx, http.MethodGet, bybit.PrivateInversePerpetualWalletFundRecordsPath, params, &response) + if err != nil { + return + } + return +} + +/* +GetWithdrawRecords - get wallet withdraw records. [ /v2/private/wallet/withdraw/list - GET ] + +Get withdrawal records. + +The difference between data returned by this endpoint and data of type Withdraw in the Wallet Fund Records endpoint: + +This endpoint provides one withdrawal operation per record, and you can check the current withdrawal state with the status field. + +Once you have submitted a withdrawal application, there will be a record with type Withdraw, and if the application is CancelByUser, Reject or Expire in the Wallet Fund Records endpoint, with a corresponding record with type Refund. + +docs - https://bybit-exchange.github.io/docs/futuresV2/inverse/#t-withdrawrecords +*/ +func (c *InversePerpetualWalletClient) GetWithdrawRecords(ctx context.Context, params *inverseperp.WithdrawRecordsParams) (response *inverseperp.WithdrawRecordsResponse, err error) { + err = c.Transporter.SignedRequest(ctx, http.MethodGet, bybit.PrivateInversePerpetualWithdrawRecordsPath, params, &response) + if err != nil { + return + } + return +} + +/* +GetAssetExchangeRecords - get asset exchange records. [ /v2/private/asset/records - GET ] + +Get asset exchange records. + +This endpoint returns the records of asset exchanges, including the exchanges from the Wallet Fund Records endpoint. + +docs - https://bybit-exchange.github.io/docs/futuresV2/inverse/#t-assetexchangerecords +*/ +func (c *InversePerpetualWalletClient) GetAssetExchangeRecords(ctx context.Context, params *inverseperp.AssetExchangeRecordsParams) (response *inverseperp.AssetExchangeRecordsResponse, err error) { + err = c.Transporter.SignedRequest(ctx, http.MethodGet, bybit.PrivateInversePerpetualAssetExchangeRecords, params, &response) + if err != nil { + return + } + return +} diff --git a/rest/inverse_perpetual/wallet/wallet_test.go b/rest/inverse_perpetual/wallet/wallet_test.go new file mode 100644 index 0000000..06fb979 --- /dev/null +++ b/rest/inverse_perpetual/wallet/wallet_test.go @@ -0,0 +1,55 @@ +package wallet_test + +import ( + "context" + "os" + "testing" + + "github.com/cksidharthan/go-bybit/bybit" + domain "github.com/cksidharthan/go-bybit/rest/domain/inverse_perpetual" + inverseperp "github.com/cksidharthan/go-bybit/rest/inverse_perpetual" + "github.com/stretchr/testify/assert" +) + +func TestClient_InversePerpetualWallet(t *testing.T) { + t.Parallel() + inversePerpClient := inverseperp.NewInversePerpetualClient(bybit.BybitTestnetBaseURL, os.Getenv("BYBIT_API_KEY"), os.Getenv("BYBIT_API_SECRET")) + + t.Run("Get Wallet Balance - INVERSE PERPETUAL", func(t *testing.T) { + t.Parallel() + response, err := inversePerpClient.Wallet().GetWalletBalance(context.Background(), &domain.WalletBalanceParams{ + Coin: "BTC", + }) + assert.NoError(t, err) + assert.Equal(t, 0, response.RetCode) + assert.NotEmpty(t, response) + assert.NotNil(t, response) + }) + + t.Run("Get Wallet Fund Records - INVERSE PERPETUAL", func(t *testing.T) { + t.Parallel() + response, err := inversePerpClient.Wallet().GetWalletFundRecords(context.Background(), &domain.WalletFundRecordsParams{}) + assert.NoError(t, err) + assert.Equal(t, 0, response.RetCode) + assert.NotEmpty(t, response) + assert.NotNil(t, response) + }) + + t.Run("Get Withdraw Records - INVERSE PERPETUAL", func(t *testing.T) { + t.Parallel() + response, err := inversePerpClient.Wallet().GetWithdrawRecords(context.Background(), &domain.WithdrawRecordsParams{}) + assert.NoError(t, err) + assert.Equal(t, 0, response.RetCode) + assert.NotEmpty(t, response) + assert.NotNil(t, response) + }) + + t.Run("Get Asset Exchange Records - INVERSE PERPETUAL", func(t *testing.T) { + t.Parallel() + response, err := inversePerpClient.Wallet().GetAssetExchangeRecords(context.Background(), &domain.AssetExchangeRecordsParams{}) + assert.NoError(t, err) + assert.Equal(t, 0, response.RetCode) + assert.NotEmpty(t, response) + assert.NotNil(t, response) + }) +} diff --git a/rest/linear/wallet/wallet_test.go b/rest/linear/wallet/wallet_test.go index 6294d46..fe9a3e1 100644 --- a/rest/linear/wallet/wallet_test.go +++ b/rest/linear/wallet/wallet_test.go @@ -17,7 +17,9 @@ func TestClient_Linear_Wallet(t *testing.T) { t.Run("Get Wallet Balance - LINEAR", func(t *testing.T) { t.Parallel() - response, err := bybitClient.Wallet().GetWalletBalance(context.Background(), &linear.GetWalletBalanceParams{}) + response, err := bybitClient.Wallet().GetWalletBalance(context.Background(), &linear.GetWalletBalanceParams{ + Coin: "BTC", + }) assert.NoError(t, err) assert.Equal(t, 0, response.RetCode) assert.NotEmpty(t, response) @@ -45,7 +47,11 @@ func TestClient_Linear_Wallet(t *testing.T) { t.Run("Get Asset Exchange Records - LINEAR", func(t *testing.T) { t.Parallel() - response, err := bybitClient.Wallet().GetAssetExchangeRecords(context.Background(), &linear.GetAssetExchangeRecordsParams{}) + response, err := bybitClient.Wallet().GetAssetExchangeRecords(context.Background(), &linear.GetAssetExchangeRecordsParams{ + Limit: 5, + From: 0, + Direction: "", + }) assert.NoError(t, err) assert.Equal(t, 0, response.RetCode) assert.NotEmpty(t, response)