Merge pull request #304 from tiagosiebler/docsupdate

Docsupdate
This commit is contained in:
Tiago
2023-12-11 10:13:14 +00:00
committed by GitHub
18 changed files with 43 additions and 1081 deletions

View File

@@ -35,7 +35,6 @@ Check out my related projects:
- [bybit-api](https://www.npmjs.com/package/bybit-api) - [bybit-api](https://www.npmjs.com/package/bybit-api)
- [okx-api](https://www.npmjs.com/package/okx-api) - [okx-api](https://www.npmjs.com/package/okx-api)
- [bitget-api](https://www.npmjs.com/package/bitget-api) - [bitget-api](https://www.npmjs.com/package/bitget-api)
- [ftx-api](https://www.npmjs.com/package/ftx-api)
- Try my misc utilities: - Try my misc utilities:
- [orderbooks](https://www.npmjs.com/package/orderbooks) - [orderbooks](https://www.npmjs.com/package/orderbooks)
- Check out my examples: - Check out my examples:
@@ -55,33 +54,33 @@ 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 - [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. - [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) - examples & demonstrations. Contributions are welcome!
- [examples](./examples) - some implementation examples & demonstrations. Contributions are welcome!
--- ---
## REST API Clients ## 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: Here are the available REST clients and the corresponding API groups described in the documentation:
| Class | Description | | 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). | | [ **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) | | [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) | | [ **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) | | [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). | | [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 | | [ **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) | | 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/) | | [~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) | | [~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) | | [~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 | | [ **Spot** ] | The spot APIs |
| [SpotClientV3](src/spot-client-v3.ts) | [Spot Market (v3) APIs](https://bybit-exchange.github.io/docs/spot/public/instrument) | | [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) | | [~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 | | [ **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) | | [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) | | [USDCOptionClient](src/usdc-option-client.ts) | [USDC Option APIs](https://bybit-exchange.github.io/docs/usdc/option/#t-introduction) |
@@ -256,6 +255,9 @@ const wsConfig = {
// how long to wait before attempting to reconnect (in ms) after connection is closed // how long to wait before attempting to reconnect (in ms) after connection is closed
// reconnectTimeout: 500, // 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. // config options sent to RestClient (used for time sync). See RestClient docs.
// restOptions: { }, // restOptions: { },

View File

@@ -1,6 +1,6 @@
{ {
"name": "bybit-api", "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.", "description": "Complete & robust Node.js SDK for Bybit's REST APIs and WebSockets, with TypeScript & strong end to end tests.",
"main": "lib/index.js", "main": "lib/index.js",
"types": "lib/index.d.ts", "types": "lib/index.d.ts",

View File

@@ -98,6 +98,8 @@ export interface WSClientConfigurableOptions {
pongTimeout?: number; pongTimeout?: number;
pingInterval?: number; pingInterval?: number;
reconnectTimeout?: number; reconnectTimeout?: number;
/** Override the recv window for authenticating over websockets (default: 5000 ms) */
recvWindow?: number;
restOptions?: RestClientOptions; restOptions?: RestClientOptions;
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
requestOptions?: any; requestOptions?: any;

View File

@@ -123,6 +123,7 @@ export class WebsocketClient extends EventEmitter {
pongTimeout: 1000, pongTimeout: 1000,
pingInterval: 10000, pingInterval: 10000,
reconnectTimeout: 500, reconnectTimeout: 500,
recvWindow: 5000,
fetchTimeOffsetBeforeAuth: false, fetchTimeOffsetBeforeAuth: false,
...options, ...options,
}; };
@@ -739,7 +740,9 @@ export class WebsocketClient extends EventEmitter {
? (await this.restClient?.fetchTimeOffset()) || 0 ? (await this.restClient?.fetchTimeOffset()) || 0
: 0; : 0;
const signatureExpiresAt = Date.now() + timeOffset + 5000; const recvWindow = this.options.recvWindow || 5000;
const signatureExpiresAt = Date.now() + timeOffset + recvWindow;
const signature = await signMessage( const signature = await signMessage(
'GET/realtime' + signatureExpiresAt, 'GET/realtime' + signatureExpiresAt,

View File

@@ -2,7 +2,7 @@ import { SpotClient } from '../../src';
import { getTestProxy } from '../proxy.util'; import { getTestProxy } from '../proxy.util';
import { errorResponseObject, successResponseList } from '../response.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_KEY = process.env.API_KEY_COM;
const API_SECRET = process.env.API_SECRET_COM; const API_SECRET = process.env.API_SECRET_COM;

View File

@@ -2,7 +2,7 @@ import { API_ERROR_CODE, SpotClient } from '../../src';
import { getTestProxy } from '../proxy.util'; import { getTestProxy } from '../proxy.util';
import { successResponseObject } from '../response.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_KEY = process.env.API_KEY_COM;
const API_SECRET = process.env.API_SECRET_COM; const API_SECRET = process.env.API_SECRET_COM;

View File

@@ -14,7 +14,7 @@ import {
waitForSocketEvent, waitForSocketEvent,
} from '../ws.util'; } from '../ws.util';
describe('Private Spot V1 Websocket Client', () => { describe.skip('Private Spot V1 Websocket Client', () => {
let wsClient: WebsocketClient; let wsClient: WebsocketClient;
const API_KEY = process.env.API_KEY_COM; const API_KEY = process.env.API_KEY_COM;
const API_SECRET = process.env.API_SECRET_COM; const API_SECRET = process.env.API_SECRET_COM;
@@ -34,7 +34,7 @@ describe('Private Spot V1 Websocket Client', () => {
wsClient = new WebsocketClient( wsClient = new WebsocketClient(
wsClientOptions, wsClientOptions,
// fullLogger // fullLogger
getSilentLogger('expectSuccess') getSilentLogger('expectSuccess'),
); );
logAllEvents(wsClient); logAllEvents(wsClient);
}); });

View File

@@ -13,7 +13,7 @@ import {
waitForSocketEvent, waitForSocketEvent,
} from '../ws.util'; } from '../ws.util';
describe('Public Spot V1 Websocket Client', () => { describe.skip('Public Spot V1 Websocket Client', () => {
let wsClient: WebsocketClient; let wsClient: WebsocketClient;
const wsClientOptions: WSClientConfigurableOptions = { const wsClientOptions: WSClientConfigurableOptions = {
@@ -23,7 +23,7 @@ describe('Public Spot V1 Websocket Client', () => {
beforeAll(() => { beforeAll(() => {
wsClient = new WebsocketClient( wsClient = new WebsocketClient(
wsClientOptions, wsClientOptions,
getSilentLogger('expectSuccess') getSilentLogger('expectSuccess'),
); );
wsClient.connectPublic(); wsClient.connectPublic();
// logAllEvents(wsClient); // logAllEvents(wsClient);

View File

@@ -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(),
);
});
});

View File

@@ -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,
});
});
});

View File

@@ -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());
});
});

View File

@@ -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,
});
});
});
});

View File

@@ -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();
// }
});
});

View File

@@ -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(),
);
});
});

View File

@@ -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,
});
});
});

View File

@@ -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());
});
});

View File

@@ -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,
});
});
});
});

View File

@@ -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();
}
});
});