diff --git a/README.md b/README.md index 87b7a37..1239f73 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,6 @@ Check out my related projects: - [bybit-api](https://www.npmjs.com/package/bybit-api) - [okx-api](https://www.npmjs.com/package/okx-api) - [bitget-api](https://www.npmjs.com/package/bitget-api) - - [ftx-api](https://www.npmjs.com/package/ftx-api) - Try my misc utilities: - [orderbooks](https://www.npmjs.com/package/orderbooks) - Check out my examples: @@ -55,41 +54,41 @@ The version on npm is the output from the `build` command and can be used in pro - [src](./src) - the whole connector written in TypeScript - [lib](./lib) - the JavaScript version of the project (built from TypeScript). This should not be edited directly, as it will be overwritten with each release. -- [dist](./dist) - the webpack bundle of the project for use in browser environments (see guidance on webpack below). -- [examples](./examples) - some implementation examples & demonstrations. Contributions are welcome! +- [examples](./examples) - examples & demonstrations. Contributions are welcome! --- ## REST API Clients -Bybit has several API groups (originally one per product). Each generation is labelled with the version number (e.g. v1/v2/v3/v5). Some of the newer API groups can only be used by upgrading your account to the unified account, but doing so will prevent you from using the V1 and V2 APIs. +Bybit has several API groups (originally one per product). Each generation is labelled with the version number (e.g. v1/v2/v3/v5). New projects & developments should use the newest available API generation (e.g. use the V5 APIs instead of V3). -Refer to the [V5 upgrade guide](https://bybit-exchange.github.io/docs/v5/upgrade-guide) for more information on requirements to use each API group. If you have a choice, you should use the newest generation that is available (e.g. use the V5 instead of the V3 APIs if you can). +Refer to the [V5 interface mapping page](https://bybit-exchange.github.io/docs/v5/intro#v5-and-v3-interface-mapping-list) for more information on which V5 endpoints can be used instead of previous V3 endpoints. Here are the available REST clients and the corresponding API groups described in the documentation: -| Class | Description | -|:------------------------------------------------------------------: |:----------------------------------------------------------------------------------------------------------------------------: | -| [ **V5 API** ] | The new unified V5 APIs (successor to previously fragmented APIs for all API groups). To learn more about the V5 API, please read the [V5 upgrade guideline](https://bybit-exchange.github.io/docs/v5/upgrade-guide). | -| [RestClientV5](src/rest-client-v5.ts) | Unified V5 all-in-one REST client for all [V5 REST APIs](https://bybit-exchange.github.io/docs/v5/intro) | -| [ **Derivatives v3** ] | The Derivatives v3 APIs (successor to the Futures V2 APIs) | -| [UnifiedMarginClient](src/unified-margin-client.ts) | [Derivatives (v3) Unified Margin APIs](https://bybit-exchange.github.io/docs/derivatives/unified/place-order) | -| [ContractClient](src/contract-client.ts) | [Derivatives (v3) Contract APIs](https://bybit-exchange.github.io/docs/derivatives/contract/place-order). | -| [ **Futures v2** ] | The Futures v2 APIs | -| Deprecated! ContractClient or RestClientV5 recommended | Please read the [V5 upgrade guideline](https://bybit-exchange.github.io/docs/v5/upgrade-guide) | -| [~InverseClient~](src/inverse-client.ts)| [Inverse Perpetual Futures (v2) APIs](https://bybit-exchange.github.io/docs/futuresV2/inverse/) | -| [~LinearClient~](src/linear-client.ts) | [USDT Perpetual Futures (v2) APIs](https://bybit-exchange.github.io/docs/futuresV2/linear/#t-introduction) | -| [~InverseFuturesClient~](src/inverse-futures-client.ts) | [Inverse Futures (v2) APIs](https://bybit-exchange.github.io/docs/futuresV2/inverse_futures/#t-introduction) | -| [ **Spot** ] | The spot APIs | -| [SpotClientV3](src/spot-client-v3.ts) | [Spot Market (v3) APIs](https://bybit-exchange.github.io/docs/spot/public/instrument) | -| [~SpotClient~](src/spot-client.ts) (deprecated, SpotClientV3 recommended)| [Spot Market (v1) APIs](https://bybit-exchange.github.io/docs/spot/v1/#t-introduction) | -| [ **USDC Contract** ] | The USDC Contract APIs | -| [USDCPerpetualClient](src/usdc-perpetual-client.ts) | [USDC Perpetual APIs](https://bybit-exchange.github.io/docs/usdc/option/?console#t-querydeliverylog) | -| [USDCOptionClient](src/usdc-option-client.ts) | [USDC Option APIs](https://bybit-exchange.github.io/docs/usdc/option/#t-introduction) | -| [ **Other** ] | Other standalone API groups | -| [CopyTradingClient](src/copy-trading-client.ts) | [Copy Trading APIs](https://bybit-exchange.github.io/docs/category/copy-trade) | -| [AccountAssetClientV3](src/account-asset-client-v3.ts) | [Account Asset V3 APIs](https://bybit-exchange.github.io/docs/account-asset/internal-transfer) | -| [~AccountAssetClient~](src/account-asset-client.ts) (deprecated, AccountAssetClientV3 recommended) | [Account Asset V1 APIs](https://bybit-exchange.github.io/docs/account_asset/v1/#t-introduction) | -| [WebsocketClient](src/websocket-client.ts) | All WebSocket Events (Public & Private for all API categories) | + +| Class | Description | +| :------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | +| [ **V5 API** ] | The new unified V5 APIs (successor to previously fragmented APIs for all API groups). To learn more about the V5 API, please read the [V5 upgrade guideline](https://bybit-exchange.github.io/docs/v5/upgrade-guide). | +| [RestClientV5](src/rest-client-v5.ts) | Unified V5 all-in-one REST client for all [V5 REST APIs](https://bybit-exchange.github.io/docs/v5/intro) | +| [ **Derivatives v3** ] | The Derivatives v3 APIs (successor to the Futures V2 APIs) | +| [UnifiedMarginClient](src/unified-margin-client.ts) | [Derivatives (v3) Unified Margin APIs](https://bybit-exchange.github.io/docs/derivatives/unified/place-order) | +| [ContractClient](src/contract-client.ts) | [Derivatives (v3) Contract APIs](https://bybit-exchange.github.io/docs/derivatives/contract/place-order). | +| [ **Futures v2** ] | The Futures v2 APIs | +| Deprecated! RestClientV5 recommended | Please read the [V5 interface mapping page](https://bybit-exchange.github.io/docs/v5/intro#v5-and-v3-interface-mapping-list) | +| [~InverseClient~](src/inverse-client.ts) | [Inverse Perpetual Futures (v2) APIs](https://bybit-exchange.github.io/docs/futuresV2/inverse/) | +| [~LinearClient~](src/linear-client.ts) | [USDT Perpetual Futures (v2) APIs](https://bybit-exchange.github.io/docs/futuresV2/linear/#t-introduction) | +| [~InverseFuturesClient~](src/inverse-futures-client.ts) | [Inverse Futures (v2) APIs](https://bybit-exchange.github.io/docs/futuresV2/inverse_futures/#t-introduction) | +| [ **Spot** ] | The spot APIs | +| [SpotClientV3](src/spot-client-v3.ts) | [Spot Market (v3) APIs](https://bybit-exchange.github.io/docs/spot/public/instrument) | +| [~SpotClient~](src/spot-client.ts) (deprecated, SpotClientV3 recommended) | [Spot Market (v1) APIs](https://bybit-exchange.github.io/docs/spot/v1/#t-introduction) | +| [ **USDC Contract** ] | The USDC Contract APIs | +| [USDCPerpetualClient](src/usdc-perpetual-client.ts) | [USDC Perpetual APIs](https://bybit-exchange.github.io/docs/usdc/option/?console#t-querydeliverylog) | +| [USDCOptionClient](src/usdc-option-client.ts) | [USDC Option APIs](https://bybit-exchange.github.io/docs/usdc/option/#t-introduction) | +| [ **Other** ] | Other standalone API groups | +| [CopyTradingClient](src/copy-trading-client.ts) | [Copy Trading APIs](https://bybit-exchange.github.io/docs/category/copy-trade) | +| [AccountAssetClientV3](src/account-asset-client-v3.ts) | [Account Asset V3 APIs](https://bybit-exchange.github.io/docs/account-asset/internal-transfer) | +| [~AccountAssetClient~](src/account-asset-client.ts) (deprecated, AccountAssetClientV3 recommended) | [Account Asset V1 APIs](https://bybit-exchange.github.io/docs/account_asset/v1/#t-introduction) | +| [WebsocketClient](src/websocket-client.ts) | All WebSocket Events (Public & Private for all API categories) | Examples for using each client can be found in: @@ -256,6 +255,9 @@ const wsConfig = { // how long to wait before attempting to reconnect (in ms) after connection is closed // reconnectTimeout: 500, + // recv window size for authenticated websocket requests (higher latency connections (VPN) can cause authentication to fail if the recv window is too small) + // recvWindow: 5000, + // config options sent to RestClient (used for time sync). See RestClient docs. // restOptions: { }, diff --git a/package.json b/package.json index 928596e..13e2c41 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "bybit-api", - "version": "3.7.7", + "version": "3.7.8", "description": "Complete & robust Node.js SDK for Bybit's REST APIs and WebSockets, with TypeScript & strong end to end tests.", "main": "lib/index.js", "types": "lib/index.d.ts", diff --git a/src/types/websockets.ts b/src/types/websockets.ts index 4d49d55..ee9730f 100644 --- a/src/types/websockets.ts +++ b/src/types/websockets.ts @@ -98,6 +98,8 @@ export interface WSClientConfigurableOptions { pongTimeout?: number; pingInterval?: number; reconnectTimeout?: number; + /** Override the recv window for authenticating over websockets (default: 5000 ms) */ + recvWindow?: number; restOptions?: RestClientOptions; // eslint-disable-next-line @typescript-eslint/no-explicit-any requestOptions?: any; diff --git a/src/websocket-client.ts b/src/websocket-client.ts index f48a847..ade0eeb 100644 --- a/src/websocket-client.ts +++ b/src/websocket-client.ts @@ -123,6 +123,7 @@ export class WebsocketClient extends EventEmitter { pongTimeout: 1000, pingInterval: 10000, reconnectTimeout: 500, + recvWindow: 5000, fetchTimeOffsetBeforeAuth: false, ...options, }; @@ -739,7 +740,9 @@ export class WebsocketClient extends EventEmitter { ? (await this.restClient?.fetchTimeOffset()) || 0 : 0; - const signatureExpiresAt = Date.now() + timeOffset + 5000; + const recvWindow = this.options.recvWindow || 5000; + + const signatureExpiresAt = Date.now() + timeOffset + recvWindow; const signature = await signMessage( 'GET/realtime' + signatureExpiresAt, diff --git a/test/spot/private.v1.read.test.ts b/test/spot/private.v1.read.test.ts index 67a83e6..af8425c 100644 --- a/test/spot/private.v1.read.test.ts +++ b/test/spot/private.v1.read.test.ts @@ -2,7 +2,7 @@ import { SpotClient } from '../../src'; import { getTestProxy } from '../proxy.util'; import { errorResponseObject, successResponseList } from '../response.util'; -describe('Private Spot REST API GET Endpoints', () => { +describe.skip('Private Spot REST API GET Endpoints', () => { const API_KEY = process.env.API_KEY_COM; const API_SECRET = process.env.API_SECRET_COM; diff --git a/test/spot/private.v1.write.test.ts b/test/spot/private.v1.write.test.ts index 8c260db..41e59a5 100644 --- a/test/spot/private.v1.write.test.ts +++ b/test/spot/private.v1.write.test.ts @@ -2,7 +2,7 @@ import { API_ERROR_CODE, SpotClient } from '../../src'; import { getTestProxy } from '../proxy.util'; import { successResponseObject } from '../response.util'; -describe('Private Spot REST API POST Endpoints', () => { +describe.skip('Private Spot REST API POST Endpoints', () => { const API_KEY = process.env.API_KEY_COM; const API_SECRET = process.env.API_SECRET_COM; diff --git a/test/spot/ws.private.v1.test.ts b/test/spot/ws.private.v1.test.ts index d409b7f..2a64338 100644 --- a/test/spot/ws.private.v1.test.ts +++ b/test/spot/ws.private.v1.test.ts @@ -14,7 +14,7 @@ import { waitForSocketEvent, } from '../ws.util'; -describe('Private Spot V1 Websocket Client', () => { +describe.skip('Private Spot V1 Websocket Client', () => { let wsClient: WebsocketClient; const API_KEY = process.env.API_KEY_COM; const API_SECRET = process.env.API_SECRET_COM; @@ -34,7 +34,7 @@ describe('Private Spot V1 Websocket Client', () => { wsClient = new WebsocketClient( wsClientOptions, // fullLogger - getSilentLogger('expectSuccess') + getSilentLogger('expectSuccess'), ); logAllEvents(wsClient); }); diff --git a/test/spot/ws.public.v1.test.ts b/test/spot/ws.public.v1.test.ts index b6b1d87..8824b37 100644 --- a/test/spot/ws.public.v1.test.ts +++ b/test/spot/ws.public.v1.test.ts @@ -13,7 +13,7 @@ import { waitForSocketEvent, } from '../ws.util'; -describe('Public Spot V1 Websocket Client', () => { +describe.skip('Public Spot V1 Websocket Client', () => { let wsClient: WebsocketClient; const wsClientOptions: WSClientConfigurableOptions = { @@ -23,7 +23,7 @@ describe('Public Spot V1 Websocket Client', () => { beforeAll(() => { wsClient = new WebsocketClient( wsClientOptions, - getSilentLogger('expectSuccess') + getSilentLogger('expectSuccess'), ); wsClient.connectPublic(); // logAllEvents(wsClient); diff --git a/test/usdc/options/private.read.test.ts b/test/usdc/options/private.read.test.ts deleted file mode 100644 index 557559d..0000000 --- a/test/usdc/options/private.read.test.ts +++ /dev/null @@ -1,84 +0,0 @@ -import { USDCOptionClient } from '../../../src'; -import { getTestProxy } from '../../proxy.util'; -import { successResponseObjectV3 } from '../../response.util'; - -describe('Private USDC Options REST API GET Endpoints', () => { - const API_KEY = process.env.API_KEY_COM; - const API_SECRET = process.env.API_SECRET_COM; - const symbol = 'BTC-30SEP22-400000-C'; - - it('should have api credentials to test with', () => { - expect(API_KEY).toStrictEqual(expect.any(String)); - expect(API_SECRET).toStrictEqual(expect.any(String)); - }); - - const api = new USDCOptionClient( - { - key: API_KEY, - secret: API_SECRET, - testnet: false, - }, - getTestProxy(), - ); - const category = 'OPTION'; - - it('getActiveRealtimeOrders()', async () => { - expect(await api.getActiveRealtimeOrders()).toMatchObject( - successResponseObjectV3(), - ); - }); - - it('getActiveOrders()', async () => { - expect(await api.getActiveOrders({ category })).toMatchObject( - successResponseObjectV3(), - ); - }); - - it('getHistoricOrders()', async () => { - expect(await api.getHistoricOrders({ category })).toMatchObject( - successResponseObjectV3(), - ); - }); - - it('getOrderExecutionHistory()', async () => { - expect(await api.getOrderExecutionHistory({ category })).toMatchObject( - successResponseObjectV3(), - ); - }); - - it('getTransactionLog()', async () => { - expect(await api.getTransactionLog({ type: 'TRADE' })).toMatchObject( - successResponseObjectV3(), - ); - }); - - it('getBalances()', async () => { - expect(await api.getBalances()).toMatchObject(successResponseObjectV3()); - }); - - it('getAssetInfo()', async () => { - expect(await api.getAssetInfo()).toMatchObject(successResponseObjectV3()); - }); - - it('getMarginMode()', async () => { - expect(await api.getMarginMode()).toMatchObject(successResponseObjectV3()); - }); - - it('getPositions()', async () => { - expect(await api.getPositions({ category })).toMatchObject( - successResponseObjectV3(), - ); - }); - - it('getDeliveryHistory()', async () => { - expect(await api.getDeliveryHistory({ symbol })).toMatchObject( - successResponseObjectV3(), - ); - }); - - it('getPositionsInfoUponExpiry()', async () => { - expect(await api.getPositionsInfoUponExpiry()).toMatchObject( - successResponseObjectV3(), - ); - }); -}); diff --git a/test/usdc/options/private.write.test.ts b/test/usdc/options/private.write.test.ts deleted file mode 100644 index 7e9d4ff..0000000 --- a/test/usdc/options/private.write.test.ts +++ /dev/null @@ -1,169 +0,0 @@ -import { API_ERROR_CODE, USDCOptionClient } from '../../../src'; -import { getTestProxy } from '../../proxy.util'; -// import { successResponseObjectV3 } from '../../response.util'; - -describe('Private USDC Options REST API POST Endpoints', () => { - const API_KEY = process.env.API_KEY_COM; - const API_SECRET = process.env.API_SECRET_COM; - - it('should have api credentials to test with', () => { - expect(API_KEY).toStrictEqual(expect.any(String)); - expect(API_SECRET).toStrictEqual(expect.any(String)); - }); - - const api = new USDCOptionClient( - { - key: API_KEY, - secret: API_SECRET, - testnet: false, - }, - getTestProxy(), - ); - - const currency = 'USDC'; - const symbol = 'BTC-30SEP22-400000-C'; - - it('submitOrder()', async () => { - expect( - await api.submitOrder({ - symbol, - orderType: 'Limit', - side: 'Sell', - orderQty: '1000', - orderPrice: '40', - orderLinkId: Date.now().toString(), - timeInForce: 'GoodTillCancel', - }), - ).toMatchObject({ - retCode: API_ERROR_CODE.CONTRACT_NAME_NOT_EXIST, - }); - }); - - it('batchSubmitOrders()', async () => { - expect( - await api.batchSubmitOrders([ - { - symbol, - orderType: 'Limit', - side: 'Sell', - orderQty: '1000', - orderPrice: '40', - orderLinkId: Date.now().toString(), - timeInForce: 'GoodTillCancel', - }, - { - symbol, - orderType: 'Limit', - side: 'Sell', - orderQty: '1000', - orderPrice: '40', - orderLinkId: Date.now().toString(), - timeInForce: 'GoodTillCancel', - }, - ]), - ).toMatchObject({ - result: [ - { errorCode: API_ERROR_CODE.CONTRACT_NAME_NOT_EXIST }, - { errorCode: API_ERROR_CODE.CONTRACT_NAME_NOT_EXIST }, - ], - }); - }); - - it('modifyOrder()', async () => { - expect( - await api.modifyOrder({ - symbol, - orderId: 'somethingFake', - }), - ).toMatchObject({ - retCode: API_ERROR_CODE.CONTRACT_NAME_NOT_EXIST, - }); - }); - - it('batchModifyOrders()', async () => { - expect( - await api.batchModifyOrders([ - { - symbol, - orderId: 'somethingFake1', - }, - { - symbol, - orderId: 'somethingFake2', - }, - ]), - ).toMatchObject({ - result: [ - { errorCode: API_ERROR_CODE.CONTRACT_NAME_NOT_EXIST }, - { errorCode: API_ERROR_CODE.CONTRACT_NAME_NOT_EXIST }, - ], - }); - }); - - it('cancelOrder()', async () => { - expect( - await api.cancelOrder({ - symbol, - orderId: 'somethingFake1', - }), - ).toMatchObject({ - retCode: API_ERROR_CODE.CONTRACT_NAME_NOT_EXIST, - }); - }); - - it('batchCancelOrders()', async () => { - expect( - await api.batchCancelOrders([ - { - symbol, - orderId: 'somethingFake1', - }, - { - symbol, - orderId: 'somethingFake2', - }, - ]), - ).toMatchObject({ - result: [ - { errorCode: API_ERROR_CODE.CONTRACT_NAME_NOT_EXIST }, - { errorCode: API_ERROR_CODE.CONTRACT_NAME_NOT_EXIST }, - ], - }); - }); - - it('cancelActiveOrders()', async () => { - expect(await api.cancelActiveOrders()).toMatchObject({ - retCode: API_ERROR_CODE.NO_ACTIVE_ORDER, - }); - }); - - // Reached out to bybit - it.skip('setMarginMode()', async () => { - expect(await api.setMarginMode('REGULAR_MARGIN')).toMatchObject( - { - retCode: API_ERROR_CODE.SET_MARGIN_MODE_FAILED_USDC, - }, - // successResponseObjectV3() - ); - }); - - it('modifyMMP()', async () => { - expect( - await api.modifyMMP({ - currency, - windowMs: 0, - frozenPeriodMs: 100, - qtyLimit: '100', - deltaLimit: '1', - }), - ).toMatchObject({ - retCode: API_ERROR_CODE.INCORRECT_MMP_PARAMETERS, - }); - }); - - it('resetMMP()', async () => { - expect(await api.resetMMP(currency)).toMatchObject({ - retCode: API_ERROR_CODE.INSTITION_MMP_PROFILE_NOT_FOUND, - }); - }); -}); diff --git a/test/usdc/options/public.read.test.ts b/test/usdc/options/public.read.test.ts deleted file mode 100644 index 7b0da37..0000000 --- a/test/usdc/options/public.read.test.ts +++ /dev/null @@ -1,61 +0,0 @@ -import { USDCOptionClient } from '../../../src'; -import { getTestProxy } from '../../proxy.util'; -import { - successResponseObject, - successResponseObjectV3, -} from '../../response.util'; - -describe('Public USDC Options REST API Endpoints', () => { - const API_KEY = undefined; - const API_SECRET = undefined; - - const api = new USDCOptionClient( - { - key: API_KEY, - secret: API_SECRET, - testnet: false, - }, - getTestProxy(), - ); - const symbol = 'BTC-30SEP22-400000-C'; - - it('getOrderBook()', async () => { - expect(await api.getOrderBook(symbol)).toMatchObject( - successResponseObjectV3(), - ); - }); - - it('getContractInfo()', async () => { - expect(await api.getContractInfo()).toMatchObject( - successResponseObjectV3(), - ); - }); - - it('getSymbolTicker()', async () => { - expect(await api.getSymbolTicker(symbol)).toMatchObject( - successResponseObjectV3(), - ); - }); - - it('getDeliveryPrice()', async () => { - expect(await api.getDeliveryPrice()).toMatchObject( - successResponseObjectV3(), - ); - }); - - it('getLast500Trades()', async () => { - expect(await api.getLast500Trades({ category: 'OPTION' })).toMatchObject( - successResponseObjectV3(), - ); - }); - - it('getHistoricalVolatility()', async () => { - expect(await api.getHistoricalVolatility()).toMatchObject( - successResponseObjectV3(), - ); - }); - - it('getServerTime()', async () => { - expect(await api.getServerTime()).toMatchObject(successResponseObject()); - }); -}); diff --git a/test/usdc/options/ws.private.test.ts b/test/usdc/options/ws.private.test.ts deleted file mode 100644 index 6efcccf..0000000 --- a/test/usdc/options/ws.private.test.ts +++ /dev/null @@ -1,151 +0,0 @@ -/* eslint-disable no-unused-vars */ -/* eslint-disable @typescript-eslint/no-unused-vars */ -import { - WSClientConfigurableOptions, - WS_ERROR_ENUM, - WS_KEY_MAP, - WebsocketClient, -} from '../../../src'; -import { - WS_OPEN_EVENT_PARTIAL, - fullLogger, - getSilentLogger, - logAllEvents, - waitForSocketEvent, -} from '../../ws.util'; - -describe('Private USDC Option Websocket Client', () => { - const API_KEY = process.env.API_KEY_COM; - const API_SECRET = process.env.API_SECRET_COM; - - const wsClientOptions: WSClientConfigurableOptions = { - market: 'usdcOption', - key: API_KEY, - secret: API_SECRET, - }; - - const wsTopic = 'user.openapi.option.position'; - - describe('with invalid credentials', () => { - it('should reject private subscribe if keys/signature are incorrect', async () => { - const badClient = new WebsocketClient( - { - ...wsClientOptions, - key: 'bad', - secret: 'bad', - reconnectTimeout: 10000, - }, - // fullLogger - getSilentLogger('expect401') - ); - // logAllEvents(badClient); - - // const wsOpenPromise = waitForSocketEvent(badClient, 'open'); - const wsResponsePromise = waitForSocketEvent(badClient, 'response'); - // const wsUpdatePromise = waitForSocketEvent(wsClient, 'update'); - - badClient.connectPrivate(); - - const responsePartial = { - ret_msg: WS_ERROR_ENUM.USDC_OPTION_AUTH_FAILED, - success: false, - type: 'AUTH_RESP', - }; - expect(wsResponsePromise).rejects.toMatchObject(responsePartial); - - try { - await Promise.all([wsResponsePromise]); - } catch (e) { - // console.error() - expect(e).toMatchObject(responsePartial); - } - - // badClient.subscribe(wsTopic); - badClient.removeAllListeners(); - badClient.closeAll(true); - }); - }); - - describe('with valid API credentails', () => { - let wsClient: WebsocketClient; - - it('should have api credentials to test with', () => { - expect(API_KEY).toStrictEqual(expect.any(String)); - expect(API_SECRET).toStrictEqual(expect.any(String)); - }); - - beforeAll(() => { - wsClient = new WebsocketClient( - wsClientOptions, - getSilentLogger('expectSuccess') - ); - // logAllEvents(wsClient); - }); - - afterAll(() => { - wsClient.closeAll(true); - }); - - it('should open a private ws connection', async () => { - wsClient.connectPrivate(); - const wsOpenPromise = waitForSocketEvent(wsClient, 'open'); - const wsResponsePromise = waitForSocketEvent(wsClient, 'response'); - - try { - expect(await wsOpenPromise).toMatchObject({ - event: WS_OPEN_EVENT_PARTIAL, - wsKey: WS_KEY_MAP.usdcOptionPrivate, - }); - } catch (e) { - expect(e).toBeFalsy(); - } - - try { - expect(await wsResponsePromise).toMatchObject({ - ret_msg: '0', - success: true, - type: 'AUTH_RESP', - }); - } catch (e) { - console.error(`Wait for "${wsTopic}" event exception: `, e); - expect(e).toBeFalsy(); - } - }); - - it(`should subscribe to private "${wsTopic}" events`, async () => { - wsClient.connectPrivate(); - const wsResponsePromise = waitForSocketEvent(wsClient, 'response'); - const wsUpdatePromise = waitForSocketEvent(wsClient, 'update'); - - // expect(wsUpdatePromise).resolves.toStrictEqual(''); - wsClient.subscribe(wsTopic); - - try { - expect(await wsResponsePromise).toMatchObject({ - data: { - failTopics: [], - successTopics: [wsTopic], - }, - success: true, - type: 'COMMAND_RESP', - }); - } catch (e) { - console.error( - `Wait for "${wsTopic}" subscription response exception: `, - e - ); - expect(e).toBeFalsy(); - } - expect(await wsUpdatePromise).toMatchObject({ - creationTime: expect.any(Number), - data: { - baseLine: expect.any(Number), - dataType: expect.any(String), - result: expect.any(Array), - version: expect.any(Number), - }, - topic: wsTopic, - }); - }); - }); -}); diff --git a/test/usdc/options/ws.public.test.ts b/test/usdc/options/ws.public.test.ts deleted file mode 100644 index ad054b4..0000000 --- a/test/usdc/options/ws.public.test.ts +++ /dev/null @@ -1,78 +0,0 @@ -/* eslint-disable no-unused-vars */ -/* eslint-disable @typescript-eslint/no-unused-vars */ -import { - WSClientConfigurableOptions, - WS_KEY_MAP, - WebsocketClient, -} from '../../../src'; -import { - WS_OPEN_EVENT_PARTIAL, - getSilentLogger, - logAllEvents, - waitForSocketEvent, -} from '../../ws.util'; - -describe('Public USDC Option Websocket Client', () => { - let wsClient: WebsocketClient; - - const wsClientOptions: WSClientConfigurableOptions = { - market: 'usdcOption', - }; - - beforeAll(() => { - wsClient = new WebsocketClient( - wsClientOptions, - getSilentLogger('expectSuccessNoAuth') - ); - wsClient.connectPublic(); - }); - - afterAll(() => { - wsClient.closeAll(true); - }); - - it('should open a public ws connection', async () => { - const wsOpenPromise = waitForSocketEvent(wsClient, 'open'); - try { - expect(await wsOpenPromise).toMatchObject({ - event: WS_OPEN_EVENT_PARTIAL, - wsKey: WS_KEY_MAP.usdcOptionPublic, - }); - } catch (e) { - expect(e).toBeFalsy(); - } - }); - - it('should subscribe to public trade events', async () => { - const wsResponsePromise = waitForSocketEvent(wsClient, 'response'); - // const wsUpdatePromise = waitForSocketEvent(wsClient, 'update'); - - wsClient.subscribe([ - 'recenttrades.BTC', - 'recenttrades.ETH', - 'recenttrades.SOL', - ]); - - try { - expect(await wsResponsePromise).toMatchObject({ - success: true, - data: { - failTopics: [], - successTopics: expect.any(Array), - }, - type: 'COMMAND_RESP', - }); - } catch (e) { - // sub failed - expect(e).toBeFalsy(); - } - - // Takes a while to get an event from USDC options - testing this manually for now - // try { - // expect(await wsUpdatePromise).toStrictEqual('asdfasdf'); - // } catch (e) { - // // no data - // expect(e).toBeFalsy(); - // } - }); -}); diff --git a/test/usdc/perpetual/private.read.test.ts b/test/usdc/perpetual/private.read.test.ts deleted file mode 100644 index 23c714b..0000000 --- a/test/usdc/perpetual/private.read.test.ts +++ /dev/null @@ -1,79 +0,0 @@ -import { USDCPerpetualClient } from '../../../src'; -import { getTestProxy } from '../../proxy.util'; -import { successResponseObjectV3 } from '../../response.util'; - -describe('Private USDC Perp REST API GET Endpoints', () => { - const API_KEY = process.env.API_KEY_COM; - const API_SECRET = process.env.API_SECRET_COM; - - it('should have api credentials to test with', () => { - expect(API_KEY).toStrictEqual(expect.any(String)); - expect(API_SECRET).toStrictEqual(expect.any(String)); - }); - - const api = new USDCPerpetualClient( - { - key: API_KEY, - secret: API_SECRET, - testnet: false, - }, - getTestProxy(), - ); - - const symbol = 'BTCPERP'; - const category = 'PERPETUAL'; - - it('getActiveOrders()', async () => { - expect(await api.getActiveOrders({ category })).toMatchObject( - successResponseObjectV3(), - ); - }); - - it('getHistoricOrders()', async () => { - expect(await api.getHistoricOrders({ category })).toMatchObject( - successResponseObjectV3(), - ); - }); - - it('getOrderExecutionHistory()', async () => { - expect(await api.getOrderExecutionHistory({ category })).toMatchObject( - successResponseObjectV3(), - ); - }); - - it('getTransactionLog()', async () => { - expect(await api.getTransactionLog({ type: 'TRADE' })).toMatchObject( - successResponseObjectV3(), - ); - }); - - it('getBalances()', async () => { - expect(await api.getBalances()).toMatchObject(successResponseObjectV3()); - }); - - it('getAssetInfo()', async () => { - expect(await api.getAssetInfo()).toMatchObject(successResponseObjectV3()); - }); - - it('getMarginMode()', async () => { - expect(await api.getMarginMode()).toMatchObject(successResponseObjectV3()); - }); - - it('getPositions()', async () => { - expect(await api.getPositions({ category })).toMatchObject( - successResponseObjectV3(), - ); - }); - - it('getSettlementHistory()', async () => { - expect(await api.getSettlementHistory({ symbol })).toMatchObject( - successResponseObjectV3(), - ); - }); - - it('getPredictedFundingRate()', async () => { - expect(await api.getPredictedFundingRate(symbol)).toMatchObject( - successResponseObjectV3(), - ); - }); -}); diff --git a/test/usdc/perpetual/private.write.test.ts b/test/usdc/perpetual/private.write.test.ts deleted file mode 100644 index 1ba973b..0000000 --- a/test/usdc/perpetual/private.write.test.ts +++ /dev/null @@ -1,95 +0,0 @@ -import { API_ERROR_CODE, USDCPerpetualClient } from '../../../src'; -import { getTestProxy } from '../../proxy.util'; -import { successEmptyResponseObjectV3 } from '../../response.util'; - -describe('Private USDC Perp REST API POST Endpoints', () => { - const API_KEY = process.env.API_KEY_COM; - const API_SECRET = process.env.API_SECRET_COM; - - it('should have api credentials to test with', () => { - expect(API_KEY).toStrictEqual(expect.any(String)); - expect(API_SECRET).toStrictEqual(expect.any(String)); - }); - - const api = new USDCPerpetualClient( - { - key: API_KEY, - secret: API_SECRET, - testnet: false, - }, - getTestProxy(), - ); - - const symbol = 'BTCPERP'; - - it('submitOrder()', async () => { - expect( - await api.submitOrder({ - symbol, - side: 'Sell', - orderType: 'Limit', - orderFilter: 'Order', - orderQty: '1', - orderPrice: '20000', - orderLinkId: Date.now().toString(), - timeInForce: 'GoodTillCancel', - }), - ).toMatchObject({ - retCode: API_ERROR_CODE.INSUFFICIENT_BALANCE_FOR_ORDER_COST, - }); - }); - - it('modifyOrder()', async () => { - expect( - await api.modifyOrder({ - symbol, - orderId: 'somethingFake', - orderPrice: '20000', - orderFilter: 'Order', - }), - ).toMatchObject({ - retCode: API_ERROR_CODE.ORDER_NOT_FOUND_OR_TOO_LATE, - }); - }); - - it('cancelOrder()', async () => { - expect( - await api.cancelOrder({ - symbol, - orderId: 'somethingFake1', - orderFilter: 'Order', - }), - ).toMatchObject({ - retCode: API_ERROR_CODE.ORDER_NOT_FOUND_OR_TOO_LATE, - }); - }); - - it('cancelActiveOrders()', async () => { - expect(await api.cancelActiveOrders(symbol, 'Order')).toMatchObject( - successEmptyResponseObjectV3(), - ); - }); - - // Reached out to bybit - it.skip('setMarginMode()', async () => { - expect(await api.setMarginMode('REGULAR_MARGIN')).toMatchObject( - { - retCode: API_ERROR_CODE.SET_MARGIN_MODE_FAILED_USDC, - retMsg: '', - }, - // successResponseObjectV3() - ); - }); - - it('setLeverage()', async () => { - expect(await api.setLeverage(symbol, '5')).toMatchObject({ - retCode: API_ERROR_CODE.LEVERAGE_NOT_MODIFIED, - }); - }); - - it('setRiskLimit()', async () => { - expect(await api.setRiskLimit(symbol, 1)).toMatchObject({ - retCode: API_ERROR_CODE.RISK_LIMIT_NOT_EXISTS, - }); - }); -}); diff --git a/test/usdc/perpetual/public.read.test.ts b/test/usdc/perpetual/public.read.test.ts deleted file mode 100644 index c58f62a..0000000 --- a/test/usdc/perpetual/public.read.test.ts +++ /dev/null @@ -1,102 +0,0 @@ -import { USDCKlineRequest, USDCPerpetualClient } from '../../../src'; -import { - successResponseObject, - successResponseObjectV3, -} from '../../response.util'; -import { getTestProxy } from '../../proxy.util'; - -describe('Public USDC Perp REST API Endpoints', () => { - const API_KEY = undefined; - const API_SECRET = undefined; - - const api = new USDCPerpetualClient( - { - key: API_KEY, - secret: API_SECRET, - testnet: false, - }, - getTestProxy(), - ); - - const symbol = 'BTCPERP'; - const category = 'PERPETUAL'; - const startTime = Number((Date.now() / 1000).toFixed(0)); - - const candleRequest: USDCKlineRequest = { symbol, period: '1m', startTime }; - - it('getOrderBook()', async () => { - expect(await api.getOrderBook(symbol)).toMatchObject( - successResponseObjectV3(), - ); - }); - - it('getContractInfo()', async () => { - expect(await api.getContractInfo()).toMatchObject( - successResponseObjectV3(), - ); - }); - - it('getSymbolTicker()', async () => { - expect(await api.getSymbolTicker(symbol)).toMatchObject( - successResponseObjectV3(), - ); - }); - - it('getCandles()', async () => { - expect(await api.getCandles(candleRequest)).toMatchObject( - successResponseObjectV3(), - ); - }); - - it('getMarkPrice()', async () => { - expect(await api.getMarkPrice(candleRequest)).toMatchObject( - successResponseObjectV3(), - ); - }); - - it('getIndexPrice()', async () => { - expect(await api.getIndexPrice(candleRequest)).toMatchObject( - successResponseObjectV3(), - ); - }); - - it('getIndexPremium()', async () => { - expect(await api.getIndexPremium(candleRequest)).toMatchObject( - successResponseObjectV3(), - ); - }); - - it('getOpenInterest()', async () => { - expect(await api.getOpenInterest({ symbol, period: '1m' })).toMatchObject( - successResponseObjectV3(), - ); - }); - - it('getLargeOrders()', async () => { - expect(await api.getLargeOrders({ symbol })).toMatchObject( - successResponseObjectV3(), - ); - }); - - it('getLongShortRatio()', async () => { - expect(await api.getLongShortRatio({ symbol, period: '1m' })).toMatchObject( - successResponseObjectV3(), - ); - }); - - it('getLast500Trades()', async () => { - expect(await api.getLast500Trades({ category })).toMatchObject( - successResponseObjectV3(), - ); - }); - - it('getLastFundingRate()', async () => { - expect(await api.getLastFundingRate(symbol)).toMatchObject( - successResponseObjectV3(), - ); - }); - - it('getServerTime()', async () => { - expect(await api.getServerTime()).toMatchObject(successResponseObject()); - }); -}); diff --git a/test/usdc/perpetual/ws.private.test.ts b/test/usdc/perpetual/ws.private.test.ts deleted file mode 100644 index e9011d4..0000000 --- a/test/usdc/perpetual/ws.private.test.ts +++ /dev/null @@ -1,150 +0,0 @@ -/* eslint-disable no-unused-vars */ -/* eslint-disable @typescript-eslint/no-unused-vars */ -import { - WSClientConfigurableOptions, - WS_ERROR_ENUM, - WS_KEY_MAP, - WebsocketClient, -} from '../../../src'; -import { - WS_OPEN_EVENT_PARTIAL, - fullLogger, - getSilentLogger, - logAllEvents, - waitForSocketEvent, -} from '../../ws.util'; - -describe('Private USDC Perp Websocket Client', () => { - const API_KEY = process.env.API_KEY_COM; - const API_SECRET = process.env.API_SECRET_COM; - - const wsClientOptions: WSClientConfigurableOptions = { - market: 'usdcPerp', - key: API_KEY, - secret: API_SECRET, - }; - - const wsTopic = 'user.openapi.perp.position'; - - describe('with invalid credentials', () => { - it('should reject private subscribe if keys/signature are incorrect', async () => { - const badClient = new WebsocketClient( - { - ...wsClientOptions, - key: 'bad', - secret: 'bad', - reconnectTimeout: 10000, - }, - // fullLogger - getSilentLogger('expect401') - ); - // logAllEvents(badClient); - - // const wsOpenPromise = waitForSocketEvent(badClient, 'open'); - const wsResponsePromise = waitForSocketEvent(badClient, 'response'); - // const wsUpdatePromise = waitForSocketEvent(wsClient, 'update'); - - badClient.connectPrivate(); - - const responsePartial = { - ret_msg: WS_ERROR_ENUM.USDC_OPTION_AUTH_FAILED, - success: false, - type: 'AUTH_RESP', - }; - expect(wsResponsePromise).rejects.toMatchObject(responsePartial); - - try { - await Promise.all([wsResponsePromise]); - } catch (e) { - // console.error() - expect(e).toMatchObject(responsePartial); - } - - // badClient.subscribe(wsTopic); - badClient.removeAllListeners(); - badClient.closeAll(true); - }); - }); - - describe('with valid API credentails', () => { - let wsClient: WebsocketClient; - - it('should have api credentials to test with', () => { - expect(API_KEY).toStrictEqual(expect.any(String)); - expect(API_SECRET).toStrictEqual(expect.any(String)); - }); - - beforeAll(() => { - wsClient = new WebsocketClient( - wsClientOptions, - getSilentLogger('expectSuccess') - ); - wsClient.connectPrivate(); - // logAllEvents(wsClient); - }); - - afterAll(() => { - wsClient.closeAll(true); - }); - - it('should open a private ws connection', async () => { - const wsOpenPromise = waitForSocketEvent(wsClient, 'open'); - const wsResponsePromise = waitForSocketEvent(wsClient, 'response'); - - try { - expect(await wsOpenPromise).toMatchObject({ - event: WS_OPEN_EVENT_PARTIAL, - wsKey: WS_KEY_MAP.usdcPerpPrivate, - }); - } catch (e) { - expect(e).toBeFalsy(); - } - - try { - expect(await wsResponsePromise).toMatchObject({ - ret_msg: '0', - success: true, - type: 'AUTH_RESP', - }); - } catch (e) { - console.error(`Wait for "${wsTopic}" event exception: `, e); - expect(e).toBeFalsy(); - } - }); - - it(`should subscribe to private "${wsTopic}" events`, async () => { - const wsResponsePromise = waitForSocketEvent(wsClient, 'response'); - const wsUpdatePromise = waitForSocketEvent(wsClient, 'update'); - - // expect(wsUpdatePromise).resolves.toStrictEqual(''); - wsClient.subscribe(wsTopic); - - try { - expect(await wsResponsePromise).toMatchObject({ - data: { - failTopics: [], - successTopics: [wsTopic], - }, - success: true, - type: 'COMMAND_RESP', - }); - } catch (e) { - console.error( - `Wait for "${wsTopic}" subscription response exception: `, - e - ); - expect(e).toBeFalsy(); - } - expect(await wsUpdatePromise).toMatchObject({ - creationTime: expect.any(Number), - data: { - baseLine: expect.any(Number), - dataType: expect.any(String), - result: expect.any(Array), - version: expect.any(Number), - }, - topic: wsTopic, - }); - }); - }); -}); diff --git a/test/usdc/perpetual/ws.public.test.ts b/test/usdc/perpetual/ws.public.test.ts deleted file mode 100644 index a44db83..0000000 --- a/test/usdc/perpetual/ws.public.test.ts +++ /dev/null @@ -1,76 +0,0 @@ -import { - WSClientConfigurableOptions, - WS_KEY_MAP, - WebsocketClient, -} from '../../../src'; -import { - WS_OPEN_EVENT_PARTIAL, - getSilentLogger, - waitForSocketEvent, -} from '../../ws.util'; - -describe('Public USDC Perp Websocket Client', () => { - let wsClient: WebsocketClient; - - const wsClientOptions: WSClientConfigurableOptions = { - market: 'usdcPerp', - }; - - beforeAll(() => { - wsClient = new WebsocketClient( - wsClientOptions, - getSilentLogger('expectSuccessNoAuth') - ); - wsClient.connectPublic(); - // logAllEvents(wsClient); - }); - - afterAll(() => { - wsClient.closeAll(true); - }); - - it('should open a public ws connection', async () => { - const wsOpenPromise = waitForSocketEvent(wsClient, 'open'); - - expect(await wsOpenPromise).toMatchObject({ - event: WS_OPEN_EVENT_PARTIAL, - wsKey: WS_KEY_MAP.usdcPerpPublic, - }); - }); - - it('should subscribe to public trade events', async () => { - const wsResponsePromise = waitForSocketEvent(wsClient, 'response'); - const wsUpdatePromise = waitForSocketEvent(wsClient, 'update'); - - const topic = 'orderBook_200.100ms.BTCPERP'; - wsClient.subscribe(topic); - - try { - expect(await wsResponsePromise).toMatchObject({ - success: true, - ret_msg: '', - request: { - op: 'subscribe', - args: [topic], - }, - }); - } catch (e) { - // sub failed - expect(e).toBeFalsy(); - } - - try { - expect(await wsUpdatePromise).toMatchObject({ - crossSeq: expect.any(String), - data: { orderBook: expect.any(Array) }, - timestampE6: expect.any(String), - topic: topic, - type: 'snapshot', - }); - } catch (e) { - console.error('usdc perp ws public error: ', e); - // no data - expect(e).toBeFalsy(); - } - }); -});