From 4108f191104dc1bdf679a7808aa9f7e54e589c2a Mon Sep 17 00:00:00 2001 From: JJ-Cro Date: Thu, 22 May 2025 10:24:07 +0200 Subject: [PATCH 1/3] feat(): added wsapiclient examples, updated endpoint map, updated links to point to bybit --- docs/endpointFunctionList.md | 18 +++- examples/ws-api-client.ts | 154 +++++++++++++++++++++++++++++++++++ examples/ws-api-events.ts | 3 +- src/websocket-api-client.ts | 2 +- 4 files changed, 174 insertions(+), 3 deletions(-) create mode 100644 examples/ws-api-client.ts diff --git a/docs/endpointFunctionList.md b/docs/endpointFunctionList.md index f3a7c44..60e7f2e 100644 --- a/docs/endpointFunctionList.md +++ b/docs/endpointFunctionList.md @@ -20,6 +20,7 @@ All REST clients are in the [src](/src) folder. For usage examples, make sure to List of clients: - [rest-client-v5](#rest-client-v5ts) +- [websocket-api-client](#websocket-api-clientts) If anything is missing or wrong, please open an issue or let us know in our [Node.js Traders](https://t.me/nodetraders) telegram group! @@ -241,4 +242,19 @@ This table includes all endpoints from the official Exchange API docs and corres | [getP2POrderMessages()](https://github.com/tiagosiebler/bybit-api/blob/master/src/rest-client-v5.ts#L3013) | :closed_lock_with_key: | POST | `/v5/p2p/order/message/listpage` | | [getP2PUserInfo()](https://github.com/tiagosiebler/bybit-api/blob/master/src/rest-client-v5.ts#L3027) | :closed_lock_with_key: | POST | `/v5/p2p/user/personal/info` | | [getP2PCounterpartyUserInfo()](https://github.com/tiagosiebler/bybit-api/blob/master/src/rest-client-v5.ts#L3034) | :closed_lock_with_key: | POST | `/v5/p2p/user/order/personal/info` | -| [getP2PUserPayments()](https://github.com/tiagosiebler/bybit-api/blob/master/src/rest-client-v5.ts#L3043) | :closed_lock_with_key: | POST | `/v5/p2p/user/payment/list` | \ No newline at end of file +| [getP2PUserPayments()](https://github.com/tiagosiebler/bybit-api/blob/master/src/rest-client-v5.ts#L3043) | :closed_lock_with_key: | POST | `/v5/p2p/user/payment/list` | + +# websocket-api-client.ts + +This table includes all endpoints from the official Exchange API docs and corresponding SDK functions for each endpoint that are found in [websocket-api-client.ts](/src/websocket-api-client.ts). + +This client provides WebSocket API endpoints which allow for faster interactions with the Bybit API via a WebSocket connection. + +| Function | AUTH | HTTP Method | Endpoint | +| -------- | :------: | :------: | -------- | +| [submitNewOrder()](https://github.com/tiagosiebler/bybit-api/blob/master/src/websocket-api-client.ts#L95) | :closed_lock_with_key: | WS | `order.create` | +| [amendOrder()](https://github.com/tiagosiebler/bybit-api/blob/master/src/websocket-api-client.ts#L111) | :closed_lock_with_key: | WS | `order.amend` | +| [cancelOrder()](https://github.com/tiagosiebler/bybit-api/blob/master/src/websocket-api-client.ts#L127) | :closed_lock_with_key: | WS | `order.cancel` | +| [batchSubmitOrders()](https://github.com/tiagosiebler/bybit-api/blob/master/src/websocket-api-client.ts#L143) | :closed_lock_with_key: | WS | `order.create-batch` | +| [batchAmendOrder()](https://github.com/tiagosiebler/bybit-api/blob/master/src/websocket-api-client.ts#L171) | :closed_lock_with_key: | WS | `order.amend-batch` | +| [batchCancelOrder()](https://github.com/tiagosiebler/bybit-api/blob/master/src/websocket-api-client.ts#L199) | :closed_lock_with_key: | WS | `order.cancel-batch` | \ No newline at end of file diff --git a/examples/ws-api-client.ts b/examples/ws-api-client.ts new file mode 100644 index 0000000..6b5e1f3 --- /dev/null +++ b/examples/ws-api-client.ts @@ -0,0 +1,154 @@ +import { DefaultLogger, WebsocketAPIClient } from '../src'; + +// or +// import { DefaultLogger, WebsocketClient } from 'bybit-api'; + +const key = process.env.API_KEY_COM || '1j3PcP9EMjGPbjcjlC'; +const secret = + process.env.API_SECRET_COM || 'VlvBfQqMcGKX77XgYcMqZmOR7biwA9ZvaTwk'; + +async function main() { + // Optional + const logger = { + ...DefaultLogger, + // For a more detailed view of the WebsocketClient, enable the `trace` level by uncommenting the below line: + // trace: (...params) => console.log('trace', ...params), + }; + + const wsClient = new WebsocketAPIClient( + { + key: key, + secret: secret, + // testnet: true, // Whether to use the testnet environment: https://testnet.bybit.com/app/user/api-management + // demoTrading: false, // note: As of Jan 2025, demo trading does NOT support the WS API + }, + logger, // Optional: inject a custom logger + ); + + // To do: Check if this is how listeners are handled + + wsClient.getWSClient().on('update', (data) => { + console.log('raw message received ', JSON.stringify(data)); + }); + + wsClient.getWSClient().on('open', (data) => { + console.log('ws connected', data.wsKey); + }); + wsClient.getWSClient().on('reconnect', ({ wsKey }) => { + console.log('ws automatically reconnecting.... ', wsKey); + }); + wsClient.getWSClient().on('reconnected', (data) => { + console.log('ws has reconnected ', data?.wsKey); + }); + wsClient.getWSClient().on('authenticated', (data) => { + console.log('ws has authenticated ', data?.wsKey); + }); + + // Optional, if you see RECV Window errors, you can use this to manage time issues. + // ! However, make sure you sync your system clock first! + // https://github.com/tiagosiebler/awesome-crypto-examples/wiki/Timestamp-for-this-request-is-outside-of-the-recvWindow + // wsClient.setTimeOffsetMs(-5000); + + try { + const response = await wsClient.submitNewOrder({ + category: 'linear', + symbol: 'BTCUSDT', + orderType: 'Limit', + qty: '0.001', + side: 'Buy', + price: '50000', + }); + console.log('submitNewOrder response: ', response); + } catch (e) { + console.log('submitNewOrder error: ', e); + } + + try { + const response = await wsClient.amendOrder({ + category: 'linear', + symbol: 'BTCUSDT', + orderId: 'b4b9e205-793c-4777-8112-0bf3c2d26b6e', + qty: '0.001', + price: '60000', + }); + console.log('amendOrder response: ', response); + } catch (e) { + console.log('amendOrder error: ', e); + } + + try { + const response = await wsClient.cancelOrder({ + category: 'linear', + symbol: 'BTCUSDT', + orderId: 'b4b9e205-793c-4777-8112-0bf3c2d26b6e', + }); + console.log('cancelOrder response: ', response); + } catch (e) { + console.log('cancelOrder error: ', e); + } + + try { + const response = await wsClient.batchSubmitOrders('linear', [ + { + symbol: 'BTCUSDT', + orderType: 'Limit', + qty: '0.001', + side: 'Buy', + price: '50000', + }, + { + symbol: 'BTCUSDT', + orderType: 'Limit', + qty: '0.001', + side: 'Buy', + price: '60000', + }, + { + symbol: 'BTCUSDT', + orderType: 'Limit', + qty: '0.001', + side: 'Buy', + price: '70000', + }, + ]); + console.log('batchSubmitOrders response: ', response); + } catch (e) { + console.log('batchSubmitOrders error: ', e); + } + + try { + const response = await wsClient.batchAmendOrder('linear', [ + { + symbol: 'BTCUSDT', + orderId: '2473ee58', + price: '80000', + }, + { + symbol: 'BTCUSDT', + orderId: 'b4b9e205-793c-4777-8112-0bf3c2d26b6e', + price: '80000', + }, + ]); + console.log('batchAmendOrder response: ', response); + } catch (e) { + console.log('batchAmendOrder error: ', e); + } + + try { + const response = await wsClient.batchCancelOrder('linear', [ + { + symbol: 'BTCUSDT', + orderId: '2473ee58', + }, + { + symbol: 'BTCUSDT', + orderId: 'b4b9e205-793c-4777-8112-0bf3c2d26b6e', + }, + ]); + console.log('batchCancelOrder response: ', response); + } catch (e) { + console.log('batchCancelOrder error: ', e); + } +} + +main(); diff --git a/examples/ws-api-events.ts b/examples/ws-api-events.ts index ce47005..99aa670 100644 --- a/examples/ws-api-events.ts +++ b/examples/ws-api-events.ts @@ -55,7 +55,8 @@ async function main() { * - Handle any exceptions in a catch block. * * This is a more "raw" workflow in how WebSockets behave. For a more convenient & REST-like approach, using the - * promise-driven interface is recommended. See the `ws-api-promises.ts` example for a demonstration you can compare. + * promise-driven interface is recommended. See the `ws-api-promises.ts` and `ws-api-client.ts` examples for a + * demonstration you can compare. * * Note: even without using promises, you should still tie on a .catch handler to each sendWSAPIRequest call, to prevent * any unnecessary "unhandled promise rejection" exceptions. diff --git a/src/websocket-api-client.ts b/src/websocket-api-client.ts index d08037a..d1ec80d 100644 --- a/src/websocket-api-client.ts +++ b/src/websocket-api-client.ts @@ -47,7 +47,7 @@ export interface WSAPIClientConfigurableOptions { * may find the below methods slightly more intuitive. * * Refer to the WS API promises example for a more detailed example on using sendWSAPIRequest() directly: - * https://github.com/tiagosiebler/binance/blob/master/examples/WebSockets/ws-api-raw-promises.ts#L108 + * https://github.com/tiagosiebler/bybit-api/blob/master/examples/ws-api-client.ts#L58 */ export class WebsocketAPIClient { private wsClient: WebsocketClient; From 599616651d9f085ae6327dd0ff4adee39f4cdf2e Mon Sep 17 00:00:00 2001 From: JJ-Cro Date: Thu, 22 May 2025 11:03:56 +0200 Subject: [PATCH 2/3] chore(): cleanup --- examples/ws-api-client.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/examples/ws-api-client.ts b/examples/ws-api-client.ts index 6b5e1f3..b6c595c 100644 --- a/examples/ws-api-client.ts +++ b/examples/ws-api-client.ts @@ -3,9 +3,8 @@ import { DefaultLogger, WebsocketAPIClient } from '../src'; // or // import { DefaultLogger, WebsocketClient } from 'bybit-api'; -const key = process.env.API_KEY_COM || '1j3PcP9EMjGPbjcjlC'; -const secret = - process.env.API_SECRET_COM || 'VlvBfQqMcGKX77XgYcMqZmOR7biwA9ZvaTwk'; +const key = process.env.API_KEY_COM; +const secret = process.env.API_SECRET_COM; async function main() { // Optional From 9f9732a035d9e7c0dc941ac32115cc300d80dd8f Mon Sep 17 00:00:00 2001 From: JJ-Cro Date: Thu, 22 May 2025 11:10:15 +0200 Subject: [PATCH 3/3] feat(): add example event handlers for WebsocketAPIClient and clean up listener code --- examples/ws-api-client.ts | 48 ++++++++++++++++++++++----------------- 1 file changed, 27 insertions(+), 21 deletions(-) diff --git a/examples/ws-api-client.ts b/examples/ws-api-client.ts index b6c595c..dec15e2 100644 --- a/examples/ws-api-client.ts +++ b/examples/ws-api-client.ts @@ -1,31 +1,14 @@ import { DefaultLogger, WebsocketAPIClient } from '../src'; // or -// import { DefaultLogger, WebsocketClient } from 'bybit-api'; +// import { DefaultLogger, WebsocketAPIClient } from 'bybit-api'; const key = process.env.API_KEY_COM; const secret = process.env.API_SECRET_COM; -async function main() { - // Optional - const logger = { - ...DefaultLogger, - // For a more detailed view of the WebsocketClient, enable the `trace` level by uncommenting the below line: - // trace: (...params) => console.log('trace', ...params), - }; - - const wsClient = new WebsocketAPIClient( - { - key: key, - secret: secret, - // testnet: true, // Whether to use the testnet environment: https://testnet.bybit.com/app/user/api-management - // demoTrading: false, // note: As of Jan 2025, demo trading does NOT support the WS API - }, - logger, // Optional: inject a custom logger - ); - - // To do: Check if this is how listeners are handled - +/* function attachEventHandlers( + wsClient: TWSClient, +): void { wsClient.getWSClient().on('update', (data) => { console.log('raw message received ', JSON.stringify(data)); }); @@ -42,6 +25,29 @@ async function main() { wsClient.getWSClient().on('authenticated', (data) => { console.log('ws has authenticated ', data?.wsKey); }); +} */ + +async function main() { + // Optional + const logger = { + ...DefaultLogger, + // For a more detailed view of the WebsocketClient, enable the `trace` level by uncommenting the below line: + // trace: (...params) => console.log('trace', ...params), + }; + + const wsClient = new WebsocketAPIClient( + { + key: key, + secret: secret, + // testnet: true, // Whether to use the testnet environment: https://testnet.bybit.com/app/user/api-management + // demoTrading: false, // note: As of Jan 2025, demo trading does NOT support the WS API + + // If you want your own event handlers instead of the default ones with logs, + // disable this setting and see the `attachEventHandlers` example below: + // attachEventListeners: false + }, + logger, // Optional: inject a custom logger + ); // Optional, if you see RECV Window errors, you can use this to manage time issues. // ! However, make sure you sync your system clock first!