diff --git a/README.md b/README.md index 6b5e160..9bebff7 100644 --- a/README.md +++ b/README.md @@ -32,13 +32,126 @@ Your contributions are most welcome! bybit-go-api is under active development with the latest features and updates from Bybit's API implemented promptly. The module utilizes minimal external libraries to provide a lightweight and efficient experience. If you've made enhancements or fixed bugs, please submit a pull request. ## Installation -Ensure you have go 1.21.0 or higher. You can include bybit-go-api in your project using Maven or Gradle. +Ensure you have go 1.21.0 or higher. And use dependencies as below +```go +require ( + github.com/google/uuid v1.4.0 + github.com/gorilla/websocket v1.5.1 + github.com/stretchr/testify v1.8.4 +) +``` ## Usage Note: Replace placeholders (like YOUR_API_KEY, links, or other details) with the actual information. You can also customize this template to better fit the actual state and details of your Java API. ### Rest API +- Place an order by Map +```go +client := bybit.NewBybitHttpClient("YOUR_API_KEY", "YOUR_API_SECRET", bybit.WithBaseURL(bybit.TESTNET)) +params := map[string]interface{}{"category": "linear", "symbol": "BTCUSDT", "side": "Buy", "positionIdx": 0, "orderType": "Limit", "qty": "0.001", "price": "10000", "timeInForce": "GTC"} +orderResult, err := client.NewTradeService(params).PlaceOrder(context.Background()) +if err != nil { + fmt.Println(err) + return +} +fmt.Println(bybit.PrettyPrint(orderResult)) +``` + +- Place an order by Trade Class +```go +client := bybit.NewBybitHttpClient("YOUR_API_KEY", "YOUR_API_SECRET", bybit.WithBaseURL(bybit.TESTNET)) +orderResult, err := client.NewPlaceOrderService("linear", "XRPUSDT", "Buy", "Market", "10").Do(context.Background()) +if err != nil { + fmt.Println(err) + return +} +fmt.Println(bybit.PrettyPrint(orderResult)) +``` + +- Place batch order +```go +client := bybit.NewBybitHttpClient("YOUR_API_KEY", "YOUR_API_SECRET", bybit.WithBaseURL(bybit.TESTNET)) +params := map[string]interface{}{"category": "option", + "request": []map[string]interface{}{ + { + "category": "option", + "symbol": "BTC-10FEB23-24000-C", + "orderType": "Limit", + "side": "Buy", + "qty": "0.1", + "price": "5", + "orderIv": "0.1", + "timeInForce": "GTC", + "orderLinkId": "9b381bb1-401", + "mmp": false, + "reduceOnly": false, + }, + { + "category": "option", + "symbol": "BTC-10FEB23-24000-C", + "orderType": "Limit", + "side": "Buy", + "qty": "0.1", + "price": "5", + "orderIv": "0.1", + "timeInForce": "GTC", + "orderLinkId": "82ee86dd-001", + "mmp": false, + "reduceOnly": false, + }, + }, +} +orderResult, err := client.NewTradeService(params).PlaceBatchOrder(context.Background()) +if err != nil { + fmt.Println(err) + return +} +fmt.Println(bybit.PrettyPrint(orderResult)) +``` + +- Get Position +```go +client := bybit.NewBybitHttpClient("YOUR_API_KEY", "YOUR_API_SECRET", bybit.WithBaseURL(bybit.TESTNET)) +params := map[string]interface{}{"category": "linear", "settleCoin": "USDT", "limit": 10} +orderResult, err := client.NewPositionService(params).GetPositionList(context.Background()) +if err != nil { + fmt.Println(err) + return +} +fmt.Println(bybit.PrettyPrint(orderResult)) +``` + +- Get Transaction Log +```go +client := bybit.NewBybitHttpClient("YOUR_API_KEY", "YOUR_API_SECRET", bybit.WithBaseURL(bybit.TESTNET)) +params := map[string]interface{}{"accountType": "UNIFIED", "category": "linear"} +accountResult, err := client.NewAccountService(params).GetTransactionLog(context.Background()) +if err != nil { + fmt.Println(err) + return +} +fmt.Println(bybit.PrettyPrint(accountResult)) +``` + ### Websocket public channel +- Order book Subscribe +```go +ws := bybit.NewBybitPublicWebSocket("wss://stream.bybit.com/v5/public/spot", func(message string) error { +fmt.Println("Received:", message) +return nil +}) +_ = ws.Connect([]string{"orderbook.1.BTCUSDT"}) +select {} +``` + ### Websocket private channel +```go +ws := bybit.NewBybitPrivateWebSocket("wss://stream-testnet.bybit.com/v5/private", "YOUR_API_KEY", "YOUR_API_SECRET", func(message string) error { + fmt.Println("Received:", message) + return nil +}) +_ = ws.Connect([]string{"order"}) +select {} +``` ## Contact For support, join our Bybit API community on [Telegram](https://t.me/Bybitapi). diff --git a/bybit_api_client.go b/bybit_api_client.go index 5ea6c43..681bb2e 100644 --- a/bybit_api_client.go +++ b/bybit_api_client.go @@ -64,6 +64,11 @@ func (c *Client) debug(format string, v ...interface{}) { } } +// FormatTimestamp formats a time into Unix timestamp in milliseconds, as requested by Binance. +func FormatTimestamp(t time.Time) int64 { + return t.UnixNano() / int64(time.Millisecond) +} + func GetCurrentTime() int64 { now := time.Now() unixNano := now.UnixNano() diff --git a/bybit_api_client_test.go b/bybit_api_client_test.go new file mode 100644 index 0000000..c1d20c0 --- /dev/null +++ b/bybit_api_client_test.go @@ -0,0 +1,150 @@ +package bybit_connector + +import ( + "bytes" + "context" + "io" + "net/http" + "net/url" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" + "github.com/stretchr/testify/suite" +) + +type baseTestSuite struct { + suite.Suite + client *mockedClient + apiKey string + apiSecret string + baseURL string +} + +func (s *baseTestSuite) r() *require.Assertions { + return s.Require() +} + +func (s *baseTestSuite) SetupTest() { + s.apiKey = "dummyAPIKey" + s.apiSecret = "dummyApiSecret" + s.baseURL = "https://dummyapi.com" + s.client = newMockedClient(s.apiKey, s.apiSecret, s.baseURL) +} + +func (s *baseTestSuite) mockDo(data []byte, err error, statusCode ...int) { + s.client.Client.do = s.client.do + code := http.StatusOK + if len(statusCode) > 0 { + code = statusCode[0] + } + s.client.On("do", anyHTTPRequest()).Return(newHTTPResponse(data, code), err) +} + +func (s *baseTestSuite) assertDo() { + s.client.AssertCalled(s.T(), "do", anyHTTPRequest()) +} + +func (s *baseTestSuite) assertReq(f func(r *request)) { + s.client.assertReq = f +} + +func (s *baseTestSuite) assertRequestEqual(e, a *request) { + s.assertURLValuesEqual(e.query, a.query) +} + +func (s *baseTestSuite) assertURLValuesEqual(e, a url.Values) { + var eKeys, aKeys []string + for k := range e { + eKeys = append(eKeys, k) + } + for k := range a { + aKeys = append(aKeys, k) + } + r := s.r() + r.Len(aKeys, len(eKeys)) + for k := range a { + switch k { + case timestampKey, signatureKey: + r.NotEmpty(a.Get(k)) + continue + } + r.Equal(e[k], a[k], k) + } +} + +func anythingOfType(t string) mock.AnythingOfTypeArgument { + return mock.AnythingOfType(t) +} + +func newContext() context.Context { + return context.Background() +} + +func anyHTTPRequest() mock.AnythingOfTypeArgument { + return anythingOfType("*http.Request") +} + +func newHTTPResponse(data []byte, statusCode int) *http.Response { + return &http.Response{ + Body: io.NopCloser(bytes.NewBuffer(data)), + StatusCode: statusCode, + } +} + +func newRequest() *request { + r := &request{ + query: url.Values{}, + } + return r +} + +func newSignedRequest() *request { + return newRequest().setParams(params{ + timestampKey: "", + signatureKey: "", + apiRequestKey: "", + recvWindowKey: "5000", + signTypeKey: "2", + }) +} + +type assertReqFunc func(r *request) + +type mockedClient struct { + mock.Mock + *Client + assertReq assertReqFunc +} + +func newMockedClient(apiKey, apiSecret, baseURL string) *mockedClient { + m := new(mockedClient) + m.Client = NewBybitHttpClient(apiKey, apiSecret, WithBaseURL(baseURL)) + return m +} + +func (m *mockedClient) do(req *http.Request) (*http.Response, error) { + if m.assertReq != nil { + r := newRequest() + r.query = req.URL.Query() + if req.Body != nil && req.ContentLength > 0 { + bs := make([]byte, req.ContentLength) + _, err := req.Body.Read(bs) + if err != nil && err != io.EOF { + return nil, err // Handle read error + } + _ = req.Body.Close() // Close the body if we have read from it + r.body = bytes.NewBuffer(bs) + } + m.assertReq(r) + } + args := m.Called(req) + return args.Get(0).(*http.Response), args.Error(1) +} + +func TestFormatTimestamp(t *testing.T) { + tm, _ := time.Parse("2006-01-02 15:04:05", "2018-06-01 01:01:01") + assert.Equal(t, int64(1527814861000), FormatTimestamp(tm)) +} diff --git a/examples/Trade/place_batch_trade.go b/examples/Trade/place_batch_trade.go index bae2836..651c3fa 100644 --- a/examples/Trade/place_batch_trade.go +++ b/examples/Trade/place_batch_trade.go @@ -11,7 +11,7 @@ func main() { } func PlaceBatchTrade() { - client := bybit.NewBybitHttpClient("8wYkmpLsMg10eNQyPm", "Ouxc34myDnXvei54XsBZgoQzfGxO4bkr2Zsj", bybit.WithBaseURL(bybit.TESTNET)) + client := bybit.NewBybitHttpClient("YOUR_API_KEY", "YOUR_API_SECRET", bybit.WithBaseURL(bybit.TESTNET)) params := map[string]interface{}{"category": "option", "request": []map[string]interface{}{ { diff --git a/examples/Trade/place_order.go b/examples/Trade/place_order.go index e640850..7d86b0d 100644 --- a/examples/Trade/place_order.go +++ b/examples/Trade/place_order.go @@ -11,7 +11,7 @@ func main() { } func PlaceOrder() { - client := bybit.NewBybitHttpClient("8wYkmpLsMg10eNQyPm", "Ouxc34myDnXvei54XsBZgoQzfGxO4bkr2Zsj", bybit.WithBaseURL(bybit.TESTNET)) + client := bybit.NewBybitHttpClient("YOUR_API_KEY", "YOUR_API_SECRET", bybit.WithBaseURL(bybit.TESTNET)) orderResult, err := client.NewPlaceOrderService("linear", "XRPUSDT", "Buy", "Market", "10").Do(context.Background()) if err != nil { fmt.Println(err) diff --git a/examples/Trade/place_trade.go b/examples/Trade/place_trade.go index 5558d4f..9d1d486 100644 --- a/examples/Trade/place_trade.go +++ b/examples/Trade/place_trade.go @@ -11,7 +11,7 @@ func main() { } func PlaceTrade() { - client := bybit.NewBybitHttpClient("8wYkmpLsMg10eNQyPm", "Ouxc34myDnXvei54XsBZgoQzfGxO4bkr2Zsj", bybit.WithBaseURL(bybit.TESTNET)) + client := bybit.NewBybitHttpClient("YOUR_API_KEY", "YOUR_API_SECRET", bybit.WithBaseURL(bybit.TESTNET)) params := map[string]interface{}{"category": "linear", "symbol": "BTCUSDT", "side": "Buy", "positionIdx": 0, "orderType": "Limit", "qty": "0.001", "price": "10000", "timeInForce": "GTC"} orderResult, err := client.NewTradeService(params).PlaceOrder(context.Background()) if err != nil { diff --git a/examples/account/transaction_log.go b/examples/account/transaction_log.go index b36271c..6fcc8ed 100644 --- a/examples/account/transaction_log.go +++ b/examples/account/transaction_log.go @@ -11,7 +11,7 @@ func main() { } func PlaceTrade() { - client := bybit.NewBybitHttpClient("8wYkmpLsMg10eNQyPm", "Ouxc34myDnXvei54XsBZgoQzfGxO4bkr2Zsj", bybit.WithBaseURL(bybit.TESTNET)) + client := bybit.NewBybitHttpClient("YOUR_API_KEY", "YOUR_API_SECRET", bybit.WithBaseURL(bybit.TESTNET)) params := map[string]interface{}{"accountType": "UNIFIED", "category": "linear"} accountResult, err := client.NewAccountService(params).GetTransactionLog(context.Background()) if err != nil { diff --git a/examples/app.go b/examples/app.go deleted file mode 100644 index c048119..0000000 --- a/examples/app.go +++ /dev/null @@ -1,7 +0,0 @@ -package main - -import "fmt" - -func main() { - fmt.Println("hello world") -} diff --git a/examples/asset/asset_exchange_records.go b/examples/asset/asset_exchange_records.go index b11f339..e04910b 100644 --- a/examples/asset/asset_exchange_records.go +++ b/examples/asset/asset_exchange_records.go @@ -11,7 +11,7 @@ func main() { } func AssetInfo() { - client := bybit.NewBybitHttpClient("8wYkmpLsMg10eNQyPm", "Ouxc34myDnXvei54XsBZgoQzfGxO4bkr2Zsj", bybit.WithBaseURL(bybit.TESTNET)) + client := bybit.NewBybitHttpClient("YOUR_API_KEY", "YOUR_API_SECRET", bybit.WithBaseURL(bybit.TESTNET)) params := map[string]interface{}{"accountType": "spot"} assetResult, err := client.NewAssetService(params).GetAssetInfo(context.Background()) if err != nil { diff --git a/examples/asset/coin_info.go b/examples/asset/coin_info.go index 2875c42..fb8259d 100644 --- a/examples/asset/coin_info.go +++ b/examples/asset/coin_info.go @@ -11,7 +11,7 @@ func main() { } func GetCoinInfo() { - client := bybit.NewBybitHttpClient("8wYkmpLsMg10eNQyPm", "Ouxc34myDnXvei54XsBZgoQzfGxO4bkr2Zsj", bybit.WithBaseURL(bybit.TESTNET)) + client := bybit.NewBybitHttpClient("YOUR_API_KEY", "YOUR_API_SECRET", bybit.WithBaseURL(bybit.TESTNET)) params := map[string]interface{}{"coin": "USDT"} assetResult, err := client.NewAssetService(params).GetCoinInfo(context.Background()) if err != nil { diff --git a/examples/broker/broker_earn.go b/examples/broker/broker_earn.go index 3808e4c..f90661c 100644 --- a/examples/broker/broker_earn.go +++ b/examples/broker/broker_earn.go @@ -11,7 +11,7 @@ func main() { } func PlaceTrade() { - client := bybit.NewBybitHttpClient("8wYkmpLsMg10eNQyPm", "Ouxc34myDnXvei54XsBZgoQzfGxO4bkr2Zsj", bybit.WithBaseURL(bybit.TESTNET)) + client := bybit.NewBybitHttpClient("YOUR_API_KEY", "YOUR_API_SECRET", bybit.WithBaseURL(bybit.TESTNET)) params := map[string]interface{}{} orderResult, err := client.NewBrokerService(params).GetBrokerEarning(context.Background()) if err != nil { diff --git a/examples/lending/lending_coin.go b/examples/lending/lending_coin.go index 7503d86..ce4a23e 100644 --- a/examples/lending/lending_coin.go +++ b/examples/lending/lending_coin.go @@ -11,7 +11,7 @@ func main() { } func PlaceTrade() { - client := bybit.NewBybitHttpClient("8wYkmpLsMg10eNQyPm", "Ouxc34myDnXvei54XsBZgoQzfGxO4bkr2Zsj", bybit.WithBaseURL(bybit.TESTNET)) + client := bybit.NewBybitHttpClient("YOUR_API_KEY", "YOUR_API_SECRET", bybit.WithBaseURL(bybit.TESTNET)) params := map[string]interface{}{"coin": "USDT"} orderResult, err := client.NewLendingService(params).GetC2cLendingCoinInfo(context.Background()) if err != nil { diff --git a/examples/position/position_list.go b/examples/position/position_list.go index e3f1dc5..965dd9d 100644 --- a/examples/position/position_list.go +++ b/examples/position/position_list.go @@ -11,7 +11,7 @@ func main() { } func PlaceTrade() { - client := bybit.NewBybitHttpClient("8wYkmpLsMg10eNQyPm", "Ouxc34myDnXvei54XsBZgoQzfGxO4bkr2Zsj", bybit.WithBaseURL(bybit.TESTNET)) + client := bybit.NewBybitHttpClient("YOUR_API_KEY", "YOUR_API_SECRET", bybit.WithBaseURL(bybit.TESTNET)) params := map[string]interface{}{"category": "linear", "settleCoin": "USDT", "limit": 10} orderResult, err := client.NewPositionService(params).GetPositionList(context.Background()) if err != nil { diff --git a/examples/position/position_mode.go b/examples/position/position_mode.go index 26bfe7a..c7fec8b 100644 --- a/examples/position/position_mode.go +++ b/examples/position/position_mode.go @@ -11,7 +11,7 @@ func main() { } func SwitchPositionMode() { - client := bybit.NewBybitHttpClient("8wYkmpLsMg10eNQyPm", "Ouxc34myDnXvei54XsBZgoQzfGxO4bkr2Zsj", bybit.WithBaseURL(bybit.TESTNET)) + client := bybit.NewBybitHttpClient("YOUR_API_KEY", "YOUR_API_SECRET", bybit.WithBaseURL(bybit.TESTNET)) params := map[string]interface{}{"category": "linear", "coin": "USDT", "mode": 3} orderResult, err := client.NewPositionService(params).SwitchPositionMode(context.Background()) if err != nil { diff --git a/examples/pre_uprgade/order_history.go b/examples/pre_uprgade/order_history.go index 1903598..17fed11 100644 --- a/examples/pre_uprgade/order_history.go +++ b/examples/pre_uprgade/order_history.go @@ -11,7 +11,7 @@ func main() { } func PlaceTrade() { - client := bybit.NewBybitHttpClient("8wYkmpLsMg10eNQyPm", "Ouxc34myDnXvei54XsBZgoQzfGxO4bkr2Zsj", bybit.WithBaseURL(bybit.TESTNET)) + client := bybit.NewBybitHttpClient("YOUR_API_KEY", "YOUR_API_SECRET", bybit.WithBaseURL(bybit.TESTNET)) params := map[string]interface{}{"category": "linear", "settleCoin": "USDT", "limit": 10} orderResult, err := client.NewPreUpgradeService(params).GetPreUpgradeOrderHistory(context.Background()) if err != nil { diff --git a/examples/spot_leverage/spot_leverage_token.go b/examples/spot_leverage/spot_leverage_token.go index 430af96..67e1873 100644 --- a/examples/spot_leverage/spot_leverage_token.go +++ b/examples/spot_leverage/spot_leverage_token.go @@ -11,7 +11,7 @@ func main() { } func PlaceTrade() { - client := bybit.NewBybitHttpClient("8wYkmpLsMg10eNQyPm", "Ouxc34myDnXvei54XsBZgoQzfGxO4bkr2Zsj", bybit.WithBaseURL(bybit.TESTNET)) + client := bybit.NewBybitHttpClient("YOUR_API_KEY", "YOUR_API_SECRET", bybit.WithBaseURL(bybit.TESTNET)) params := map[string]interface{}{"ltCoin": "BTC3L"} leverageTokenResult, err := client.NewSpotLeverageService(params).GetLeverageTokenInfo(context.Background()) if err != nil { diff --git a/examples/spot_margin/uta_margin_data.go b/examples/spot_margin/uta_margin_data.go index 0a63a14..aee1583 100644 --- a/examples/spot_margin/uta_margin_data.go +++ b/examples/spot_margin/uta_margin_data.go @@ -11,7 +11,7 @@ func main() { } func SpotMarginData() { - client := bybit.NewBybitHttpClient("8wYkmpLsMg10eNQyPm", "Ouxc34myDnXvei54XsBZgoQzfGxO4bkr2Zsj", bybit.WithBaseURL(bybit.TESTNET)) + client := bybit.NewBybitHttpClient("YOUR_API_KEY", "YOUR_API_SECRET", bybit.WithBaseURL(bybit.TESTNET)) params := map[string]interface{}{"ltCoin": "BTC3L"} leverageTokenResult, err := client.NewSpotMarginDataService(params, true).GetSpotMarginData(context.Background()) if err != nil { diff --git a/examples/user/create_sub_user.go b/examples/user/create_sub_user.go index a408f0c..de65bdc 100644 --- a/examples/user/create_sub_user.go +++ b/examples/user/create_sub_user.go @@ -11,8 +11,8 @@ func main() { } func PlaceTrade() { - client := bybit.NewBybitHttpClient("8wYkmpLsMg10eNQyPm", "Ouxc34myDnXvei54XsBZgoQzfGxO4bkr2Zsj", bybit.WithBaseURL(bybit.TESTNET)) - params := map[string]interface{}{"username": "wuhe06112023Vic", "memberType": 1} + client := bybit.NewBybitHttpClient("YOUR_API_KEY", "YOUR_API_SECRET", bybit.WithBaseURL(bybit.TESTNET)) + params := map[string]interface{}{"username": "06112023Victor", "memberType": 1} userResult, err := client.NewUserService(params).CreateSubMember(context.Background()) if err != nil { fmt.Println(err) diff --git a/examples/websocket/private_ws.go b/examples/websocket/private_ws.go index fe00528..686e977 100644 --- a/examples/websocket/private_ws.go +++ b/examples/websocket/private_ws.go @@ -6,11 +6,10 @@ import ( ) func main() { - ws := bybit.NewBybitPrivateWebSocket("wss://stream-testnet.bybit.com/v5/private", "8wYkmpLsMg10eNQyPm", "Ouxc34myDnXvei54XsBZgoQzfGxO4bkr2Zsj", func(message string) error { + ws := bybit.NewBybitPrivateWebSocket("wss://stream-testnet.bybit.com/v5/private", "YOUR_API_KEY", "YOUR_API_SECRET", func(message string) error { fmt.Println("Received:", message) return nil }) - // Connect and subscribe to the desired topic _ = ws.Connect([]string{"order"}) select {} } diff --git a/examples/websocket/public_ws.go b/examples/websocket/public_ws.go index 4524bd5..0a364fa 100644 --- a/examples/websocket/public_ws.go +++ b/examples/websocket/public_ws.go @@ -6,12 +6,10 @@ import ( ) func main() { - // Create a public WebSocket client ws := bybit.NewBybitPublicWebSocket("wss://stream.bybit.com/v5/public/spot", func(message string) error { fmt.Println("Received:", message) return nil }) - // Connect and subscribe to the desired topic _ = ws.Connect([]string{"orderbook.1.BTCUSDT"}) select {} } diff --git a/go.mod b/go.mod index 653178b..ad7ec08 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,15 @@ module github.com/wuhewuhe/bybit.go.api go 1.21 require ( - github.com/bitly/go-simplejson v0.5.1 github.com/google/uuid v1.4.0 - github.com/gorilla/websocket v1.5.0 + github.com/gorilla/websocket v1.5.1 + github.com/stretchr/testify v1.8.4 +) + +require ( + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/stretchr/objx v0.5.1 // indirect + golang.org/x/net v0.17.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index b2f3d68..bf037ec 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,30 @@ -github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngEKAMDJEczWVA= github.com/bitly/go-simplejson v0.5.1/go.mod h1:YOPVLzCfwK14b4Sff3oP1AmGhI9T9Vsg84etUnlyp+Q= -github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4= github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY= +github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.1 h1:4VhoImhV/Bm0ToFkXFi8hXNXwpDRZ/ynw3amt82mzq0= +github.com/stretchr/objx v0.5.1/go.mod h1:/iHQpkQwBD6DLUmQ4pE+s1TXdob1mORJ4/UFdrifcy0= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= +golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/market_test.go b/market_test.go new file mode 100644 index 0000000..bc3f0f4 --- /dev/null +++ b/market_test.go @@ -0,0 +1,69 @@ +package bybit_connector + +import ( + "github.com/stretchr/testify/suite" + "github.com/wuhewuhe/bybit.go.api/models" + "testing" +) + +type marketTestSuite struct { + baseTestSuite +} + +func TestMarket(t *testing.T) { + suite.Run(t, new(marketTestSuite)) +} + +func (s *marketTestSuite) TestServerTime() { + data := []byte(`{ + "retCode": 0, + "retMsg": "OK", + "result": { + "timeSecond": "1699287551", + "timeNano": "1699287551919622633" + }, + "retExtInfo": {}, + "time": 1699287551919 + }`) + s.mockDo(data, nil) + defer s.assertDo() + + s.assertReq(func(r *request) { + e := newRequest() + s.assertRequestEqual(e, r) + }) + + serverTime, err := s.client.NewMarketInfoServiceNoParams().GetServerTime(newContext()) + + e1 := &models.ServerTimeResult{ + TimeSecond: "1699287551", + TimeNano: "1699287551919622633", + } + s.r().NoError(err) + s.assertServerTimeEqual(e1, serverTime) +} + +func (s *marketTestSuite) assertServerTimeEqual(expected *models.ServerTimeResult, actual *ServerResponse) { + // Assert that the actual result is not nil and is a map + r := s.r() + actualResult, ok := actual.Result.(map[string]interface{}) + if !ok { + r.FailNow("Actual result is not a map", "Actual Result: %#v", actual.Result) + return + } + + // Cast the map to the expected struct type + var actualStruct models.ServerTimeResult + timeSecond, okSecond := actualResult["timeSecond"].(string) + timeNano, okNano := actualResult["timeNano"].(string) + if !okSecond || !okNano { + r.FailNow("Failed to cast actual result fields to string", "Actual Result: %#v", actual.Result) + return + } + actualStruct.TimeSecond = timeSecond + actualStruct.TimeNano = timeNano + + // Compare the fields + r.Equal(expected.TimeSecond, actualStruct.TimeSecond, "TimeSecond field is not equal") + r.Equal(expected.TimeNano, actualStruct.TimeNano, "TimeNano field is not equal") +}