diff --git a/examples/ws-private-v5.ts b/examples/ws-private-v5.ts new file mode 100644 index 0000000..fdf140d --- /dev/null +++ b/examples/ws-private-v5.ts @@ -0,0 +1,103 @@ +/* eslint-disable @typescript-eslint/no-empty-function */ +import { DefaultLogger, WS_KEY_MAP, WebsocketClient } from '../src'; + +// or +// import { DefaultLogger, WS_KEY_MAP, WebsocketClient } from 'bybit-api'; + +// Create & inject a custom logger to disable the silly logging level (empty function) +const logger = { + ...DefaultLogger, + silly: () => {}, +}; + +const key = process.env.API_KEY; +const secret = process.env.API_SECRET; + +/** + * Prepare an instance of the WebSocket client. This client handles all aspects of connectivity for you: + * - Connections are opened when you subscribe to topics + * - If key & secret are provided, authentication is handled automatically + * - If you subscribe to topics from different v5 products (e.g. spot and linear perps), + * subscription events are automatically routed to the different ws endpoints on bybit's side + * - Heartbeats/ping/pong/reconnects are all handled automatically. + * If a connection drops, the client will clean it up, respawn a fresh connection and resubscribe for you. + */ +const wsClient = new WebsocketClient( + { + key: key, + secret: secret, + market: 'v5', + testnet: true, + }, + logger +); + +wsClient.on('update', (data) => { + console.log('raw message received ', JSON.stringify(data)); + // console.log('raw message received ', JSON.stringify(data, null, 2)); +}); + +wsClient.on('open', (data) => { + console.log('connection opened open:', data.wsKey); +}); +wsClient.on('response', (data) => { + console.log('log response: ', JSON.stringify(data, null, 2)); +}); +wsClient.on('reconnect', ({ wsKey }) => { + console.log('ws automatically reconnecting.... ', wsKey); +}); +wsClient.on('reconnected', (data) => { + console.log('ws has reconnected ', data?.wsKey); +}); +// wsClient.on('error', (data) => { +// console.error('ws exception: ', data); +// }); + +/** + * For private V5 topics, us the subscribeV5() method on the ws client or use the original subscribe() method. + * + * Note: for private endpoints the "category" field is ignored since there is only one private endpoint + * (compared to one public one per category). + * The "category" is only needed for public topics since bybit has one endpoint for public events per category. + */ + +wsClient.subscribeV5('position', 'linear'); +wsClient.subscribeV5('execution', 'linear'); +wsClient.subscribeV5(['order', 'wallet', 'greek'], 'linear'); + +/** + * The following has the same effect as above, since there's only one private endpoint for V5 account topics: + */ +// wsClient.subscribe('position'); +// wsClient.subscribe('execution'); +// wsClient.subscribe(['order', 'wallet', 'greek']); + +// To unsubscribe from topics (after a 5 second delay, in this example): +// setTimeout(() => { +// console.log('unsubscribing'); +// wsClient.unsubscribeV5('execution', 'linear'); +// }, 5 * 1000); + +// Topics are tracked per websocket type +// Get a list of subscribed topics (e.g. for public v3 spot topics) (after a 5 second delay) +setTimeout(() => { + const activePrivateTopics = wsClient + .getWsStore() + .getTopics(WS_KEY_MAP.v5Private); + console.log('Active private v5 topics: ', activePrivateTopics); + + const activePublicLinearTopics = wsClient + .getWsStore() + .getTopics(WS_KEY_MAP.v5LinearPublic); + console.log('Active public linear v5 topics: ', activePublicLinearTopics); + + const activePublicSpotTopis = wsClient + .getWsStore() + .getTopics(WS_KEY_MAP.v5SpotPublic); + console.log('Active public spot v5 topics: ', activePublicSpotTopis); + + const activePublicOptionsTopics = wsClient + .getWsStore() + .getTopics(WS_KEY_MAP.v5OptionPublic); + console.log('Active public option v5 topics: ', activePublicOptionsTopics); +}, 5 * 1000); diff --git a/examples/ws-private.ts b/examples/ws-private.ts index 62839e4..debc15b 100644 --- a/examples/ws-private.ts +++ b/examples/ws-private.ts @@ -6,67 +6,65 @@ import { DefaultLogger, WS_KEY_MAP, WebsocketClient } from '../src'; // or // import { DefaultLogger, WS_KEY_MAP, WebsocketClient } from 'bybit-api'; -(async () => { - const logger = { - ...DefaultLogger, - silly: () => {}, - }; +const logger = { + ...DefaultLogger, + silly: () => {}, +}; - const key = process.env.API_KEY; - const secret = process.env.API_SECRET; +const key = process.env.API_KEY; +const secret = process.env.API_SECRET; - // USDT Perps: - // const market = 'linear'; - // Inverse Perp - // const market = 'inverse'; - // const market = 'spotv3'; - // Contract v3 - const market = 'contractUSDT'; - // const market = 'contractInverse'; +// USDT Perps: +// const market = 'linear'; +// Inverse Perp +// const market = 'inverse'; +// const market = 'spotv3'; +// Contract v3 +const market = 'contractUSDT'; +// const market = 'contractInverse'; - // Note: the WebsocketClient defaults to testnet. Set `livenet: true` to use live markets. - const wsClient = new WebsocketClient( - { - key: key, - secret: secret, - market: market, - // testnet: true, - restOptions: { - // enable_time_sync: true, - }, +// Note: the WebsocketClient defaults to testnet. Set `livenet: true` to use live markets. +const wsClient = new WebsocketClient( + { + key: key, + secret: secret, + market: market, + // testnet: true, + restOptions: { + // enable_time_sync: true, }, - logger - ); + }, + logger +); - wsClient.on('update', (data) => { - console.log('raw message received ', JSON.stringify(data, null, 2)); - }); +wsClient.on('update', (data) => { + console.log('raw message received ', JSON.stringify(data, null, 2)); +}); - wsClient.on('open', (data) => { - console.log('connection opened open:', data.wsKey); - }); - wsClient.on('response', (data) => { - console.log('ws response: ', JSON.stringify(data, null, 2)); - }); - wsClient.on('reconnect', ({ wsKey }) => { - console.log('ws automatically reconnecting.... ', wsKey); - }); - wsClient.on('reconnected', (data) => { - console.log('ws has reconnected ', data?.wsKey); - }); - wsClient.on('error', (data) => { - console.error('ws exception: ', data); - }); +wsClient.on('open', (data) => { + console.log('connection opened open:', data.wsKey); +}); +wsClient.on('response', (data) => { + console.log('ws response: ', JSON.stringify(data, null, 2)); +}); +wsClient.on('reconnect', ({ wsKey }) => { + console.log('ws automatically reconnecting.... ', wsKey); +}); +wsClient.on('reconnected', (data) => { + console.log('ws has reconnected ', data?.wsKey); +}); +wsClient.on('error', (data) => { + console.error('ws exception: ', data); +}); - // subscribe to private endpoints - // check the api docs in your api category to see the available topics - // wsClient.subscribe(['position', 'execution', 'order', 'wallet']); +// subscribe to private endpoints +// check the api docs in your api category to see the available topics +// wsClient.subscribe(['position', 'execution', 'order', 'wallet']); - // Contract v3 - wsClient.subscribe([ - 'user.position.contractAccount', - 'user.execution.contractAccount', - 'user.order.contractAccount', - 'user.wallet.contractAccount', - ]); -})(); +// Contract v3 +wsClient.subscribe([ + 'user.position.contractAccount', + 'user.execution.contractAccount', + 'user.order.contractAccount', + 'user.wallet.contractAccount', +]); diff --git a/examples/ws-public-v5.ts b/examples/ws-public-v5.ts new file mode 100644 index 0000000..2c7f854 --- /dev/null +++ b/examples/ws-public-v5.ts @@ -0,0 +1,116 @@ +import { DefaultLogger, WS_KEY_MAP, WebsocketClient } from '../src'; + +// or +// import { DefaultLogger, WS_KEY_MAP, WebsocketClient } from 'bybit-api'; + +const logger = { + ...DefaultLogger, + silly: (...params) => console.log('silly', ...params), +}; + +/** + * Prepare an instance of the WebSocket client. This client handles all aspects of connectivity for you: + * - Connections are opened when you subscribe to topics + * - If key & secret are provided, authentication is handled automatically + * - If you subscribe to topics from different v5 products (e.g. spot and linear perps), + * subscription events are automatically routed to the different ws endpoints on bybit's side + * - Heartbeats/ping/pong/reconnects are all handled automatically. + * If a connection drops, the client will clean it up, respawn a fresh connection and resubscribe for you. + */ +const wsClient = new WebsocketClient( + { + // key: key, + // secret: secret, + market: 'v5', + }, + logger +); + +wsClient.on('update', (data) => { + console.log('raw message received ', JSON.stringify(data)); + // console.log('raw message received ', JSON.stringify(data, null, 2)); +}); + +wsClient.on('open', (data) => { + console.log('connection opened open:', data.wsKey); +}); +wsClient.on('response', (data) => { + console.log('log response: ', JSON.stringify(data, null, 2)); +}); +wsClient.on('reconnect', ({ wsKey }) => { + console.log('ws automatically reconnecting.... ', wsKey); +}); +wsClient.on('reconnected', (data) => { + console.log('ws has reconnected ', data?.wsKey); +}); +// wsClient.on('error', (data) => { +// console.error('ws exception: ', data); +// }); + +/** + * For public V5 topics, use the subscribeV5 method and include the API category this topic is for. + * Category is required, since each category has a different websocket endpoint. + */ + +// Linear v5 +// -> Just one topic per call +// wsClient.subscribeV5('orderbook.50.BTCUSDT', 'linear'); + +// -> Or multiple topics in one call +// wsClient.subscribeV5( +// ['orderbook.50.BTCUSDT', 'orderbook.50.ETHUSDT'], +// 'linear' +// ); + +// Inverse v5 +// wsClient.subscribeV5('orderbook.50.BTCUSD', 'inverse'); + +// Spot v5 +// wsClient.subscribeV5('orderbook.50.BTCUSDT', 'spot'); + +// Option v5 +// wsClient.subscribeV5('publicTrade.BTC', 'option'); + +/** + * For private V5 topics, just call the same subscribeV5() method on the ws client or use the original subscribe() method. + * + * Note: for private endpoints the "category" field is ignored since there is only one private endpoint + * (compared to one public one per category) + */ + +wsClient.subscribeV5('position', 'linear'); +wsClient.subscribeV5('execution', 'linear'); +wsClient.subscribeV5(['order', 'wallet', 'greek'], 'linear'); + +// Other example topics + +// To unsubscribe from topics (after a 5 second delay, in this example): +// setTimeout(() => { +// console.log('unsubscribing'); +// wsClient.unsubscribeV5('orderbook.50.BTCUSDT', 'linear); +// }, 5 * 1000); + +// Topics are tracked per websocket type +// Get a list of subscribed topics (e.g. for public v3 spot topics) (after a 5 second delay) +setTimeout(() => { + const activePrivateTopics = wsClient + .getWsStore() + .getTopics(WS_KEY_MAP.v5Private); + + console.log('Active private v5 topics: ', activePrivateTopics); + + const activePublicLinearTopics = wsClient + .getWsStore() + .getTopics(WS_KEY_MAP.v5LinearPublic); + console.log('Active public linear v5 topics: ', activePublicLinearTopics); + + const activePublicSpotTopis = wsClient + .getWsStore() + .getTopics(WS_KEY_MAP.v5SpotPublic); + console.log('Active public spot v5 topics: ', activePublicSpotTopis); + + const activePublicOptionsTopics = wsClient + .getWsStore() + .getTopics(WS_KEY_MAP.v5OptionPublic); + console.log('Active public option v5 topics: ', activePublicOptionsTopics); +}, 5 * 1000); diff --git a/examples/ws-public.ts b/examples/ws-public.ts index d156564..4670021 100644 --- a/examples/ws-public.ts +++ b/examples/ws-public.ts @@ -3,171 +3,169 @@ import { DefaultLogger, WS_KEY_MAP, WebsocketClient } from '../src'; // or // import { DefaultLogger, WS_KEY_MAP, WebsocketClient } from 'bybit-api'; -(async () => { - const logger = { - ...DefaultLogger, - silly: (...params) => console.log('silly', ...params), - }; +const logger = { + ...DefaultLogger, + silly: (...params) => console.log('silly', ...params), +}; - const wsClient = new WebsocketClient( - { - // key: key, - // secret: secret, - // market: 'linear', - // market: 'inverse', - // market: 'spot', - // market: 'spotv3', - // market: 'usdcOption', - market: 'usdcPerp', - // market: 'unifiedPerp', - // market: 'unifiedOption', - }, - logger - ); +const wsClient = new WebsocketClient( + { + // key: key, + // secret: secret, + // market: 'linear', + // market: 'inverse', + // market: 'spot', + // market: 'spotv3', + // market: 'usdcOption', + market: 'usdcPerp', + // market: 'unifiedPerp', + // market: 'unifiedOption', + }, + logger +); - wsClient.on('update', (data) => { - console.log('raw message received ', JSON.stringify(data)); - // console.log('raw message received ', JSON.stringify(data, null, 2)); - }); +wsClient.on('update', (data) => { + console.log('raw message received ', JSON.stringify(data)); + // console.log('raw message received ', JSON.stringify(data, null, 2)); +}); - wsClient.on('open', (data) => { - console.log('connection opened open:', data.wsKey); +wsClient.on('open', (data) => { + console.log('connection opened open:', data.wsKey); - // if (data.wsKey === WS_KEY_MAP.spotPublic) { - // // Spot public, but not recommended - use spotv3 client instead - // // The old spot websockets dont automatically resubscribe if they disconnect - // // wsClient.subscribePublicSpotTrades('BTCUSDT'); - // // wsClient.subscribePublicSpotTradingPair('BTCUSDT'); - // // wsClient.subscribePublicSpotV1Kline('BTCUSDT', '1m'); - // // wsClient.subscribePublicSpotOrderbook('BTCUSDT', 'full'); - // } - }); - wsClient.on('response', (data) => { - console.log('log response: ', JSON.stringify(data, null, 2)); - }); - wsClient.on('reconnect', ({ wsKey }) => { - console.log('ws automatically reconnecting.... ', wsKey); - }); - wsClient.on('reconnected', (data) => { - console.log('ws has reconnected ', data?.wsKey); - }); - // wsClient.on('error', (data) => { - // console.error('ws exception: ', data); - // }); + // if (data.wsKey === WS_KEY_MAP.spotPublic) { + // // Spot public, but not recommended - use spotv3 client instead + // // The old spot websockets dont automatically resubscribe if they disconnect + // // wsClient.subscribePublicSpotTrades('BTCUSDT'); + // // wsClient.subscribePublicSpotTradingPair('BTCUSDT'); + // // wsClient.subscribePublicSpotV1Kline('BTCUSDT', '1m'); + // // wsClient.subscribePublicSpotOrderbook('BTCUSDT', 'full'); + // } +}); +wsClient.on('response', (data) => { + console.log('log response: ', JSON.stringify(data, null, 2)); +}); +wsClient.on('reconnect', ({ wsKey }) => { + console.log('ws automatically reconnecting.... ', wsKey); +}); +wsClient.on('reconnected', (data) => { + console.log('ws has reconnected ', data?.wsKey); +}); +// wsClient.on('error', (data) => { +// console.error('ws exception: ', data); +// }); - // Inverse - // wsClient.subscribe('trade'); +// Inverse +// wsClient.subscribe('trade'); - // Linear - // wsClient.subscribe('trade.BTCUSDT'); +// Linear +// wsClient.subscribe('trade.BTCUSDT'); - // Spot V3 - // wsClient.subscribe('trade.BTCUSDT'); - // Or an array of topics - // wsClient.subscribe([ - // 'orderbook.40.BTCUSDT', - // 'orderbook.40.BTCUSDC', - // 'orderbook.40.USDCUSDT', - // 'orderbook.40.BTCDAI', - // 'orderbook.40.DAIUSDT', - // 'orderbook.40.ETHUSDT', - // 'orderbook.40.ETHUSDC', - // 'orderbook.40.ETHDAI', - // 'orderbook.40.XRPUSDT', - // 'orderbook.40.XRPUSDC', - // 'orderbook.40.EOSUSDT', - // 'orderbook.40.EOSUSDC', - // 'orderbook.40.DOTUSDT', - // 'orderbook.40.DOTUSDC', - // 'orderbook.40.XLMUSDT', - // 'orderbook.40.XLMUSDC', - // 'orderbook.40.LTCUSDT', - // 'orderbook.40.LTCUSDC', - // 'orderbook.40.DOGEUSDT', - // 'orderbook.40.DOGEUSDC', - // 'orderbook.40.BITUSDT', - // 'orderbook.40.BITUSDC', - // 'orderbook.40.BITDAI', - // 'orderbook.40.CHZUSDT', - // 'orderbook.40.CHZUSDC', - // 'orderbook.40.MANAUSDT', - // 'orderbook.40.MANAUSDC', - // 'orderbook.40.LINKUSDT', - // 'orderbook.40.LINKUSDC', - // 'orderbook.40.ICPUSDT', - // 'orderbook.40.ICPUSDC', - // 'orderbook.40.ADAUSDT', - // 'orderbook.40.ADAUSDC', - // 'orderbook.40.SOLUSDC', - // 'orderbook.40.SOLUSDT', - // 'orderbook.40.MATICUSDC', - // 'orderbook.40.MATICUSDT', - // 'orderbook.40.SANDUSDC', - // 'orderbook.40.SANDUSDT', - // 'orderbook.40.LUNCUSDC', - // 'orderbook.40.LUNCUSDT', - // 'orderbook.40.SLGUSDC', - // 'orderbook.40.SLGUSDT', - // 'orderbook.40.AVAXUSDC', - // 'orderbook.40.AVAXUSDT', - // 'orderbook.40.OPUSDC', - // 'orderbook.40.OPUSDT', - // 'orderbook.40.OKSEUSDC', - // 'orderbook.40.OKSEUSDT', - // 'orderbook.40.APEXUSDC', - // 'orderbook.40.APEXUSDT', - // 'orderbook.40.TRXUSDC', - // 'orderbook.40.TRXUSDT', - // 'orderbook.40.GMTUSDC', - // 'orderbook.40.GMTUSDT', - // 'orderbook.40.SHIBUSDC', - // 'orderbook.40.SHIBUSDT', - // 'orderbook.40.LDOUSDC', - // 'orderbook.40.LDOUSDT', - // 'orderbook.40.APEUSDC', - // 'orderbook.40.APEUSDT', - // 'orderbook.40.FILUSDC', - // 'orderbook.40.FILUSDT', - // ]); +// Spot V3 +// wsClient.subscribe('trade.BTCUSDT'); +// Or an array of topics +// wsClient.subscribe([ +// 'orderbook.40.BTCUSDT', +// 'orderbook.40.BTCUSDC', +// 'orderbook.40.USDCUSDT', +// 'orderbook.40.BTCDAI', +// 'orderbook.40.DAIUSDT', +// 'orderbook.40.ETHUSDT', +// 'orderbook.40.ETHUSDC', +// 'orderbook.40.ETHDAI', +// 'orderbook.40.XRPUSDT', +// 'orderbook.40.XRPUSDC', +// 'orderbook.40.EOSUSDT', +// 'orderbook.40.EOSUSDC', +// 'orderbook.40.DOTUSDT', +// 'orderbook.40.DOTUSDC', +// 'orderbook.40.XLMUSDT', +// 'orderbook.40.XLMUSDC', +// 'orderbook.40.LTCUSDT', +// 'orderbook.40.LTCUSDC', +// 'orderbook.40.DOGEUSDT', +// 'orderbook.40.DOGEUSDC', +// 'orderbook.40.BITUSDT', +// 'orderbook.40.BITUSDC', +// 'orderbook.40.BITDAI', +// 'orderbook.40.CHZUSDT', +// 'orderbook.40.CHZUSDC', +// 'orderbook.40.MANAUSDT', +// 'orderbook.40.MANAUSDC', +// 'orderbook.40.LINKUSDT', +// 'orderbook.40.LINKUSDC', +// 'orderbook.40.ICPUSDT', +// 'orderbook.40.ICPUSDC', +// 'orderbook.40.ADAUSDT', +// 'orderbook.40.ADAUSDC', +// 'orderbook.40.SOLUSDC', +// 'orderbook.40.SOLUSDT', +// 'orderbook.40.MATICUSDC', +// 'orderbook.40.MATICUSDT', +// 'orderbook.40.SANDUSDC', +// 'orderbook.40.SANDUSDT', +// 'orderbook.40.LUNCUSDC', +// 'orderbook.40.LUNCUSDT', +// 'orderbook.40.SLGUSDC', +// 'orderbook.40.SLGUSDT', +// 'orderbook.40.AVAXUSDC', +// 'orderbook.40.AVAXUSDT', +// 'orderbook.40.OPUSDC', +// 'orderbook.40.OPUSDT', +// 'orderbook.40.OKSEUSDC', +// 'orderbook.40.OKSEUSDT', +// 'orderbook.40.APEXUSDC', +// 'orderbook.40.APEXUSDT', +// 'orderbook.40.TRXUSDC', +// 'orderbook.40.TRXUSDT', +// 'orderbook.40.GMTUSDC', +// 'orderbook.40.GMTUSDT', +// 'orderbook.40.SHIBUSDC', +// 'orderbook.40.SHIBUSDT', +// 'orderbook.40.LDOUSDC', +// 'orderbook.40.LDOUSDT', +// 'orderbook.40.APEUSDC', +// 'orderbook.40.APEUSDT', +// 'orderbook.40.FILUSDC', +// 'orderbook.40.FILUSDT', +// ]); - // usdc options - // wsClient.subscribe([ - // `recenttrades.BTC`, - // `recenttrades.ETH`, - // `recenttrades.SOL`, - // ]); +// usdc options +// wsClient.subscribe([ +// `recenttrades.BTC`, +// `recenttrades.ETH`, +// `recenttrades.SOL`, +// ]); - // usdc perps (note: the syntax is different for the unified perp market) - // (market: 'usdcPerp') - // wsClient.subscribe('trade.BTCUSDC'); - wsClient.subscribe('instrument_info.100ms.BTCPERP'); +// usdc perps (note: the syntax is different for the unified perp market) +// (market: 'usdcPerp') +// wsClient.subscribe('trade.BTCUSDC'); +wsClient.subscribe('instrument_info.100ms.BTCPERP'); - // unified perps - // wsClient.subscribe('publicTrade.BTCUSDT'); - // wsClient.subscribe('publicTrade.BTCPERP'); +// unified perps +// wsClient.subscribe('publicTrade.BTCUSDT'); +// wsClient.subscribe('publicTrade.BTCPERP'); - // For spot v1 (the old, deprecated client), request public connection first then send required topics on 'open' - // Not necessary for spot v3 - // wsClient.connectPublic(); +// For spot v1 (the old, deprecated client), request public connection first then send required topics on 'open' +// Not necessary for spot v3 +// wsClient.connectPublic(); - // To unsubscribe from topics (after a 5 second delay, in this example): - // setTimeout(() => { - // console.log('unsubscribing'); - // wsClient.unsubscribe('trade.BTCUSDT'); - // }, 5 * 1000); +// To unsubscribe from topics (after a 5 second delay, in this example): +// setTimeout(() => { +// console.log('unsubscribing'); +// wsClient.unsubscribe('trade.BTCUSDT'); +// }, 5 * 1000); - // Topics are tracked per websocket type - // Get a list of subscribed topics (e.g. for public v3 spot topics) (after a 5 second delay) - setTimeout(() => { - const publicSpotTopics = wsClient - .getWsStore() - .getTopics(WS_KEY_MAP.spotV3Public); +// Topics are tracked per websocket type +// Get a list of subscribed topics (e.g. for public v3 spot topics) (after a 5 second delay) +setTimeout(() => { + const publicSpotTopics = wsClient + .getWsStore() + .getTopics(WS_KEY_MAP.spotV3Public); - console.log('public spot topics: ', publicSpotTopics); + console.log('public spot topics: ', publicSpotTopics); - const privateSpotTopics = wsClient - .getWsStore() - .getTopics(WS_KEY_MAP.spotV3Private); - console.log('private spot topics: ', privateSpotTopics); - }, 5 * 1000); -})(); + const privateSpotTopics = wsClient + .getWsStore() + .getTopics(WS_KEY_MAP.spotV3Private); + console.log('private spot topics: ', privateSpotTopics); +}, 5 * 1000);