initial commit, add bitget rest api and websockets connector
This commit is contained in:
111
test/broker/private.read.test.ts
Normal file
111
test/broker/private.read.test.ts
Normal file
@@ -0,0 +1,111 @@
|
||||
import { API_ERROR_CODE, BrokerClient } from '../../src';
|
||||
import { sucessEmptyResponseObject } from '../response.util';
|
||||
|
||||
describe('Private Broker REST API GET Endpoints', () => {
|
||||
const API_KEY = process.env.API_KEY_COM;
|
||||
const API_SECRET = process.env.API_SECRET_COM;
|
||||
const API_PASS = process.env.API_PASS_COM;
|
||||
|
||||
it('should have api credentials to test with', () => {
|
||||
expect(API_KEY).toStrictEqual(expect.any(String));
|
||||
expect(API_SECRET).toStrictEqual(expect.any(String));
|
||||
expect(API_PASS).toStrictEqual(expect.any(String));
|
||||
});
|
||||
|
||||
const api = new BrokerClient({
|
||||
apiKey: API_KEY,
|
||||
apiSecret: API_SECRET,
|
||||
apiPass: API_PASS,
|
||||
});
|
||||
|
||||
const coin = 'BTC';
|
||||
const subUid = '123456';
|
||||
const timestampOneHourAgo = new Date().getTime() - 1000 * 60 * 60;
|
||||
const from = timestampOneHourAgo.toFixed(0);
|
||||
const to = String(Number(from) + 1000 * 60 * 30); // 30 minutes
|
||||
|
||||
it('getBrokerInfo()', async () => {
|
||||
try {
|
||||
expect(await api.getBrokerInfo()).toMatchObject(
|
||||
sucessEmptyResponseObject()
|
||||
);
|
||||
} catch (e) {
|
||||
expect(e.body).toMatchObject({
|
||||
code: API_ERROR_CODE.ACCOUNT_NOT_BROKER,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
it('getSubAccounts()', async () => {
|
||||
try {
|
||||
expect(await api.getSubAccounts()).toMatchObject(
|
||||
sucessEmptyResponseObject()
|
||||
);
|
||||
} catch (e) {
|
||||
expect(e.body).toMatchObject({
|
||||
code: API_ERROR_CODE.ACCOUNT_NOT_BROKER,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
it('getSubEmail()', async () => {
|
||||
try {
|
||||
expect(await api.getSubEmail(subUid)).toMatchObject(
|
||||
sucessEmptyResponseObject()
|
||||
);
|
||||
} catch (e) {
|
||||
expect(e.body).toMatchObject({
|
||||
code: API_ERROR_CODE.ACCOUNT_NOT_BROKER,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
it('getSubSpotAssets()', async () => {
|
||||
try {
|
||||
expect(await api.getSubSpotAssets(subUid)).toMatchObject(
|
||||
sucessEmptyResponseObject()
|
||||
);
|
||||
} catch (e) {
|
||||
// expect(e.body).toBeNull();
|
||||
expect(e.body).toMatchObject({
|
||||
code: API_ERROR_CODE.ACCOUNT_NOT_BROKER,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
it('getSubFutureAssets()', async () => {
|
||||
try {
|
||||
expect(await api.getSubFutureAssets(subUid, 'usdt')).toMatchObject(
|
||||
sucessEmptyResponseObject()
|
||||
);
|
||||
} catch (e) {
|
||||
expect(e.body).toMatchObject({
|
||||
code: API_ERROR_CODE.ACCOUNT_NOT_BROKER,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
it('getSubDepositAddress()', async () => {
|
||||
try {
|
||||
expect(await api.getSubDepositAddress(subUid, coin)).toMatchObject(
|
||||
sucessEmptyResponseObject()
|
||||
);
|
||||
} catch (e) {
|
||||
expect(e.body).toMatchObject({
|
||||
code: API_ERROR_CODE.ACCOUNT_NOT_BROKER,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
it('getSubAPIKeys()', async () => {
|
||||
try {
|
||||
expect(await api.getSubAPIKeys(subUid)).toMatchObject(
|
||||
sucessEmptyResponseObject()
|
||||
);
|
||||
} catch (e) {
|
||||
expect(e.body).toMatchObject({
|
||||
code: API_ERROR_CODE.ACCOUNT_NOT_BROKER,
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
125
test/broker/private.write.test.ts
Normal file
125
test/broker/private.write.test.ts
Normal file
@@ -0,0 +1,125 @@
|
||||
import { API_ERROR_CODE, BrokerClient } from '../../src';
|
||||
import { sucessEmptyResponseObject } from '../response.util';
|
||||
|
||||
describe('Private Broker REST API POST Endpoints', () => {
|
||||
const API_KEY = process.env.API_KEY_COM;
|
||||
const API_SECRET = process.env.API_SECRET_COM;
|
||||
const API_PASS = process.env.API_PASS_COM;
|
||||
|
||||
it('should have api credentials to test with', () => {
|
||||
expect(API_KEY).toStrictEqual(expect.any(String));
|
||||
expect(API_SECRET).toStrictEqual(expect.any(String));
|
||||
expect(API_PASS).toStrictEqual(expect.any(String));
|
||||
});
|
||||
|
||||
const api = new BrokerClient({
|
||||
apiKey: API_KEY,
|
||||
apiSecret: API_SECRET,
|
||||
apiPass: API_PASS,
|
||||
});
|
||||
|
||||
const coin = 'BTC';
|
||||
const subUid = '123456';
|
||||
const timestampOneHourAgo = new Date().getTime() - 1000 * 60 * 60;
|
||||
const from = timestampOneHourAgo.toFixed(0);
|
||||
const to = String(Number(from) + 1000 * 60 * 30); // 30 minutes
|
||||
|
||||
it('createSubAccount()', async () => {
|
||||
try {
|
||||
expect(await api.createSubAccount('test1')).toMatchObject(
|
||||
sucessEmptyResponseObject()
|
||||
);
|
||||
} catch (e) {
|
||||
expect(e.body).toMatchObject({
|
||||
code: API_ERROR_CODE.ACCOUNT_NOT_BROKER,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
it('modifySubAccount()', async () => {
|
||||
try {
|
||||
expect(
|
||||
await api.modifySubAccount('test1', 'spot_trade,transfer', 'normal')
|
||||
).toMatchObject(sucessEmptyResponseObject());
|
||||
} catch (e) {
|
||||
expect(e.body).toMatchObject({
|
||||
code: API_ERROR_CODE.ACCOUNT_NOT_BROKER,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
it('modifySubEmail()', async () => {
|
||||
try {
|
||||
expect(
|
||||
await api.modifySubEmail('test1', 'ASDFASDF@LKMASDF.COM')
|
||||
).toMatchObject(sucessEmptyResponseObject());
|
||||
} catch (e) {
|
||||
expect(e.body).toMatchObject({
|
||||
code: API_ERROR_CODE.ACCOUNT_NOT_BROKER,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
it('subWithdrawal()', async () => {
|
||||
try {
|
||||
expect(
|
||||
await api.subWithdrawal({
|
||||
address: '123455',
|
||||
amount: '12345',
|
||||
chain: 'TRC20',
|
||||
coin: 'USDT',
|
||||
subUid,
|
||||
})
|
||||
).toMatchObject(sucessEmptyResponseObject());
|
||||
} catch (e) {
|
||||
expect(e.body).toMatchObject({
|
||||
code: API_ERROR_CODE.ACCOUNT_NOT_BROKER,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
it('setSubDepositAutoTransfer()', async () => {
|
||||
try {
|
||||
expect(
|
||||
await api.setSubDepositAutoTransfer(subUid, 'USDT', 'spot')
|
||||
).toMatchObject(sucessEmptyResponseObject());
|
||||
} catch (e) {
|
||||
expect(e.body).toMatchObject({
|
||||
code: API_ERROR_CODE.ACCOUNT_NOT_BROKER,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
it('createSubAPIKey()', async () => {
|
||||
try {
|
||||
expect(
|
||||
await api.createSubAPIKey(
|
||||
subUid,
|
||||
'passphrase12345',
|
||||
'remark',
|
||||
'10.0.0.1'
|
||||
)
|
||||
).toMatchObject(sucessEmptyResponseObject());
|
||||
} catch (e) {
|
||||
expect(e.body).toMatchObject({
|
||||
code: API_ERROR_CODE.ACCOUNT_NOT_BROKER,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
it('modifySubAPIKey()', async () => {
|
||||
try {
|
||||
expect(
|
||||
await api.modifySubAPIKey({
|
||||
apikey: '12345',
|
||||
subUid,
|
||||
remark: 'test',
|
||||
})
|
||||
).toMatchObject(sucessEmptyResponseObject());
|
||||
} catch (e) {
|
||||
expect(e.body).toMatchObject({
|
||||
code: '40017',
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
398
test/futures/private.read.test.ts
Normal file
398
test/futures/private.read.test.ts
Normal file
@@ -0,0 +1,398 @@
|
||||
import { API_ERROR_CODE, FuturesClient } from '../../src';
|
||||
import { sucessEmptyResponseObject } from '../response.util';
|
||||
|
||||
describe('Private Futures REST API GET Endpoints', () => {
|
||||
const API_KEY = process.env.API_KEY_COM;
|
||||
const API_SECRET = process.env.API_SECRET_COM;
|
||||
const API_PASS = process.env.API_PASS_COM;
|
||||
|
||||
it('should have api credentials to test with', () => {
|
||||
expect(API_KEY).toStrictEqual(expect.any(String));
|
||||
expect(API_SECRET).toStrictEqual(expect.any(String));
|
||||
expect(API_PASS).toStrictEqual(expect.any(String));
|
||||
});
|
||||
|
||||
const api = new FuturesClient({
|
||||
apiKey: API_KEY,
|
||||
apiSecret: API_SECRET,
|
||||
apiPass: API_PASS,
|
||||
});
|
||||
|
||||
const symbol = 'BTCUSDT_UMCBL';
|
||||
const marginCoin = 'USDT';
|
||||
const timestampOneHourAgo = new Date().getTime() - 1000 * 60 * 60;
|
||||
const from = timestampOneHourAgo.toFixed(0);
|
||||
const to = String(Number(from) + 1000 * 60 * 30); // 30 minutes
|
||||
|
||||
it('getAccount()', async () => {
|
||||
try {
|
||||
expect(await api.getAccount(symbol, marginCoin)).toMatchObject({
|
||||
...sucessEmptyResponseObject(),
|
||||
data: {
|
||||
available: expect.any(String),
|
||||
btcEquity: expect.any(String),
|
||||
equity: expect.any(String),
|
||||
marginCoin: expect.any(String),
|
||||
marginMode: expect.any(String),
|
||||
},
|
||||
});
|
||||
} catch (e) {
|
||||
console.error('getAccount: ', e);
|
||||
expect(e).toBeNull();
|
||||
}
|
||||
});
|
||||
|
||||
it('getAccounts()', async () => {
|
||||
try {
|
||||
expect(await api.getAccounts('umcbl')).toMatchObject({
|
||||
...sucessEmptyResponseObject(),
|
||||
data: expect.any(Array),
|
||||
});
|
||||
} catch (e) {
|
||||
console.error('getAccounts: ', e);
|
||||
expect(e).toBeNull();
|
||||
}
|
||||
});
|
||||
|
||||
it('getOpenCount()', async () => {
|
||||
try {
|
||||
expect(
|
||||
await api.getOpenCount(symbol, marginCoin, 20000, 1)
|
||||
).toMatchObject({
|
||||
...sucessEmptyResponseObject(),
|
||||
data: {
|
||||
openCount: expect.any(Number),
|
||||
},
|
||||
});
|
||||
} catch (e) {
|
||||
console.error('getOpenCount: ', e);
|
||||
expect(e).toBeNull();
|
||||
}
|
||||
});
|
||||
|
||||
it('getPosition()', async () => {
|
||||
try {
|
||||
expect(await api.getPosition(symbol, marginCoin)).toMatchObject({
|
||||
...sucessEmptyResponseObject(),
|
||||
data: expect.any(Array),
|
||||
});
|
||||
} catch (e) {
|
||||
console.error('getPosition: ', e);
|
||||
expect(e).toBeNull();
|
||||
}
|
||||
});
|
||||
|
||||
it('getPositions()', async () => {
|
||||
try {
|
||||
expect(await api.getPositions('umcbl')).toMatchObject({
|
||||
...sucessEmptyResponseObject(),
|
||||
data: expect.any(Array),
|
||||
});
|
||||
} catch (e) {
|
||||
console.error('getPosition: ', e);
|
||||
expect(e).toBeNull();
|
||||
}
|
||||
});
|
||||
|
||||
it('getAccountBill()', async () => {
|
||||
try {
|
||||
expect(
|
||||
await api.getAccountBill({
|
||||
startTime: from,
|
||||
endTime: to,
|
||||
marginCoin,
|
||||
symbol,
|
||||
})
|
||||
).toMatchObject({
|
||||
...sucessEmptyResponseObject(),
|
||||
data: {
|
||||
lastEndId: null,
|
||||
nextFlag: false,
|
||||
preFlag: false,
|
||||
result: expect.any(Array),
|
||||
},
|
||||
});
|
||||
} catch (e) {
|
||||
console.error('getAccountBill: ', e);
|
||||
expect(e).toBeNull();
|
||||
}
|
||||
});
|
||||
|
||||
it('getBusinessBill()', async () => {
|
||||
try {
|
||||
expect(
|
||||
await api.getBusinessBill({
|
||||
startTime: from,
|
||||
endTime: to,
|
||||
productType: 'umcbl',
|
||||
})
|
||||
).toMatchObject({
|
||||
...sucessEmptyResponseObject(),
|
||||
data: {
|
||||
lastEndId: null,
|
||||
nextFlag: false,
|
||||
preFlag: false,
|
||||
result: expect.any(Array),
|
||||
},
|
||||
});
|
||||
} catch (e) {
|
||||
console.error('getBusinessBill: ', e);
|
||||
expect(e).toBeNull();
|
||||
}
|
||||
});
|
||||
|
||||
it('getOpenSymbolOrders()', async () => {
|
||||
try {
|
||||
expect(await api.getOpenSymbolOrders(symbol)).toMatchObject({
|
||||
...sucessEmptyResponseObject(),
|
||||
data: expect.any(Array),
|
||||
});
|
||||
} catch (e) {
|
||||
console.error('getOpenSymbolOrders: ', e);
|
||||
expect(e).toBeNull();
|
||||
}
|
||||
});
|
||||
|
||||
it('getOpenOrders()', async () => {
|
||||
try {
|
||||
expect(await api.getOpenOrders('umcbl', marginCoin)).toMatchObject({
|
||||
...sucessEmptyResponseObject(),
|
||||
data: expect.any(Array),
|
||||
});
|
||||
} catch (e) {
|
||||
console.error('getOpenOrders: ', e);
|
||||
expect(e).toBeNull();
|
||||
}
|
||||
});
|
||||
|
||||
it('getOrderHistory()', async () => {
|
||||
try {
|
||||
expect(await api.getOrderHistory(symbol, from, to, '10')).toMatchObject({
|
||||
...sucessEmptyResponseObject(),
|
||||
data: expect.any(Object),
|
||||
});
|
||||
} catch (e) {
|
||||
console.error('getOrderHistory: ', e);
|
||||
expect(e).toBeNull();
|
||||
}
|
||||
});
|
||||
|
||||
it('getProductTypeOrderHistory()', async () => {
|
||||
try {
|
||||
expect(
|
||||
await api.getProductTypeOrderHistory('umcbl', from, to, '10')
|
||||
).toMatchObject({
|
||||
...sucessEmptyResponseObject(),
|
||||
data: expect.any(Object),
|
||||
});
|
||||
} catch (e) {
|
||||
console.error('getProductTypeOrderHistory: ', e);
|
||||
expect(e).toBeNull();
|
||||
}
|
||||
});
|
||||
|
||||
it('getOrder() should throw FUTURES_ORDER_NOT_FOUND', async () => {
|
||||
try {
|
||||
expect(await api.getOrder(symbol, '12345')).toMatchObject({
|
||||
...sucessEmptyResponseObject(),
|
||||
data: expect.any(Object),
|
||||
});
|
||||
} catch (e) {
|
||||
expect(e.body).toMatchObject({
|
||||
code: API_ERROR_CODE.FUTURES_ORDER_GET_NOT_FOUND,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
it('getOrderFills() should throw FUTURES_ORDER_NOT_FOUND', async () => {
|
||||
try {
|
||||
expect(await api.getOrderFills(symbol, '12345')).toMatchObject({
|
||||
...sucessEmptyResponseObject(),
|
||||
data: expect.any(Object),
|
||||
});
|
||||
} catch (e) {
|
||||
expect(e.body).toMatchObject({
|
||||
code: API_ERROR_CODE.FUTURES_ORDER_GET_NOT_FOUND,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
it('getProductTypeOrderFills() ', async () => {
|
||||
try {
|
||||
expect(
|
||||
await api.getProductTypeOrderFills('umcbl', {
|
||||
startTime: from,
|
||||
endTime: to,
|
||||
})
|
||||
).toMatchObject({
|
||||
...sucessEmptyResponseObject(),
|
||||
data: expect.any(Object),
|
||||
});
|
||||
} catch (e) {
|
||||
console.error('getProductTypeOrderFills: ', e);
|
||||
expect(e).toBeNull();
|
||||
}
|
||||
});
|
||||
|
||||
it('getPlanOrderTPSLs()', async () => {
|
||||
try {
|
||||
expect(await api.getPlanOrderTPSLs(symbol)).toMatchObject({
|
||||
...sucessEmptyResponseObject(),
|
||||
data: expect.any(Object),
|
||||
});
|
||||
} catch (e) {
|
||||
console.error('getPlanOrderTPSLs: ', e);
|
||||
expect(e).toBeNull();
|
||||
}
|
||||
});
|
||||
|
||||
it('getHistoricPlanOrdersTPSL()', async () => {
|
||||
try {
|
||||
expect(
|
||||
await api.getHistoricPlanOrdersTPSL({
|
||||
startTime: from,
|
||||
endTime: to,
|
||||
symbol,
|
||||
})
|
||||
).toMatchObject({
|
||||
...sucessEmptyResponseObject(),
|
||||
data: expect.any(Object),
|
||||
});
|
||||
} catch (e) {
|
||||
console.error('getHistoricPlanOrdersTPSL: ', e);
|
||||
expect(e).toBeNull();
|
||||
}
|
||||
});
|
||||
|
||||
it('getCopyTraderOpenOrder()', async () => {
|
||||
try {
|
||||
expect(
|
||||
await api.getCopyTraderOpenOrder(symbol, 'umcbl', 1, 0)
|
||||
).toMatchObject({
|
||||
...sucessEmptyResponseObject(),
|
||||
data: expect.any(Object),
|
||||
});
|
||||
} catch (e) {
|
||||
expect(e.body).toMatchObject({
|
||||
code: API_ERROR_CODE.ACCOUNT_NOT_COPY_TRADER,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
it('getCopyFollowersOpenOrder()', async () => {
|
||||
try {
|
||||
expect(
|
||||
await api.getCopyFollowersOpenOrder(symbol, 'umcbl', 1, 0)
|
||||
).toMatchObject({
|
||||
...sucessEmptyResponseObject(),
|
||||
data: expect.any(Object),
|
||||
});
|
||||
} catch (e) {
|
||||
expect(e.body).toMatchObject({
|
||||
code: API_ERROR_CODE.ACCOUNT_NOT_COPY_TRADER,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
it('getCopyTraderOrderHistory()', async () => {
|
||||
try {
|
||||
expect(await api.getCopyTraderOrderHistory(from, to, 1, 0)).toMatchObject(
|
||||
{
|
||||
...sucessEmptyResponseObject(),
|
||||
data: expect.any(Object),
|
||||
}
|
||||
);
|
||||
} catch (e) {
|
||||
expect(e.body).toMatchObject({
|
||||
code: API_ERROR_CODE.ACCOUNT_NOT_COPY_TRADER,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
it('getCopyTraderProfitSummary()', async () => {
|
||||
try {
|
||||
expect(await api.getCopyTraderProfitSummary()).toMatchObject({
|
||||
...sucessEmptyResponseObject(),
|
||||
data: expect.any(Object),
|
||||
});
|
||||
} catch (e) {
|
||||
expect(e.body).toMatchObject({
|
||||
code: API_ERROR_CODE.ACCOUNT_NOT_COPY_TRADER,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
it('getCopyTraderHistoricProfitSummary()', async () => {
|
||||
try {
|
||||
expect(await api.getCopyTraderHistoricProfitSummary()).toMatchObject({
|
||||
...sucessEmptyResponseObject(),
|
||||
data: expect.any(Object),
|
||||
});
|
||||
} catch (e) {
|
||||
expect(e.body).toMatchObject({
|
||||
code: API_ERROR_CODE.ACCOUNT_NOT_COPY_TRADER,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
it('getCopyTraderHistoricProfitSummaryByDate()', async () => {
|
||||
try {
|
||||
expect(
|
||||
await api.getCopyTraderHistoricProfitSummaryByDate(
|
||||
marginCoin,
|
||||
from,
|
||||
1,
|
||||
1
|
||||
)
|
||||
).toMatchObject({
|
||||
...sucessEmptyResponseObject(),
|
||||
data: expect.any(Object),
|
||||
});
|
||||
} catch (e) {
|
||||
expect(e.body).toMatchObject({
|
||||
code: API_ERROR_CODE.ACCOUNT_NOT_COPY_TRADER,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
it('getCopyTraderHistoricProfitDetail()', async () => {
|
||||
try {
|
||||
expect(
|
||||
await api.getCopyTraderHistoricProfitDetail(marginCoin, from, 1, 1)
|
||||
).toMatchObject({
|
||||
...sucessEmptyResponseObject(),
|
||||
data: expect.any(Object),
|
||||
});
|
||||
} catch (e) {
|
||||
expect(e.body).toMatchObject({
|
||||
code: API_ERROR_CODE.ACCOUNT_NOT_COPY_TRADER,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
it('getCopyTraderProfitDetails()', async () => {
|
||||
try {
|
||||
expect(await api.getCopyTraderProfitDetails(1, 1)).toMatchObject({
|
||||
...sucessEmptyResponseObject(),
|
||||
data: expect.any(Object),
|
||||
});
|
||||
} catch (e) {
|
||||
expect(e.body).toMatchObject({
|
||||
code: API_ERROR_CODE.ACCOUNT_NOT_COPY_TRADER,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
it('getCopyTraderSymbols()', async () => {
|
||||
try {
|
||||
expect(await api.getCopyTraderSymbols()).toMatchObject({
|
||||
...sucessEmptyResponseObject(),
|
||||
data: expect.any(Object),
|
||||
});
|
||||
} catch (e) {
|
||||
expect(e.body).toMatchObject({
|
||||
code: API_ERROR_CODE.ACCOUNT_NOT_COPY_TRADER,
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
340
test/futures/private.write.test.ts
Normal file
340
test/futures/private.write.test.ts
Normal file
@@ -0,0 +1,340 @@
|
||||
import { API_ERROR_CODE, FuturesClient } from '../../src';
|
||||
import { sucessEmptyResponseObject } from '../response.util';
|
||||
|
||||
describe('Private Futures REST API POST Endpoints', () => {
|
||||
const API_KEY = process.env.API_KEY_COM;
|
||||
const API_SECRET = process.env.API_SECRET_COM;
|
||||
const API_PASS = process.env.API_PASS_COM;
|
||||
|
||||
it('should have api credentials to test with', () => {
|
||||
expect(API_KEY).toStrictEqual(expect.any(String));
|
||||
expect(API_SECRET).toStrictEqual(expect.any(String));
|
||||
expect(API_PASS).toStrictEqual(expect.any(String));
|
||||
});
|
||||
|
||||
const api = new FuturesClient({
|
||||
apiKey: API_KEY,
|
||||
apiSecret: API_SECRET,
|
||||
apiPass: API_PASS,
|
||||
});
|
||||
|
||||
const symbol = 'BTCUSDT_UMCBL';
|
||||
const marginCoin = 'USDT';
|
||||
const timestampOneHourAgo = new Date().getTime() - 1000 * 60 * 60;
|
||||
const from = timestampOneHourAgo.toFixed(0);
|
||||
const to = String(Number(from) + 1000 * 60 * 30); // 30 minutes
|
||||
|
||||
it('setLeverage()', async () => {
|
||||
try {
|
||||
expect(await api.setLeverage(symbol, marginCoin, '20')).toMatchObject({
|
||||
...sucessEmptyResponseObject(),
|
||||
data: {},
|
||||
});
|
||||
} catch (e) {
|
||||
console.error('setLeverage: ', e);
|
||||
expect(e).toBeNull();
|
||||
}
|
||||
});
|
||||
|
||||
it('setMargin()', async () => {
|
||||
try {
|
||||
expect(await api.setMargin(symbol, marginCoin, '-10')).toMatchObject({
|
||||
...sucessEmptyResponseObject(),
|
||||
data: {},
|
||||
});
|
||||
} catch (e) {
|
||||
// expect(e).toBeNull();
|
||||
expect(e.body).toMatchObject({
|
||||
code: API_ERROR_CODE.PARAMETER_EXCEPTION,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
it('setMarginMode()', async () => {
|
||||
try {
|
||||
expect(
|
||||
await api.setMarginMode(symbol, marginCoin, 'crossed')
|
||||
).toMatchObject({
|
||||
...sucessEmptyResponseObject(),
|
||||
data: {},
|
||||
});
|
||||
} catch (e) {
|
||||
console.error('setMarginMode: ', e);
|
||||
expect(e).toBeNull();
|
||||
}
|
||||
});
|
||||
|
||||
it('submitOrder()', async () => {
|
||||
try {
|
||||
expect(
|
||||
await api.submitOrder({
|
||||
marginCoin,
|
||||
orderType: 'market',
|
||||
symbol,
|
||||
size: '1',
|
||||
side: 'open_long',
|
||||
})
|
||||
).toMatchObject({
|
||||
...sucessEmptyResponseObject(),
|
||||
data: {},
|
||||
});
|
||||
} catch (e) {
|
||||
expect(e.body).toMatchObject({
|
||||
code: API_ERROR_CODE.INSUFFICIENT_BALANCE,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
it('batchSubmitOrder()', async () => {
|
||||
try {
|
||||
expect(
|
||||
await api.batchSubmitOrder(symbol, marginCoin, [
|
||||
{
|
||||
orderType: 'market',
|
||||
size: '1',
|
||||
side: 'open_long',
|
||||
},
|
||||
])
|
||||
).toMatchObject({
|
||||
...sucessEmptyResponseObject(),
|
||||
data: {},
|
||||
});
|
||||
} catch (e) {
|
||||
expect(e.body).toMatchObject({
|
||||
code: API_ERROR_CODE.INSUFFICIENT_BALANCE,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
it('cancelOrder()', async () => {
|
||||
try {
|
||||
expect(
|
||||
await api.cancelOrder(symbol, marginCoin, '1234656')
|
||||
).toMatchObject({
|
||||
...sucessEmptyResponseObject(),
|
||||
data: {},
|
||||
});
|
||||
} catch (e) {
|
||||
expect(e.body).toMatchObject({
|
||||
code: API_ERROR_CODE.FUTURES_ORDER_CANCEL_NOT_FOUND,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
it('batchCancelOrder()', async () => {
|
||||
try {
|
||||
expect(
|
||||
await api.batchCancelOrder(symbol, marginCoin, ['1234656'])
|
||||
).toMatchObject({
|
||||
...sucessEmptyResponseObject(),
|
||||
data: {},
|
||||
});
|
||||
} catch (e) {
|
||||
console.error('batchCancelOrder: ', e);
|
||||
expect(e).toBeNull();
|
||||
}
|
||||
});
|
||||
|
||||
it('cancelAllOrders()', async () => {
|
||||
try {
|
||||
expect(await api.cancelAllOrders('umcbl', marginCoin)).toMatchObject({
|
||||
...sucessEmptyResponseObject(),
|
||||
data: {},
|
||||
});
|
||||
} catch (e) {
|
||||
console.error('cancelAllOrders: ', e);
|
||||
expect(e).toBeNull();
|
||||
}
|
||||
});
|
||||
|
||||
it('submitPlanOrder()', async () => {
|
||||
try {
|
||||
expect(
|
||||
await api.submitPlanOrder({
|
||||
marginCoin,
|
||||
orderType: 'market',
|
||||
side: 'open_long',
|
||||
size: '1',
|
||||
symbol,
|
||||
triggerPrice: '100',
|
||||
triggerType: 'market_price',
|
||||
})
|
||||
).toMatchObject({
|
||||
...sucessEmptyResponseObject(),
|
||||
data: {},
|
||||
});
|
||||
} catch (e) {
|
||||
console.error('submitPlanOrder: ', e);
|
||||
expect(e).toBeNull();
|
||||
}
|
||||
});
|
||||
|
||||
it('modifyPlanOrder()', async () => {
|
||||
try {
|
||||
expect(
|
||||
await api.modifyPlanOrder({
|
||||
orderId: '123456',
|
||||
marginCoin,
|
||||
orderType: 'market',
|
||||
symbol,
|
||||
triggerPrice: '100',
|
||||
triggerType: 'market_price',
|
||||
})
|
||||
).toMatchObject({
|
||||
...sucessEmptyResponseObject(),
|
||||
data: {},
|
||||
});
|
||||
} catch (e) {
|
||||
expect(e.body).toMatchObject({
|
||||
code: API_ERROR_CODE.PLAN_ORDER_NOT_FOUND,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
it('modifyPlanOrderTPSL()', async () => {
|
||||
try {
|
||||
expect(
|
||||
await api.modifyPlanOrderTPSL({
|
||||
orderId: '123456',
|
||||
marginCoin,
|
||||
symbol,
|
||||
presetTakeProfitPrice: '100',
|
||||
})
|
||||
).toMatchObject({
|
||||
...sucessEmptyResponseObject(),
|
||||
data: {},
|
||||
});
|
||||
} catch (e) {
|
||||
// expect(e).toBeNull();
|
||||
expect(e.body).toMatchObject({
|
||||
code: API_ERROR_CODE.SERVICE_RETURNED_ERROR,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
it('submitStopOrder()', async () => {
|
||||
try {
|
||||
expect(
|
||||
await api.submitStopOrder({
|
||||
marginCoin,
|
||||
symbol,
|
||||
planType: 'profit_plan',
|
||||
triggerPrice: '100',
|
||||
})
|
||||
).toMatchObject({
|
||||
...sucessEmptyResponseObject(),
|
||||
data: {},
|
||||
});
|
||||
} catch (e) {
|
||||
expect(e.body).toMatchObject({
|
||||
code: API_ERROR_CODE.FUTURES_POSITION_DIRECTION_EMPTY,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
it('submitPositionTPSL()', async () => {
|
||||
try {
|
||||
expect(
|
||||
await api.submitPositionTPSL({
|
||||
marginCoin,
|
||||
symbol,
|
||||
holdSide: 'long',
|
||||
planType: 'profit_plan',
|
||||
triggerPrice: '50',
|
||||
})
|
||||
).toMatchObject({
|
||||
...sucessEmptyResponseObject(),
|
||||
data: {},
|
||||
});
|
||||
} catch (e) {
|
||||
expect(e.body).toMatchObject({
|
||||
code: API_ERROR_CODE.FUTURES_POSITION_DIRECTION_EMPTY,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
it('modifyStopOrder()', async () => {
|
||||
try {
|
||||
expect(
|
||||
await api.modifyStopOrder({
|
||||
marginCoin,
|
||||
symbol,
|
||||
orderId: '123456',
|
||||
})
|
||||
).toMatchObject({
|
||||
...sucessEmptyResponseObject(),
|
||||
data: {},
|
||||
});
|
||||
} catch (e) {
|
||||
// expect(e).toBeNull();
|
||||
expect(e.body).toMatchObject({
|
||||
code: API_ERROR_CODE.FUTURES_ORDER_TPSL_NOT_FOUND,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
it('cancelPlanOrderTPSL()', async () => {
|
||||
try {
|
||||
expect(
|
||||
await api.cancelPlanOrderTPSL({
|
||||
marginCoin,
|
||||
symbol,
|
||||
orderId: '123456',
|
||||
planType: 'profit_plan',
|
||||
})
|
||||
).toMatchObject({
|
||||
...sucessEmptyResponseObject(),
|
||||
data: {},
|
||||
});
|
||||
} catch (e) {
|
||||
expect(e.body).toMatchObject({
|
||||
code: API_ERROR_CODE.FUTURES_ORDER_TPSL_NOT_FOUND,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
it('closeCopyTraderPosition()', async () => {
|
||||
try {
|
||||
expect(await api.closeCopyTraderPosition(symbol, '123456')).toMatchObject(
|
||||
{
|
||||
...sucessEmptyResponseObject(),
|
||||
data: {},
|
||||
}
|
||||
);
|
||||
} catch (e) {
|
||||
expect(e.body).toMatchObject({
|
||||
code: API_ERROR_CODE.ACCOUNT_NOT_COPY_TRADER,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
it('modifyCopyTraderTPSL()', async () => {
|
||||
try {
|
||||
expect(
|
||||
await api.modifyCopyTraderTPSL(symbol, '123456', {
|
||||
stopLossPrice: 1234,
|
||||
})
|
||||
).toMatchObject({
|
||||
...sucessEmptyResponseObject(),
|
||||
data: {},
|
||||
});
|
||||
} catch (e) {
|
||||
expect(e.body).toMatchObject({
|
||||
code: API_ERROR_CODE.ACCOUNT_NOT_COPY_TRADER,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
it('setCopyTraderSymbols()', async () => {
|
||||
try {
|
||||
expect(await api.setCopyTraderSymbols(symbol, 'delete')).toMatchObject({
|
||||
...sucessEmptyResponseObject(),
|
||||
data: {},
|
||||
});
|
||||
} catch (e) {
|
||||
expect(e.body).toMatchObject({
|
||||
code: API_ERROR_CODE.ACCOUNT_NOT_COPY_TRADER,
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
147
test/futures/public.test.ts
Normal file
147
test/futures/public.test.ts
Normal file
@@ -0,0 +1,147 @@
|
||||
import { API_ERROR_CODE, FuturesClient } from '../../src';
|
||||
import {
|
||||
notAuthenticatedError,
|
||||
successResponseString,
|
||||
sucessEmptyResponseObject,
|
||||
} from '../response.util';
|
||||
|
||||
describe('Public Spot REST API Endpoints', () => {
|
||||
const api = new FuturesClient();
|
||||
|
||||
const symbol = 'BTCUSDT_UMCBL';
|
||||
const timestampOneHourAgo = new Date().getTime() - 1000 * 60 * 60;
|
||||
const from = Number(timestampOneHourAgo.toFixed(0));
|
||||
const to = from + 1000 * 60 * 30; // 30 minutes
|
||||
|
||||
// it('should throw for unauthenticated private calls', async () => {
|
||||
// expect(() => api.getOpenOrders()).rejects.toMatchObject(
|
||||
// notAuthenticatedError()
|
||||
// );
|
||||
// expect(() => api.getBalances()).rejects.toMatchObject(
|
||||
// notAuthenticatedError()
|
||||
// );
|
||||
// });
|
||||
|
||||
/**
|
||||
*
|
||||
* Market
|
||||
*
|
||||
*/
|
||||
it('getSymbols()', async () => {
|
||||
expect(await api.getSymbols('umcbl')).toMatchObject({
|
||||
...sucessEmptyResponseObject(),
|
||||
data: expect.any(Array),
|
||||
});
|
||||
});
|
||||
|
||||
it('getDepth()', async () => {
|
||||
expect(await api.getDepth(symbol)).toMatchObject({
|
||||
...sucessEmptyResponseObject(),
|
||||
data: {
|
||||
bids: expect.any(Array),
|
||||
asks: expect.any(Array),
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('getTicker()', async () => {
|
||||
expect(await api.getTicker(symbol)).toMatchObject({
|
||||
...sucessEmptyResponseObject(),
|
||||
data: {
|
||||
bestAsk: expect.any(String),
|
||||
bestBid: expect.any(String),
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('getAllTickers()', async () => {
|
||||
expect(await api.getAllTickers('umcbl')).toMatchObject({
|
||||
...sucessEmptyResponseObject(),
|
||||
data: expect.any(Array),
|
||||
});
|
||||
});
|
||||
|
||||
it('getMarketTrades()', async () => {
|
||||
expect(await api.getMarketTrades(symbol)).toMatchObject({
|
||||
...sucessEmptyResponseObject(),
|
||||
data: expect.any(Array),
|
||||
});
|
||||
});
|
||||
|
||||
it('getCandles()', async () => {
|
||||
expect(
|
||||
await api.getCandles(symbol, '1min', `${from}`, `${to}`)
|
||||
).toMatchObject(expect.any(Array));
|
||||
});
|
||||
|
||||
it('getIndexPrice()', async () => {
|
||||
expect(await api.getIndexPrice(symbol)).toMatchObject({
|
||||
...sucessEmptyResponseObject(),
|
||||
data: {
|
||||
index: expect.any(String),
|
||||
symbol: expect.any(String),
|
||||
timestamp: expect.any(String),
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('getNextFundingTime()', async () => {
|
||||
expect(await api.getNextFundingTime(symbol)).toMatchObject({
|
||||
...sucessEmptyResponseObject(),
|
||||
data: {
|
||||
fundingTime: expect.any(String),
|
||||
symbol: expect.any(String),
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('getHistoricFundingRate()', async () => {
|
||||
expect(await api.getHistoricFundingRate(symbol)).toMatchObject({
|
||||
...sucessEmptyResponseObject(),
|
||||
data: expect.any(Array),
|
||||
});
|
||||
});
|
||||
|
||||
it('getCurrentFundingRate()', async () => {
|
||||
expect(await api.getCurrentFundingRate(symbol)).toMatchObject({
|
||||
...sucessEmptyResponseObject(),
|
||||
data: {
|
||||
fundingRate: expect.any(String),
|
||||
symbol: expect.any(String),
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('getOpenInterest()', async () => {
|
||||
expect(await api.getOpenInterest(symbol)).toMatchObject({
|
||||
...sucessEmptyResponseObject(),
|
||||
data: {
|
||||
amount: expect.any(String),
|
||||
symbol: expect.any(String),
|
||||
timestamp: expect.any(String),
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('getMarkPrice()', async () => {
|
||||
expect(await api.getMarkPrice(symbol)).toMatchObject({
|
||||
...sucessEmptyResponseObject(),
|
||||
data: {
|
||||
markPrice: expect.any(String),
|
||||
symbol: expect.any(String),
|
||||
timestamp: expect.any(String),
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('getLeverageMinMax()', async () => {
|
||||
expect(await api.getLeverageMinMax(symbol)).toMatchObject({
|
||||
...sucessEmptyResponseObject(),
|
||||
data: {
|
||||
maxLeverage: expect.any(String),
|
||||
minLeverage: expect.any(String),
|
||||
symbol: expect.any(String),
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
43
test/response.util.ts
Normal file
43
test/response.util.ts
Normal file
@@ -0,0 +1,43 @@
|
||||
import { API_ERROR_CODE } from '../src';
|
||||
|
||||
const SUCCESS_MSG_REGEX = /success/gim;
|
||||
|
||||
export function successResponseString() {
|
||||
return {
|
||||
data: expect.any(String),
|
||||
...sucessEmptyResponseObject(),
|
||||
};
|
||||
}
|
||||
|
||||
export function sucessEmptyResponseObject() {
|
||||
return {
|
||||
code: API_ERROR_CODE.SUCCESS,
|
||||
msg: expect.stringMatching(SUCCESS_MSG_REGEX),
|
||||
};
|
||||
}
|
||||
|
||||
export function errorResponseObject(
|
||||
result: null | any = null,
|
||||
ret_code: number,
|
||||
ret_msg: string
|
||||
) {
|
||||
return {
|
||||
result,
|
||||
ret_code,
|
||||
ret_msg,
|
||||
};
|
||||
}
|
||||
|
||||
export function errorResponseObjectV3(
|
||||
result: null | any = null,
|
||||
retCode: number
|
||||
) {
|
||||
return {
|
||||
result,
|
||||
retCode: retCode,
|
||||
};
|
||||
}
|
||||
|
||||
export function notAuthenticatedError() {
|
||||
return new Error('Private endpoints require api and private keys set');
|
||||
}
|
||||
161
test/spot/private.read.test.ts
Normal file
161
test/spot/private.read.test.ts
Normal file
@@ -0,0 +1,161 @@
|
||||
import { API_ERROR_CODE, SpotClient } from '../../src';
|
||||
import { sucessEmptyResponseObject } from '../response.util';
|
||||
|
||||
describe('Private Spot REST API GET Endpoints', () => {
|
||||
const API_KEY = process.env.API_KEY_COM;
|
||||
const API_SECRET = process.env.API_SECRET_COM;
|
||||
const API_PASS = process.env.API_PASS_COM;
|
||||
|
||||
it('should have api credentials to test with', () => {
|
||||
expect(API_KEY).toStrictEqual(expect.any(String));
|
||||
expect(API_SECRET).toStrictEqual(expect.any(String));
|
||||
expect(API_PASS).toStrictEqual(expect.any(String));
|
||||
});
|
||||
|
||||
const api = new SpotClient({
|
||||
apiKey: API_KEY,
|
||||
apiSecret: API_SECRET,
|
||||
apiPass: API_PASS,
|
||||
});
|
||||
|
||||
const symbol = 'BTCUSDT_SPBL';
|
||||
const coin = 'BTC';
|
||||
const timestampOneHourAgo = new Date().getTime() - 1000 * 60 * 60;
|
||||
const from = timestampOneHourAgo.toFixed(0);
|
||||
const to = String(Number(from) + 1000 * 60 * 30); // 30 minutes
|
||||
|
||||
// Seems to throw a permission error, probably because withdrawal permissions aren't set on this key (requires IP whitelist)
|
||||
it.skip('getDepositAddress()', async () => {
|
||||
try {
|
||||
expect(await api.getDepositAddress(coin)).toStrictEqual('');
|
||||
} catch (e) {
|
||||
console.error('exception: ', e);
|
||||
expect(e).toBeNull();
|
||||
}
|
||||
});
|
||||
|
||||
it('getWithdrawals()', async () => {
|
||||
try {
|
||||
expect(await api.getWithdrawals(coin, from, to)).toMatchObject({
|
||||
...sucessEmptyResponseObject(),
|
||||
data: expect.any(Array),
|
||||
});
|
||||
} catch (e) {
|
||||
console.error('getWithdrawals: ', e);
|
||||
expect(e).toBeNull();
|
||||
}
|
||||
});
|
||||
|
||||
it('getDeposits()', async () => {
|
||||
try {
|
||||
expect(await api.getDeposits(coin, from, to)).toMatchObject({
|
||||
...sucessEmptyResponseObject(),
|
||||
data: expect.any(Array),
|
||||
});
|
||||
} catch (e) {
|
||||
console.error('getDeposits: ', e);
|
||||
expect(e).toBeNull();
|
||||
}
|
||||
});
|
||||
|
||||
it('getApiKeyInfo()', async () => {
|
||||
// No auth error == test pass
|
||||
try {
|
||||
expect(await api.getApiKeyInfo()).toMatchObject({
|
||||
...sucessEmptyResponseObject(),
|
||||
data: {
|
||||
user_id: expect.any(String),
|
||||
authorities: expect.any(Array),
|
||||
},
|
||||
});
|
||||
} catch (e) {
|
||||
console.error('getApiKeyInfo: ', e);
|
||||
expect(e).toBeNull();
|
||||
}
|
||||
});
|
||||
|
||||
it('getBalance()', async () => {
|
||||
try {
|
||||
// expect(await api.getWithdrawals(coin, from, to)).toStrictEqual('');
|
||||
expect(await api.getBalance()).toMatchObject({
|
||||
...sucessEmptyResponseObject(),
|
||||
data: expect.any(Array),
|
||||
});
|
||||
} catch (e) {
|
||||
console.error('getBalance: ', e);
|
||||
expect(e).toBeNull();
|
||||
}
|
||||
});
|
||||
|
||||
it('getTransactionHistory()', async () => {
|
||||
try {
|
||||
expect(await api.getTransactionHistory()).toMatchObject({
|
||||
...sucessEmptyResponseObject(),
|
||||
data: expect.any(Array),
|
||||
});
|
||||
} catch (e) {
|
||||
console.error('getTransactionHistory: ', e);
|
||||
expect(e).toBeNull();
|
||||
}
|
||||
});
|
||||
|
||||
it('getTransferHistory()', async () => {
|
||||
try {
|
||||
expect(await api.getTransferHistory()).toMatchObject({
|
||||
...sucessEmptyResponseObject(),
|
||||
data: expect.any(Array),
|
||||
});
|
||||
} catch (e) {
|
||||
console.error('getTransferHistory: ', e);
|
||||
expect(e).toBeNull();
|
||||
}
|
||||
});
|
||||
|
||||
it('getOrder()', async () => {
|
||||
try {
|
||||
expect(await api.getOrder(symbol, '12345')).toMatchObject({
|
||||
...sucessEmptyResponseObject(),
|
||||
data: expect.any(Array),
|
||||
});
|
||||
} catch (e) {
|
||||
console.error('getOrder: ', e);
|
||||
expect(e).toBeNull();
|
||||
}
|
||||
});
|
||||
|
||||
it('getOpenOrders()', async () => {
|
||||
try {
|
||||
expect(await api.getOpenOrders()).toMatchObject({
|
||||
...sucessEmptyResponseObject(),
|
||||
data: expect.any(Array),
|
||||
});
|
||||
} catch (e) {
|
||||
console.error('getOpenOrders: ', e);
|
||||
expect(e).toBeNull();
|
||||
}
|
||||
});
|
||||
|
||||
it('getOrderHistory()', async () => {
|
||||
try {
|
||||
expect(await api.getOrderHistory(symbol)).toMatchObject({
|
||||
...sucessEmptyResponseObject(),
|
||||
data: expect.any(Array),
|
||||
});
|
||||
} catch (e) {
|
||||
console.error('getOrderHistory: ', e);
|
||||
expect(e).toBeNull();
|
||||
}
|
||||
});
|
||||
|
||||
it('getOrderFills()', async () => {
|
||||
try {
|
||||
expect(await api.getOrderFills(symbol, '12345')).toMatchObject({
|
||||
...sucessEmptyResponseObject(),
|
||||
data: expect.any(Array),
|
||||
});
|
||||
} catch (e) {
|
||||
console.error('getOrderFills: ', e);
|
||||
expect(e).toBeNull();
|
||||
}
|
||||
});
|
||||
});
|
||||
152
test/spot/private.write.test.ts
Normal file
152
test/spot/private.write.test.ts
Normal file
@@ -0,0 +1,152 @@
|
||||
import { API_ERROR_CODE, SpotClient } from '../../src';
|
||||
import { sucessEmptyResponseObject } from '../response.util';
|
||||
|
||||
describe('Private Spot REST API POST Endpoints', () => {
|
||||
const API_KEY = process.env.API_KEY_COM;
|
||||
const API_SECRET = process.env.API_SECRET_COM;
|
||||
const API_PASS = process.env.API_PASS_COM;
|
||||
|
||||
it('should have api credentials to test with', () => {
|
||||
expect(API_KEY).toStrictEqual(expect.any(String));
|
||||
expect(API_SECRET).toStrictEqual(expect.any(String));
|
||||
expect(API_PASS).toStrictEqual(expect.any(String));
|
||||
});
|
||||
|
||||
const api = new SpotClient({
|
||||
apiKey: API_KEY,
|
||||
apiSecret: API_SECRET,
|
||||
apiPass: API_PASS,
|
||||
});
|
||||
|
||||
const symbol = 'BTCUSDT_SPBL';
|
||||
const coin = 'USDT';
|
||||
const timestampOneHourAgo = new Date().getTime() - 1000 * 60 * 60;
|
||||
const from = timestampOneHourAgo.toFixed(0);
|
||||
const to = String(Number(from) + 1000 * 60 * 30); // 30 minutes
|
||||
|
||||
it('transfer()', async () => {
|
||||
try {
|
||||
expect(
|
||||
await api.transfer({
|
||||
amount: '100',
|
||||
coin,
|
||||
fromType: 'spot',
|
||||
toType: 'mix_usdt',
|
||||
})
|
||||
).toStrictEqual('');
|
||||
|
||||
// .toMatchObject({
|
||||
// // not sure what this error means, probably no balance
|
||||
// code: '42013',
|
||||
// });
|
||||
} catch (e) {
|
||||
// console.error('transfer: ', e);
|
||||
expect(e.body).toMatchObject({
|
||||
// not sure what this error means, probably no balance
|
||||
code: '42013',
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
it('withdraw()', async () => {
|
||||
try {
|
||||
expect(
|
||||
await api.withdraw({
|
||||
amount: '100',
|
||||
coin,
|
||||
chain: 'TRC20',
|
||||
address: `123456`,
|
||||
})
|
||||
).toMatchObject({
|
||||
...sucessEmptyResponseObject(),
|
||||
data: expect.any(Array),
|
||||
});
|
||||
} catch (e) {
|
||||
expect(e.body).toMatchObject({
|
||||
code: API_ERROR_CODE.INCORRECT_PERMISSIONS,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
it('innerWithdraw()', async () => {
|
||||
try {
|
||||
expect(await api.innerWithdraw(coin, '12345', '1')).toMatchObject({
|
||||
...sucessEmptyResponseObject(),
|
||||
data: expect.any(Array),
|
||||
});
|
||||
} catch (e) {
|
||||
expect(e.body).toMatchObject({
|
||||
code: API_ERROR_CODE.INCORRECT_PERMISSIONS,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
it('submitOrder()', async () => {
|
||||
try {
|
||||
expect(
|
||||
await api.submitOrder({
|
||||
symbol,
|
||||
side: 'buy',
|
||||
orderType: 'market',
|
||||
quantity: '1',
|
||||
force: 'normal',
|
||||
})
|
||||
).toMatchObject({
|
||||
...sucessEmptyResponseObject(),
|
||||
data: expect.any(Array),
|
||||
});
|
||||
} catch (e) {
|
||||
expect(e.body).toMatchObject({
|
||||
code: API_ERROR_CODE.QTY_LESS_THAN_MINIMUM,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
it('batchSubmitOrder()', async () => {
|
||||
try {
|
||||
expect(
|
||||
await api.batchSubmitOrder(symbol, [
|
||||
{
|
||||
side: 'buy',
|
||||
orderType: 'market',
|
||||
quantity: '1',
|
||||
force: 'normal',
|
||||
},
|
||||
])
|
||||
).toMatchObject({
|
||||
...sucessEmptyResponseObject(),
|
||||
data: expect.any(Array),
|
||||
});
|
||||
} catch (e) {
|
||||
expect(e.body).toMatchObject({
|
||||
code: API_ERROR_CODE.QTY_LESS_THAN_MINIMUM,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
it('cancelOrder()', async () => {
|
||||
try {
|
||||
expect(await api.cancelOrder(symbol, '123456')).toMatchObject({
|
||||
...sucessEmptyResponseObject(),
|
||||
data: expect.any(Array),
|
||||
});
|
||||
} catch (e) {
|
||||
expect(e.body).toMatchObject({
|
||||
code: API_ERROR_CODE.ORDER_NOT_FOUND,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
it('batchCancelOrder()', async () => {
|
||||
try {
|
||||
expect(await api.batchCancelOrder(symbol, ['123456'])).toMatchObject({
|
||||
...sucessEmptyResponseObject(),
|
||||
data: expect.any(Array),
|
||||
});
|
||||
} catch (e) {
|
||||
expect(e.body).toMatchObject({
|
||||
code: API_ERROR_CODE.ORDER_NOT_FOUND,
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
108
test/spot/public.test.ts
Normal file
108
test/spot/public.test.ts
Normal file
@@ -0,0 +1,108 @@
|
||||
import { API_ERROR_CODE, SpotClient } from '../../src';
|
||||
import {
|
||||
notAuthenticatedError,
|
||||
successResponseString,
|
||||
sucessEmptyResponseObject,
|
||||
} from '../response.util';
|
||||
|
||||
describe('Public Spot REST API Endpoints', () => {
|
||||
const api = new SpotClient();
|
||||
|
||||
const symbol = 'BTCUSDT_SPBL';
|
||||
const timestampOneHourAgo = new Date().getTime() / 1000 - 1000 * 60 * 60;
|
||||
const from = Number(timestampOneHourAgo.toFixed(0));
|
||||
|
||||
// it('should throw for unauthenticated private calls', async () => {
|
||||
// expect(() => api.getOpenOrders()).rejects.toMatchObject(
|
||||
// notAuthenticatedError()
|
||||
// );
|
||||
// expect(() => api.getBalances()).rejects.toMatchObject(
|
||||
// notAuthenticatedError()
|
||||
// );
|
||||
// });
|
||||
|
||||
/**
|
||||
*
|
||||
* Public
|
||||
*
|
||||
*/
|
||||
|
||||
it('getServerTime()', async () => {
|
||||
// expect(await api.getServerTime()).toStrictEqual('');
|
||||
expect(await api.getServerTime()).toMatchObject(successResponseString());
|
||||
});
|
||||
|
||||
it('fetchServertime() returns number', async () => {
|
||||
expect(await api.fetchServerTime()).toStrictEqual(expect.any(Number));
|
||||
});
|
||||
|
||||
it('getCoins()', async () => {
|
||||
expect(await api.getCoins()).toMatchObject({
|
||||
...sucessEmptyResponseObject(),
|
||||
data: expect.any(Array),
|
||||
});
|
||||
});
|
||||
|
||||
it('getSymbols()', async () => {
|
||||
expect(await api.getSymbols()).toMatchObject({
|
||||
...sucessEmptyResponseObject(),
|
||||
data: expect.any(Array),
|
||||
});
|
||||
});
|
||||
|
||||
it('getSymbol()', async () => {
|
||||
expect(await api.getSymbol(symbol)).toMatchObject({
|
||||
...sucessEmptyResponseObject(),
|
||||
data: {
|
||||
baseCoin: expect.any(String),
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
*
|
||||
* Market
|
||||
*
|
||||
*/
|
||||
|
||||
it('getTicker()', async () => {
|
||||
expect(await api.getTicker(symbol)).toMatchObject({
|
||||
...sucessEmptyResponseObject(),
|
||||
data: {
|
||||
askSz: expect.any(String),
|
||||
baseVol: expect.any(String),
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('getAllTickers()', async () => {
|
||||
expect(await api.getAllTickers()).toMatchObject({
|
||||
...sucessEmptyResponseObject(),
|
||||
data: expect.any(Array),
|
||||
});
|
||||
});
|
||||
|
||||
it('getMarketTrades()', async () => {
|
||||
expect(await api.getMarketTrades(symbol)).toMatchObject({
|
||||
...sucessEmptyResponseObject(),
|
||||
data: expect.any(Array),
|
||||
});
|
||||
});
|
||||
|
||||
it('getCandles()', async () => {
|
||||
expect(await api.getCandles(symbol, '1min')).toMatchObject({
|
||||
...sucessEmptyResponseObject(),
|
||||
data: expect.any(Array),
|
||||
});
|
||||
});
|
||||
|
||||
it('getDepth()', async () => {
|
||||
expect(await api.getDepth(symbol, 'step0')).toMatchObject({
|
||||
...sucessEmptyResponseObject(),
|
||||
data: {
|
||||
bids: expect.any(Array),
|
||||
asks: expect.any(Array),
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
110
test/ws.private.test.ts
Normal file
110
test/ws.private.test.ts
Normal file
@@ -0,0 +1,110 @@
|
||||
import {
|
||||
WebsocketClient,
|
||||
WSClientConfigurableOptions,
|
||||
WS_ERROR_ENUM,
|
||||
WS_KEY_MAP,
|
||||
} from '../src';
|
||||
import { getSilentLogger, waitForSocketEvent } from './ws.util';
|
||||
|
||||
describe('Private Spot Websocket Client', () => {
|
||||
const API_KEY = process.env.API_KEY_COM;
|
||||
const API_SECRET = process.env.API_SECRET_COM;
|
||||
const API_PASS = process.env.API_PASS_COM;
|
||||
|
||||
const wsClientOptions: WSClientConfigurableOptions = {
|
||||
apiKey: API_KEY,
|
||||
apiSecret: API_SECRET,
|
||||
apiPass: API_PASS,
|
||||
};
|
||||
|
||||
describe('with invalid credentials', () => {
|
||||
it('should reject private subscribe if keys/signature are incorrect', async () => {
|
||||
const badClient = new WebsocketClient(
|
||||
{
|
||||
...wsClientOptions,
|
||||
apiKey: 'bad',
|
||||
apiSecret: 'bad',
|
||||
apiPass: 'bad',
|
||||
},
|
||||
getSilentLogger('expect401')
|
||||
);
|
||||
|
||||
// const wsOpenPromise = waitForSocketEvent(badClient, 'open');
|
||||
const wsResponsePromise = waitForSocketEvent(badClient, 'response');
|
||||
// const wsUpdatePromise = waitForSocketEvent(wsClient, 'update');
|
||||
|
||||
badClient.subscribeTopic('SPBL', 'account');
|
||||
|
||||
expect(wsResponsePromise).rejects.toMatchObject({
|
||||
code: WS_ERROR_ENUM.INVALID_ACCESS_KEY,
|
||||
wsKey: WS_KEY_MAP.spotv1,
|
||||
event: 'error',
|
||||
});
|
||||
|
||||
try {
|
||||
await Promise.all([wsResponsePromise]);
|
||||
} catch (e) {
|
||||
// console.error()
|
||||
}
|
||||
badClient.closeAll();
|
||||
});
|
||||
});
|
||||
|
||||
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));
|
||||
expect(API_PASS).toStrictEqual(expect.any(String));
|
||||
});
|
||||
|
||||
beforeAll(() => {
|
||||
wsClient = new WebsocketClient(
|
||||
wsClientOptions,
|
||||
getSilentLogger('expectSuccess')
|
||||
);
|
||||
wsClient.connectAll();
|
||||
// logAllEvents(wsClient);
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
wsClient.closeAll();
|
||||
});
|
||||
|
||||
it('should successfully authenticate a private ws connection', async () => {
|
||||
const wsOpenPromise = waitForSocketEvent(wsClient, 'open');
|
||||
const wsResponsePromise = waitForSocketEvent(wsClient, 'response');
|
||||
|
||||
try {
|
||||
expect(await wsOpenPromise).toMatchObject({});
|
||||
} catch (e) {
|
||||
expect(e).toBeFalsy();
|
||||
}
|
||||
|
||||
try {
|
||||
expect(await wsResponsePromise).toMatchObject({
|
||||
code: 0,
|
||||
event: 'login',
|
||||
});
|
||||
} catch (e) {
|
||||
console.error(`Wait for "books" subscription response exception: `, e);
|
||||
expect(e).toBeFalsy();
|
||||
}
|
||||
});
|
||||
|
||||
it('should subscribe to private account events and get a snapshot', async () => {
|
||||
const wsUpdatePromise = waitForSocketEvent(wsClient, 'update');
|
||||
|
||||
const channel = 'account';
|
||||
wsClient.subscribeTopic('SPBL', channel);
|
||||
|
||||
expect(await wsUpdatePromise).toMatchObject({
|
||||
action: 'snapshot',
|
||||
arg: {
|
||||
channel: channel,
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
74
test/ws.public.test.ts
Normal file
74
test/ws.public.test.ts
Normal file
@@ -0,0 +1,74 @@
|
||||
import {
|
||||
WebsocketClient,
|
||||
WSClientConfigurableOptions,
|
||||
WS_KEY_MAP,
|
||||
} from '../src';
|
||||
import { logAllEvents, getSilentLogger, waitForSocketEvent } from './ws.util';
|
||||
|
||||
describe('Public Spot Websocket Client', () => {
|
||||
let wsClient: WebsocketClient;
|
||||
|
||||
const wsClientOptions: WSClientConfigurableOptions = {};
|
||||
|
||||
beforeAll(() => {
|
||||
wsClient = new WebsocketClient(
|
||||
wsClientOptions,
|
||||
getSilentLogger('expectSuccess')
|
||||
);
|
||||
wsClient.connectAll();
|
||||
logAllEvents(wsClient);
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
wsClient.closeAll();
|
||||
});
|
||||
|
||||
it('should open a public ws connection', async () => {
|
||||
const wsOpenPromise = waitForSocketEvent(wsClient, 'open');
|
||||
|
||||
try {
|
||||
expect(await wsOpenPromise).toMatchObject({
|
||||
wsKey: expect.any(String),
|
||||
});
|
||||
} catch (e) {
|
||||
expect(e).toBeFalsy();
|
||||
}
|
||||
});
|
||||
|
||||
it('should subscribe to public orderbook events and get a snapshot', async () => {
|
||||
const wsResponsePromise = waitForSocketEvent(wsClient, 'response');
|
||||
const wsUpdatePromise = waitForSocketEvent(wsClient, 'update');
|
||||
|
||||
const symbol = 'BTCUSDT';
|
||||
|
||||
wsClient.subscribeTopic('SP', 'books', symbol);
|
||||
|
||||
try {
|
||||
expect(await wsResponsePromise).toMatchObject({
|
||||
arg: { channel: 'books', instId: symbol, instType: expect.any(String) },
|
||||
event: 'subscribe',
|
||||
wsKey: WS_KEY_MAP.spotv1,
|
||||
});
|
||||
} catch (e) {
|
||||
console.error(`Wait for "books" subscription response exception: `, e);
|
||||
expect(e).toBeFalsy();
|
||||
}
|
||||
|
||||
try {
|
||||
expect(await wsUpdatePromise).toMatchObject({
|
||||
action: 'snapshot',
|
||||
arg: { channel: 'books', instId: 'BTCUSDT', instType: 'sp' },
|
||||
data: [
|
||||
{
|
||||
asks: expect.any(Array),
|
||||
bids: expect.any(Array),
|
||||
},
|
||||
],
|
||||
wsKey: 'spotv1',
|
||||
});
|
||||
} catch (e) {
|
||||
console.error(`Wait for "books" event exception: `, e);
|
||||
expect(e).toBeFalsy();
|
||||
}
|
||||
});
|
||||
});
|
||||
128
test/ws.util.ts
Normal file
128
test/ws.util.ts
Normal file
@@ -0,0 +1,128 @@
|
||||
import { WebsocketClient, WsClientEvent } from '../src';
|
||||
|
||||
export function getSilentLogger(logHint?: string) {
|
||||
return {
|
||||
silly: () => {},
|
||||
debug: () => {},
|
||||
notice: () => {},
|
||||
info: () => {},
|
||||
warning: () => {},
|
||||
error: () => {},
|
||||
};
|
||||
}
|
||||
|
||||
export const fullLogger = {
|
||||
silly: (...params) => console.log('silly', ...params),
|
||||
debug: (...params) => console.log('debug', ...params),
|
||||
notice: (...params) => console.log('notice', ...params),
|
||||
info: (...params) => console.info('info', ...params),
|
||||
warning: (...params) => console.warn('warning', ...params),
|
||||
error: (...params) => console.error('error', ...params),
|
||||
};
|
||||
|
||||
/** Resolves a promise if an event is seen before a timeout (defaults to 4.5 seconds) */
|
||||
export function waitForSocketEvent(
|
||||
wsClient: WebsocketClient,
|
||||
event: WsClientEvent,
|
||||
timeoutMs: number = 4.5 * 1000
|
||||
) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const timeout = setTimeout(() => {
|
||||
reject(
|
||||
`Failed to receive "${event}" event before timeout. Check that these are correct: topic, api keys (if private), signature process (if private)`
|
||||
);
|
||||
}, timeoutMs);
|
||||
|
||||
let resolvedOnce = false;
|
||||
|
||||
function cleanup() {
|
||||
clearTimeout(timeout);
|
||||
resolvedOnce = true;
|
||||
wsClient.removeListener(event, (e) => resolver(e));
|
||||
wsClient.removeListener('error', (e) => rejector(e));
|
||||
}
|
||||
|
||||
function resolver(event) {
|
||||
resolve(event);
|
||||
cleanup();
|
||||
}
|
||||
|
||||
function rejector(event) {
|
||||
if (!resolvedOnce) {
|
||||
reject(event);
|
||||
}
|
||||
cleanup();
|
||||
}
|
||||
|
||||
wsClient.on(event, (e) => resolver(e));
|
||||
wsClient.on('exception', (e) => rejector(e));
|
||||
|
||||
// if (event !== 'close') {
|
||||
// wsClient.on('close', (event) => {
|
||||
// clearTimeout(timeout);
|
||||
|
||||
// if (!resolvedOnce) {
|
||||
// reject(event);
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
});
|
||||
}
|
||||
|
||||
export function listenToSocketEvents(wsClient: WebsocketClient) {
|
||||
const retVal: Record<
|
||||
'update' | 'open' | 'response' | 'close' | 'error',
|
||||
typeof jest.fn
|
||||
> = {
|
||||
open: jest.fn(),
|
||||
response: jest.fn(),
|
||||
update: jest.fn(),
|
||||
close: jest.fn(),
|
||||
error: jest.fn(),
|
||||
};
|
||||
|
||||
wsClient.on('open', retVal.open);
|
||||
wsClient.on('response', retVal.response);
|
||||
wsClient.on('update', retVal.update);
|
||||
wsClient.on('close', retVal.close);
|
||||
wsClient.on('exception', retVal.error);
|
||||
|
||||
return {
|
||||
...retVal,
|
||||
cleanup: () => {
|
||||
wsClient.removeListener('open', retVal.open);
|
||||
wsClient.removeListener('response', retVal.response);
|
||||
wsClient.removeListener('update', retVal.update);
|
||||
wsClient.removeListener('close', retVal.close);
|
||||
wsClient.removeListener('exception', retVal.error);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export function logAllEvents(wsClient: WebsocketClient) {
|
||||
wsClient.on('update', (data) => {
|
||||
// console.log('wsUpdate: ', JSON.stringify(data, null, 2));
|
||||
});
|
||||
|
||||
wsClient.on('open', (data) => {
|
||||
console.log('wsOpen: ', data.wsKey);
|
||||
});
|
||||
wsClient.on('response', (data) => {
|
||||
console.log('wsResponse ', JSON.stringify(data, null, 2));
|
||||
});
|
||||
wsClient.on('reconnect', ({ wsKey }) => {
|
||||
console.log('wsReconnecting ', wsKey);
|
||||
});
|
||||
wsClient.on('reconnected', (data) => {
|
||||
console.log('wsReconnected ', data?.wsKey);
|
||||
});
|
||||
wsClient.on('close', (data) => {
|
||||
// console.log('wsClose: ', data);
|
||||
});
|
||||
}
|
||||
|
||||
export function promiseSleep(ms: number) {
|
||||
return new Promise((resolve, reject) => {
|
||||
setTimeout(resolve, ms);
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user