Merge pull request #182 from tiagosiebler/origin/tiagosiebler-patch-1
v3.1.0: fix typo in types (#180), fix tests, fix repeating subscribe/unsubscribe WS events to active connections
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "bybit-api",
|
||||
"version": "3.0.2",
|
||||
"version": "3.1.0",
|
||||
"description": "Complete & robust node.js SDK for Bybit's REST APIs and WebSockets, with TypeScript & integration tests.",
|
||||
"main": "lib/index.js",
|
||||
"types": "lib/index.d.ts",
|
||||
|
||||
@@ -51,6 +51,8 @@ export const API_ERROR_CODE = {
|
||||
INSUFFICIENT_BALANCE_FOR_ORDER_COST_LINEAR: 130080,
|
||||
SAME_SLTP_MODE_LINEAR: 130150,
|
||||
RISK_ID_NOT_MODIFIED: 134026,
|
||||
/** E.g. USDC Options trading, trying to access a symbol that is no longer active */
|
||||
CONTRACT_NAME_NOT_EXIST: 3100111,
|
||||
ORDER_NOT_EXIST: 3100136,
|
||||
NO_ACTIVE_ORDER: 3100205,
|
||||
/** E.g. USDC Options trading when the account hasn't been opened for USDC Options yet */
|
||||
|
||||
@@ -116,22 +116,21 @@ export class WebsocketClient extends EventEmitter {
|
||||
public subscribe(wsTopics: WsTopic[] | WsTopic, isPrivateTopic?: boolean) {
|
||||
const topics = Array.isArray(wsTopics) ? wsTopics : [wsTopics];
|
||||
|
||||
topics.forEach((topic) =>
|
||||
this.wsStore.addTopic(
|
||||
getWsKeyForTopic(this.options.market, topic, isPrivateTopic),
|
||||
topic
|
||||
)
|
||||
);
|
||||
topics.forEach((topic) => {
|
||||
const wsKey = getWsKeyForTopic(
|
||||
this.options.market,
|
||||
topic,
|
||||
isPrivateTopic
|
||||
);
|
||||
|
||||
// Persist topic for reconnects
|
||||
this.wsStore.addTopic(wsKey, topic);
|
||||
|
||||
// attempt to send subscription topic per websocket
|
||||
this.wsStore.getKeys().forEach((wsKey: WsKey) => {
|
||||
// if connected, send subscription request
|
||||
if (
|
||||
this.wsStore.isConnectionState(wsKey, WsConnectionStateEnum.CONNECTED)
|
||||
) {
|
||||
return this.requestSubscribeTopics(wsKey, [
|
||||
...this.wsStore.getTopics(wsKey),
|
||||
]);
|
||||
return this.requestSubscribeTopics(wsKey, [topic]);
|
||||
}
|
||||
|
||||
// start connection process if it hasn't yet begun. Topics are automatically subscribed to on-connect
|
||||
@@ -157,21 +156,21 @@ export class WebsocketClient extends EventEmitter {
|
||||
*/
|
||||
public unsubscribe(wsTopics: WsTopic[] | WsTopic, isPrivateTopic?: boolean) {
|
||||
const topics = Array.isArray(wsTopics) ? wsTopics : [wsTopics];
|
||||
topics.forEach((topic) =>
|
||||
this.wsStore.deleteTopic(
|
||||
getWsKeyForTopic(this.options.market, topic, isPrivateTopic),
|
||||
topic
|
||||
)
|
||||
);
|
||||
topics.forEach((topic) => {
|
||||
const wsKey = getWsKeyForTopic(
|
||||
this.options.market,
|
||||
topic,
|
||||
isPrivateTopic
|
||||
);
|
||||
|
||||
// Remove topic from persistence for reconnects
|
||||
this.wsStore.deleteTopic(wsKey, topic);
|
||||
|
||||
this.wsStore.getKeys().forEach((wsKey: WsKey) => {
|
||||
// unsubscribe request only necessary if active connection exists
|
||||
if (
|
||||
this.wsStore.isConnectionState(wsKey, WsConnectionStateEnum.CONNECTED)
|
||||
) {
|
||||
this.requestUnsubscribeTopics(wsKey, [
|
||||
...this.wsStore.getTopics(wsKey),
|
||||
]);
|
||||
this.requestUnsubscribeTopics(wsKey, [topic]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -12,7 +12,27 @@ describe('Private Inverse-Futures REST API GET Endpoints', () => {
|
||||
});
|
||||
|
||||
// Warning: if some of these start to fail with 10001 params error, it's probably that this future expired and a newer one exists with a different symbol!
|
||||
const symbol = 'BTCUSDU22';
|
||||
let symbol = '';
|
||||
|
||||
beforeAll(async () => {
|
||||
const symbolsResponse = await api.getSymbols();
|
||||
|
||||
const prefix = 'BTCUSD';
|
||||
|
||||
const futuresAsset = symbolsResponse.result
|
||||
.filter((row) => row.name.startsWith(prefix))
|
||||
.find((row) => {
|
||||
const splitSymbol = row.name.split(prefix);
|
||||
return splitSymbol[1] && splitSymbol[1] !== 'T';
|
||||
});
|
||||
|
||||
if (!futuresAsset?.name) {
|
||||
throw new Error('No symbol');
|
||||
}
|
||||
|
||||
symbol = futuresAsset?.name;
|
||||
console.log('Symbol: ', symbol);
|
||||
});
|
||||
|
||||
it('getApiKeyInfo()', async () => {
|
||||
expect(await api.getApiKeyInfo()).toMatchObject(successResponseObject());
|
||||
|
||||
@@ -17,7 +17,27 @@ describe('Private Inverse-Futures REST API POST Endpoints', () => {
|
||||
});
|
||||
|
||||
// Warning: if some of these start to fail with 10001 params error, it's probably that this future expired and a newer one exists with a different symbol!
|
||||
const symbol = 'BTCUSDU22';
|
||||
let symbol = '';
|
||||
|
||||
beforeAll(async () => {
|
||||
const symbolsResponse = await api.getSymbols();
|
||||
|
||||
const prefix = 'BTCUSD';
|
||||
|
||||
const futuresAsset = symbolsResponse.result
|
||||
.filter((row) => row.name.startsWith(prefix))
|
||||
.find((row) => {
|
||||
const splitSymbol = row.name.split(prefix);
|
||||
return splitSymbol[1] && splitSymbol[1] !== 'T';
|
||||
});
|
||||
|
||||
if (!futuresAsset?.name) {
|
||||
throw new Error('No symbol');
|
||||
}
|
||||
|
||||
symbol = futuresAsset?.name;
|
||||
console.log('Symbol: ', symbol);
|
||||
});
|
||||
|
||||
// These tests are primarily check auth is working by expecting balance or order not found style errors
|
||||
|
||||
@@ -134,7 +154,7 @@ describe('Private Inverse-Futures REST API POST Endpoints', () => {
|
||||
take_profit: 50000,
|
||||
})
|
||||
).toMatchObject({
|
||||
ret_code: API_ERROR_CODE.POSITION_IDX_NOT_MATCH_POSITION_MODE,
|
||||
ret_code: API_ERROR_CODE.POSITION_STATUS_NOT_NORMAL,
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ describe('Private USDC Options REST API POST Endpoints', () => {
|
||||
timeInForce: 'GoodTillCancel',
|
||||
})
|
||||
).toMatchObject({
|
||||
retCode: API_ERROR_CODE.ACCOUNT_NOT_EXIST,
|
||||
retCode: API_ERROR_CODE.CONTRACT_NAME_NOT_EXIST,
|
||||
});
|
||||
});
|
||||
|
||||
@@ -59,8 +59,8 @@ describe('Private USDC Options REST API POST Endpoints', () => {
|
||||
])
|
||||
).toMatchObject({
|
||||
result: [
|
||||
{ errorCode: API_ERROR_CODE.ACCOUNT_NOT_EXIST },
|
||||
{ errorCode: API_ERROR_CODE.ACCOUNT_NOT_EXIST },
|
||||
{ errorCode: API_ERROR_CODE.CONTRACT_NAME_NOT_EXIST },
|
||||
{ errorCode: API_ERROR_CODE.CONTRACT_NAME_NOT_EXIST },
|
||||
],
|
||||
});
|
||||
});
|
||||
@@ -72,7 +72,7 @@ describe('Private USDC Options REST API POST Endpoints', () => {
|
||||
orderId: 'somethingFake',
|
||||
})
|
||||
).toMatchObject({
|
||||
retCode: API_ERROR_CODE.ORDER_NOT_EXIST,
|
||||
retCode: API_ERROR_CODE.CONTRACT_NAME_NOT_EXIST,
|
||||
});
|
||||
});
|
||||
|
||||
@@ -90,8 +90,8 @@ describe('Private USDC Options REST API POST Endpoints', () => {
|
||||
])
|
||||
).toMatchObject({
|
||||
result: [
|
||||
{ errorCode: API_ERROR_CODE.ORDER_NOT_EXIST },
|
||||
{ errorCode: API_ERROR_CODE.ORDER_NOT_EXIST },
|
||||
{ errorCode: API_ERROR_CODE.CONTRACT_NAME_NOT_EXIST },
|
||||
{ errorCode: API_ERROR_CODE.CONTRACT_NAME_NOT_EXIST },
|
||||
],
|
||||
});
|
||||
});
|
||||
@@ -103,7 +103,7 @@ describe('Private USDC Options REST API POST Endpoints', () => {
|
||||
orderId: 'somethingFake1',
|
||||
})
|
||||
).toMatchObject({
|
||||
retCode: API_ERROR_CODE.ORDER_NOT_EXIST,
|
||||
retCode: API_ERROR_CODE.CONTRACT_NAME_NOT_EXIST,
|
||||
});
|
||||
});
|
||||
|
||||
@@ -121,8 +121,8 @@ describe('Private USDC Options REST API POST Endpoints', () => {
|
||||
])
|
||||
).toMatchObject({
|
||||
result: [
|
||||
{ errorCode: API_ERROR_CODE.ORDER_NOT_EXIST },
|
||||
{ errorCode: API_ERROR_CODE.ORDER_NOT_EXIST },
|
||||
{ errorCode: API_ERROR_CODE.CONTRACT_NAME_NOT_EXIST },
|
||||
{ errorCode: API_ERROR_CODE.CONTRACT_NAME_NOT_EXIST },
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user