UNPKG

bybit-api

Version:

Complete & robust Node.js SDK for Bybit's REST APIs and WebSockets, with TypeScript & strong end to end tests.

506 lines 18.8 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.safeTerminateWs = exports.neverGuard = exports.WS_ERROR_ENUM = exports.getUsdcWsKeyForTopic = exports.getMaxTopicsPerSubscribeEvent = exports.getWsUrl = exports.getWsKeyForTopic = exports.isPrivateWsTopic = exports.PUBLIC_WS_KEYS = exports.WS_AUTH_ON_CONNECT_KEYS = exports.WS_KEY_MAP = exports.WS_BASE_URL_MAP = void 0; exports.WS_BASE_URL_MAP = { inverse: { public: { livenet: 'wss://stream.bybit.com/realtime', testnet: 'wss://stream-testnet.bybit.com/realtime', }, private: { livenet: 'wss://stream.bybit.com/realtime', testnet: 'wss://stream-testnet.bybit.com/realtime', }, }, linear: { public: { livenet: 'wss://stream.bybit.com/realtime_public', livenet2: 'wss://stream.bytick.com/realtime_public', testnet: 'wss://stream-testnet.bybit.com/realtime_public', }, private: { livenet: 'wss://stream.bybit.com/realtime_private', livenet2: 'wss://stream.bytick.com/realtime_private', testnet: 'wss://stream-testnet.bybit.com/realtime_private', }, }, spot: { public: { livenet: 'wss://stream.bybit.com/spot/quote/ws/v1', livenet2: 'wss://stream.bybit.com/spot/quote/ws/v2', testnet: 'wss://stream-testnet.bybit.com/spot/quote/ws/v1', testnet2: 'wss://stream-testnet.bybit.com/spot/quote/ws/v2', }, private: { livenet: 'wss://stream.bybit.com/spot/ws', testnet: 'wss://stream-testnet.bybit.com/spot/ws', }, }, spotv3: { public: { livenet: 'wss://stream.bybit.com/spot/public/v3', testnet: 'wss://stream-testnet.bybit.com/spot/public/v3', }, private: { livenet: 'wss://stream.bybit.com/spot/private/v3', testnet: 'wss://stream-testnet.bybit.com/spot/private/v3', }, }, usdcOption: { public: { livenet: 'wss://stream.bybit.com/trade/option/usdc/public/v1', livenet2: 'wss://stream.bytick.com/trade/option/usdc/public/v1', testnet: 'wss://stream-testnet.bybit.com/trade/option/usdc/public/v1', }, private: { livenet: 'wss://stream.bybit.com/trade/option/usdc/private/v1', livenet2: 'wss://stream.bytick.com/trade/option/usdc/private/v1', testnet: 'wss://stream-testnet.bybit.com/trade/option/usdc/private/v1', }, }, usdcPerp: { public: { livenet: 'wss://stream.bybit.com/perpetual/ws/v1/realtime_public', livenet2: 'wss://stream.bytick.com/perpetual/ws/v1/realtime_public', testnet: 'wss://stream-testnet.bybit.com/perpetual/ws/v1/realtime_public', }, private: { livenet: 'wss://stream.bybit.com/trade/option/usdc/private/v1', livenet2: 'wss://stream.bytick.com/trade/option/usdc/private/v1', testnet: 'wss://stream-testnet.bybit.com/trade/option/usdc/private/v1', }, }, unifiedOption: { public: { livenet: 'wss://stream.bybit.com/option/usdc/public/v3', testnet: 'wss://stream-testnet.bybit.com/option/usdc/public/v3', }, private: { livenet: 'wss://stream.bybit.com/unified/private/v3', testnet: 'wss://stream-testnet.bybit.com/unified/private/v3', }, }, unifiedPerp: { public: { livenet: 'useBaseSpecificEndpoint', testnet: 'useBaseSpecificEndpoint', }, private: { livenet: 'wss://stream.bybit.com/unified/private/v3', testnet: 'wss://stream-testnet.bybit.com/unified/private/v3', }, }, unifiedPerpUSDT: { public: { livenet: 'wss://stream.bybit.com/contract/usdt/public/v3', testnet: 'wss://stream-testnet.bybit.com/contract/usdt/public/v3', }, }, unifiedPerpUSDC: { public: { livenet: 'wss://stream.bybit.com/contract/usdc/public/v3', testnet: 'wss://stream-testnet.bybit.com/contract/usdc/public/v3', }, }, contractUSDT: { public: { livenet: 'wss://stream.bybit.com/contract/usdt/public/v3', testnet: 'wss://stream-testnet.bybit.com/contract/usdt/public/v3', }, private: { livenet: 'wss://stream.bybit.com/contract/private/v3', testnet: 'wss://stream-testnet.bybit.com/contract/private/v3', }, }, contractInverse: { public: { livenet: 'wss://stream.bybit.com/contract/inverse/public/v3', testnet: 'wss://stream-testnet.bybit.com/contract/inverse/public/v3', }, private: { livenet: 'wss://stream.bybit.com/contract/private/v3', testnet: 'wss://stream-testnet.bybit.com/contract/private/v3', }, }, v5: { public: { livenet: 'public topics are routed internally via the public wskeys', testnet: 'public topics are routed internally via the public wskeys', }, private: { livenet: 'wss://stream.bybit.com/v5/private', testnet: 'wss://stream-testnet.bybit.com/v5/private', }, }, v5SpotPublic: { public: { livenet: 'wss://stream.bybit.com/v5/public/spot', testnet: 'wss://stream-testnet.bybit.com/v5/public/spot', }, }, v5LinearPublic: { public: { livenet: 'wss://stream.bybit.com/v5/public/linear', testnet: 'wss://stream-testnet.bybit.com/v5/public/linear', }, }, v5InversePublic: { public: { livenet: 'wss://stream.bybit.com/v5/public/inverse', testnet: 'wss://stream-testnet.bybit.com/v5/public/inverse', }, }, v5OptionPublic: { public: { livenet: 'wss://stream.bybit.com/v5/public/option', testnet: 'wss://stream-testnet.bybit.com/v5/public/option', }, }, }; exports.WS_KEY_MAP = { inverse: 'inverse', linearPrivate: 'linearPrivate', linearPublic: 'linearPublic', spotPrivate: 'spotPrivate', spotPublic: 'spotPublic', spotV3Private: 'spotV3Private', spotV3Public: 'spotV3Public', usdcOptionPrivate: 'usdcOptionPrivate', usdcOptionPublic: 'usdcOptionPublic', usdcPerpPrivate: 'usdcPerpPrivate', usdcPerpPublic: 'usdcPerpPublic', unifiedPrivate: 'unifiedPrivate', unifiedOptionPublic: 'unifiedOptionPublic', unifiedPerpUSDTPublic: 'unifiedPerpUSDTPublic', unifiedPerpUSDCPublic: 'unifiedPerpUSDCPublic', contractUSDTPublic: 'contractUSDTPublic', contractUSDTPrivate: 'contractUSDTPrivate', contractInversePublic: 'contractInversePublic', contractInversePrivate: 'contractInversePrivate', v5SpotPublic: 'v5SpotPublic', v5LinearPublic: 'v5LinearPublic', v5InversePublic: 'v5InversePublic', v5OptionPublic: 'v5OptionPublic', v5Private: 'v5Private', }; exports.WS_AUTH_ON_CONNECT_KEYS = [ exports.WS_KEY_MAP.spotV3Private, exports.WS_KEY_MAP.usdcOptionPrivate, exports.WS_KEY_MAP.usdcPerpPrivate, exports.WS_KEY_MAP.unifiedPrivate, exports.WS_KEY_MAP.contractUSDTPrivate, exports.WS_KEY_MAP.contractInversePrivate, exports.WS_KEY_MAP.v5Private, ]; exports.PUBLIC_WS_KEYS = [ exports.WS_KEY_MAP.linearPublic, exports.WS_KEY_MAP.spotPublic, exports.WS_KEY_MAP.spotV3Public, exports.WS_KEY_MAP.usdcOptionPublic, exports.WS_KEY_MAP.usdcPerpPublic, exports.WS_KEY_MAP.unifiedOptionPublic, exports.WS_KEY_MAP.unifiedPerpUSDTPublic, exports.WS_KEY_MAP.unifiedPerpUSDCPublic, exports.WS_KEY_MAP.contractUSDTPublic, exports.WS_KEY_MAP.contractInversePublic, exports.WS_KEY_MAP.v5SpotPublic, exports.WS_KEY_MAP.v5LinearPublic, exports.WS_KEY_MAP.v5InversePublic, exports.WS_KEY_MAP.v5OptionPublic, ]; /** Used to automatically determine if a sub request should be to the public or private ws (when there's two) */ const PRIVATE_TOPICS = [ 'stop_order', 'outboundAccountInfo', 'executionReport', 'ticketInfo', // copy trading apis 'copyTradePosition', 'copyTradeOrder', 'copyTradeExecution', 'copyTradeWallet', // usdc options 'user.openapi.option.position', 'user.openapi.option.trade', 'user.order', 'user.openapi.option.order', 'user.service', 'user.openapi.greeks', 'user.mmp.event', // usdc perps 'user.openapi.perp.position', 'user.openapi.perp.trade', 'user.openapi.perp.order', 'user.service', // unified margin 'user.position.unifiedAccount', 'user.execution.unifiedAccount', 'user.order.unifiedAccount', 'user.wallet.unifiedAccount', 'user.greeks.unifiedAccount', // contract v3 'user.position.contractAccount', 'user.execution.contractAccount', 'user.order.contractAccount', 'user.wallet.contractAccount', // v5 'position', 'execution', 'order', 'wallet', 'greeks', ]; function isPrivateWsTopic(topic) { return PRIVATE_TOPICS.includes(topic); } exports.isPrivateWsTopic = isPrivateWsTopic; function getWsKeyForTopic(market, topic, isPrivate, category) { const isPrivateTopic = isPrivate === true || PRIVATE_TOPICS.includes(topic); switch (market) { case 'inverse': { return exports.WS_KEY_MAP.inverse; } case 'linear': { return isPrivateTopic ? exports.WS_KEY_MAP.linearPrivate : exports.WS_KEY_MAP.linearPublic; } case 'spot': { return isPrivateTopic ? exports.WS_KEY_MAP.spotPrivate : exports.WS_KEY_MAP.spotPublic; } case 'spotv3': { return isPrivateTopic ? exports.WS_KEY_MAP.spotV3Private : exports.WS_KEY_MAP.spotV3Public; } case 'usdcOption': { return isPrivateTopic ? exports.WS_KEY_MAP.usdcOptionPrivate : exports.WS_KEY_MAP.usdcOptionPublic; } case 'usdcPerp': { return isPrivateTopic ? exports.WS_KEY_MAP.usdcPerpPrivate : exports.WS_KEY_MAP.usdcPerpPublic; } case 'unifiedOption': { return isPrivateTopic ? exports.WS_KEY_MAP.unifiedPrivate : exports.WS_KEY_MAP.unifiedOptionPublic; } case 'unifiedPerp': { if (isPrivateTopic) { return exports.WS_KEY_MAP.unifiedPrivate; } const upperTopic = topic.toUpperCase(); if (upperTopic.indexOf('USDT') !== -1) { return exports.WS_KEY_MAP.unifiedPerpUSDTPublic; } if (upperTopic.indexOf('USDC') !== -1 || upperTopic.indexOf('PERP') !== -1) { return exports.WS_KEY_MAP.unifiedPerpUSDCPublic; } throw new Error(`Failed to determine wskey for unified perps topic: "${topic}"`); } case 'contractInverse': { return isPrivateTopic ? exports.WS_KEY_MAP.contractInversePrivate : exports.WS_KEY_MAP.contractInversePublic; } case 'contractUSDT': { return isPrivateTopic ? exports.WS_KEY_MAP.contractUSDTPrivate : exports.WS_KEY_MAP.contractUSDTPublic; } case 'v5': { if (isPrivateTopic) { return exports.WS_KEY_MAP.v5Private; } switch (category) { case 'spot': { return exports.WS_KEY_MAP.v5SpotPublic; } case 'linear': { return exports.WS_KEY_MAP.v5LinearPublic; } case 'inverse': { return exports.WS_KEY_MAP.v5InversePublic; } case 'option': { return exports.WS_KEY_MAP.v5OptionPublic; } case undefined: { throw new Error('Category cannot be undefined'); } default: { throw neverGuard(category, 'getWsKeyForTopic(v5): Unhandled v5 category'); } } } default: { throw neverGuard(market, 'getWsKeyForTopic(): Unhandled market'); } } } exports.getWsKeyForTopic = getWsKeyForTopic; function getWsUrl(wsKey, wsClientOptions, logger) { const wsUrl = wsClientOptions.wsUrl; if (wsUrl) { return wsUrl; } // https://bybit-exchange.github.io/docs/v5/demo const isDemoTrading = wsClientOptions.demoTrading; if (isDemoTrading) { return 'wss://stream-demo.bybit.com/v5/private'; } const isTestnet = wsClientOptions.testnet; const networkKey = isTestnet ? 'testnet' : 'livenet'; switch (wsKey) { case exports.WS_KEY_MAP.linearPublic: { return exports.WS_BASE_URL_MAP.linear.public[networkKey]; } case exports.WS_KEY_MAP.linearPrivate: { return exports.WS_BASE_URL_MAP.linear.private[networkKey]; } case exports.WS_KEY_MAP.spotPublic: { return exports.WS_BASE_URL_MAP.spot.public[networkKey]; } case exports.WS_KEY_MAP.spotPrivate: { return exports.WS_BASE_URL_MAP.spot.private[networkKey]; } case exports.WS_KEY_MAP.spotV3Public: { return exports.WS_BASE_URL_MAP.spotv3.public[networkKey]; } case exports.WS_KEY_MAP.spotV3Private: { return exports.WS_BASE_URL_MAP.spotv3.private[networkKey]; } case exports.WS_KEY_MAP.inverse: { // private and public are on the same WS connection return exports.WS_BASE_URL_MAP.inverse.public[networkKey]; } case exports.WS_KEY_MAP.usdcOptionPublic: { return exports.WS_BASE_URL_MAP.usdcOption.public[networkKey]; } case exports.WS_KEY_MAP.usdcOptionPrivate: { return exports.WS_BASE_URL_MAP.usdcOption.private[networkKey]; } case exports.WS_KEY_MAP.usdcPerpPublic: { return exports.WS_BASE_URL_MAP.usdcPerp.public[networkKey]; } case exports.WS_KEY_MAP.usdcPerpPrivate: { return exports.WS_BASE_URL_MAP.usdcPerp.private[networkKey]; } case exports.WS_KEY_MAP.unifiedOptionPublic: { return exports.WS_BASE_URL_MAP.unifiedOption.public[networkKey]; } case exports.WS_KEY_MAP.unifiedPerpUSDTPublic: { return exports.WS_BASE_URL_MAP.unifiedPerpUSDT.public[networkKey]; } case exports.WS_KEY_MAP.unifiedPerpUSDCPublic: { return exports.WS_BASE_URL_MAP.unifiedPerpUSDC.public[networkKey]; } case exports.WS_KEY_MAP.unifiedPrivate: { return exports.WS_BASE_URL_MAP.unifiedPerp.private[networkKey]; } case exports.WS_KEY_MAP.contractInversePrivate: { return exports.WS_BASE_URL_MAP.contractInverse.private[networkKey]; } case exports.WS_KEY_MAP.contractInversePublic: { return exports.WS_BASE_URL_MAP.contractInverse.public[networkKey]; } case exports.WS_KEY_MAP.contractUSDTPrivate: { return exports.WS_BASE_URL_MAP.contractUSDT.private[networkKey]; } case exports.WS_KEY_MAP.contractUSDTPublic: { return exports.WS_BASE_URL_MAP.contractUSDT.public[networkKey]; } case exports.WS_KEY_MAP.v5Private: { return exports.WS_BASE_URL_MAP.v5.private[networkKey]; } case exports.WS_KEY_MAP.v5SpotPublic: { return exports.WS_BASE_URL_MAP.v5SpotPublic.public[networkKey]; } case exports.WS_KEY_MAP.v5LinearPublic: { return exports.WS_BASE_URL_MAP.v5LinearPublic.public[networkKey]; } case exports.WS_KEY_MAP.v5InversePublic: { return exports.WS_BASE_URL_MAP.v5InversePublic.public[networkKey]; } case exports.WS_KEY_MAP.v5OptionPublic: { return exports.WS_BASE_URL_MAP.v5OptionPublic.public[networkKey]; } default: { logger.error('getWsUrl(): Unhandled wsKey: ', { category: 'bybit-ws', wsKey, }); throw neverGuard(wsKey, 'getWsUrl(): Unhandled wsKey'); } } } exports.getWsUrl = getWsUrl; function getMaxTopicsPerSubscribeEvent(market, wsKey) { const topicsPerEventSpot = 10; switch (market) { case 'inverse': case 'linear': case 'usdcOption': case 'usdcPerp': case 'unifiedOption': case 'unifiedPerp': case 'spot': case 'contractInverse': case 'contractUSDT': case 'v5': { if (wsKey === exports.WS_KEY_MAP.v5SpotPublic) { return topicsPerEventSpot; } return null; } case 'spotv3': { return topicsPerEventSpot; } default: { throw neverGuard(market, 'getWsKeyForTopic(): Unhandled market'); } } } exports.getMaxTopicsPerSubscribeEvent = getMaxTopicsPerSubscribeEvent; function getUsdcWsKeyForTopic(topic, subGroup) { const isPrivateTopic = PRIVATE_TOPICS.includes(topic); if (subGroup === 'option') { return isPrivateTopic ? exports.WS_KEY_MAP.usdcOptionPrivate : exports.WS_KEY_MAP.usdcOptionPublic; } return isPrivateTopic ? exports.WS_KEY_MAP.usdcOptionPrivate : exports.WS_KEY_MAP.usdcOptionPublic; // return isPrivateTopic // ? WS_KEY_MAP.usdcPerpPrivate // : WS_KEY_MAP.usdcPerpPublic; } exports.getUsdcWsKeyForTopic = getUsdcWsKeyForTopic; exports.WS_ERROR_ENUM = { NOT_AUTHENTICATED_SPOT_V3: '-1004', API_ERROR_GENERIC: '10001', API_SIGN_AUTH_FAILED: '10003', USDC_OPTION_AUTH_FAILED: '3303006', }; function neverGuard(x, msg) { return new Error(`Unhandled value exception "x", ${msg}`); } exports.neverGuard = neverGuard; /** * #305: ws.terminate() is undefined in browsers. * This only works in node.js, not in browsers. * Does nothing if `ws` is undefined. */ function safeTerminateWs(ws) { // #305: ws.terminate() undefined in browsers if (ws && typeof ws['terminate'] === 'function') { ws.terminate(); } } exports.safeTerminateWs = safeTerminateWs; //# sourceMappingURL=websocket-util.js.map