diff --git a/src/index.ts b/src/index.ts index df2faad..941d3ea 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,10 +1,11 @@ -export * from "./inverse-client"; -export * from "./inverse-futures-client"; -export * from "./linear-client"; -export * from "./spot-client"; -export * from "./websocket-client"; -export * from "./logger"; -export * from "./types/shared"; -export * from "./types/spot"; -export * from "./util/WsStore"; -export * from "./constants/enum"; +export * from './inverse-client'; +export * from './inverse-futures-client'; +export * from './linear-client'; +export * from './spot-client'; +export * from './websocket-client'; +export * from './logger'; +export * from './types/shared'; +export * from './types/spot'; +export * from './util/WsStore'; +export * from './util/enum'; +export * from './constants/enum'; diff --git a/src/inverse-client.ts b/src/inverse-client.ts index f2f706e..0dbd297 100644 --- a/src/inverse-client.ts +++ b/src/inverse-client.ts @@ -7,11 +7,9 @@ import { } from './util/requestUtils'; import RequestWrapper from './util/requestWrapper'; import { - APIResponse, APIResponseWithTime, AssetExchangeRecordsReq, CoinParam, - SymbolFromLimitParam, SymbolInfo, SymbolIntervalFromLimitParam, SymbolLimitParam, @@ -382,10 +380,6 @@ export class InverseClient extends BaseRestClient { return this.getPrivate('v2/private/trade/closed-pnl/list', params); } - setPositionMode(params: { symbol: string; mode: 0 | 3 }): GenericAPIResponse { - return this.requestWrapper.post('v2/private/position/switch-mode', params); - } - setSlTpPositionMode(params: { symbol: string; tp_sl_mode: 'Full' | 'Partial'; diff --git a/src/util/BaseRestClient.ts b/src/util/BaseRestClient.ts index 4d0c957..e9296cc 100644 --- a/src/util/BaseRestClient.ts +++ b/src/util/BaseRestClient.ts @@ -131,8 +131,7 @@ export default abstract class BaseRestClient { await this.syncTime(); } - const signedRequest = await this.signRequest(params); - return signedRequest; + return this.signRequest(params); } /** diff --git a/src/util/enum.ts b/src/util/enum.ts new file mode 100644 index 0000000..a0072e2 --- /dev/null +++ b/src/util/enum.ts @@ -0,0 +1,12 @@ +export const API_ERROR_CODE = { + ORDER_NOT_FOUND_OR_TOO_LATE: 20001, + CANNOT_SET_TRADING_STOP_FOR_ZERO_POS: 30024, + /** Seen when placing an order */ + INSUFFICIENT_BALANCE_FOR_ORDER_COST: 30031, + /** Seen if a conditional order is too large */ + INSUFFICIENT_BALANCE: 30042, + /** E.g. trying to change position margin while on cross */ + POSITION_IS_CROSS_MARGIN: 30056, + RISK_LIMIT_NOT_EXISTS: 30090, + SAME_SLTP_MODE: 37002, +} as const; diff --git a/test/inverse/private.read.test.ts b/test/inverse/private.read.test.ts index 349db3e..12301c1 100644 --- a/test/inverse/private.read.test.ts +++ b/test/inverse/private.read.test.ts @@ -17,91 +17,87 @@ describe('Private Inverse REST API Endpoints', () => { const symbol = 'BTCUSD'; - describe('Inverse only private GET endpoints', () => { - it('getApiKeyInfo()', async () => { - expect(await api.getApiKeyInfo()).toMatchObject(successResponseObject()); - }); + it('getApiKeyInfo()', async () => { + expect(await api.getApiKeyInfo()).toMatchObject(successResponseObject()); + }); - it('getWalletBalance()', async () => { - expect(await api.getWalletBalance()).toMatchObject( - successResponseObject() - ); - }); + it('getWalletBalance()', async () => { + expect(await api.getWalletBalance()).toMatchObject(successResponseObject()); + }); - it('getWalletFundRecords()', async () => { - expect(await api.getWalletFundRecords()).toMatchObject( - successResponseObject() - ); - }); + it('getWalletFundRecords()', async () => { + expect(await api.getWalletFundRecords()).toMatchObject( + successResponseObject() + ); + }); - it('getWithdrawRecords()', async () => { - expect(await api.getWithdrawRecords()).toMatchObject( - successResponseObject() - ); - }); + it('getWithdrawRecords()', async () => { + expect(await api.getWithdrawRecords()).toMatchObject( + successResponseObject() + ); + }); - it('getAssetExchangeRecords()', async () => { - expect(await api.getAssetExchangeRecords()).toMatchObject( - successResponseList() - ); - }); + it('getAssetExchangeRecords()', async () => { + expect(await api.getAssetExchangeRecords()).toMatchObject( + successResponseList() + ); + }); - it('getActiveOrderList()', async () => { - expect(await api.getActiveOrderList({ symbol: symbol })).toMatchObject( - successResponseObject() - ); - }); + it('getActiveOrderList()', async () => { + expect(await api.getActiveOrderList({ symbol: symbol })).toMatchObject( + successResponseObject() + ); + }); - it('queryActiveOrder()', async () => { - expect(await api.queryActiveOrder({ symbol: symbol })).toMatchObject( - successResponseObject() - ); - }); + it('queryActiveOrder()', async () => { + expect(await api.queryActiveOrder({ symbol: symbol })).toMatchObject( + successResponseObject() + ); + }); - it('getConditionalOrder()', async () => { - expect(await api.getConditionalOrder({ symbol: symbol })).toMatchObject( - successResponseObject() - ); - }); + it('getConditionalOrder()', async () => { + expect(await api.getConditionalOrder({ symbol: symbol })).toMatchObject( + successResponseObject() + ); + }); - it('queryConditionalOrder()', async () => { - expect(await api.queryConditionalOrder({ symbol: symbol })).toMatchObject( - successResponseObject() - ); - }); + it('queryConditionalOrder()', async () => { + expect(await api.queryConditionalOrder({ symbol: symbol })).toMatchObject( + successResponseObject() + ); + }); - it('getPosition()', async () => { - expect(await api.getPosition()).toMatchObject(successResponseObject()); - }); + it('getPosition()', async () => { + expect(await api.getPosition()).toMatchObject(successResponseObject()); + }); - it('getTradeRecords()', async () => { - expect(await api.getTradeRecords({ symbol: symbol })).toMatchObject( - successResponseObject() - ); - }); + it('getTradeRecords()', async () => { + expect(await api.getTradeRecords({ symbol: symbol })).toMatchObject( + successResponseObject() + ); + }); - it('getRiskLimitList()', async () => { - expect(await api.getRiskLimitList()).toMatchObject( - successResponseList('ok') - ); - }); + it('getRiskLimitList()', async () => { + expect(await api.getRiskLimitList()).toMatchObject( + successResponseList('ok') + ); + }); - it('getClosedPnl()', async () => { - expect(await api.getClosedPnl({ symbol: symbol })).toMatchObject( - successResponseObject() - ); - }); + it('getClosedPnl()', async () => { + expect(await api.getClosedPnl({ symbol: symbol })).toMatchObject( + successResponseObject() + ); + }); - it('getMyLastFundingFee()', async () => { - expect(await api.getMyLastFundingFee({ symbol: symbol })).toMatchObject( - successResponseObject() - ); - }); + it('getMyLastFundingFee()', async () => { + expect(await api.getMyLastFundingFee({ symbol: symbol })).toMatchObject( + successResponseObject() + ); + }); - it('getLcpInfo()', async () => { - expect(await api.getLcpInfo({ symbol: symbol })).toMatchObject( - successResponseObject() - ); - }); + it('getLcpInfo()', async () => { + expect(await api.getLcpInfo({ symbol: symbol })).toMatchObject( + successResponseObject() + ); }); }); diff --git a/test/inverse/private.write.test.ts b/test/inverse/private.write.test.ts new file mode 100644 index 0000000..8577c3d --- /dev/null +++ b/test/inverse/private.write.test.ts @@ -0,0 +1,193 @@ +import { InverseClient } from '../../src/inverse-client'; +import { API_ERROR_CODE } from '../../src/util/enum'; +import { successResponseList, successResponseObject } from '../response.util'; + +describe('Private Inverse REST API Endpoints', () => { + const useLivenet = true; + 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 InverseClient(API_KEY, API_SECRET, useLivenet, { + disable_time_sync: true, + }); + + const symbol = 'BTCUSD'; + + // These tests are primarily check auth is working by expecting balance or order not found style errors + + it('placeActiveOrder()', async () => { + expect( + await api.placeActiveOrder({ + side: 'Buy', + symbol, + order_type: 'Limit', + price: 30000, + qty: 1, + time_in_force: 'GoodTillCancel', + }) + ).toMatchObject({ + ret_code: API_ERROR_CODE.INSUFFICIENT_BALANCE_FOR_ORDER_COST, + }); + }); + + it('cancelActiveOrder()', async () => { + expect( + await api.cancelActiveOrder({ + symbol, + }) + ).toMatchObject({ + ret_code: API_ERROR_CODE.ORDER_NOT_FOUND_OR_TOO_LATE, + ret_msg: 'order not exists or too late to cancel', + }); + }); + + it('cancelAllActiveOrders()', async () => { + expect( + await api.cancelAllActiveOrders({ + symbol, + }) + ).toMatchObject(successResponseObject()); + }); + + it('replaceActiveOrder()', async () => { + expect( + await api.replaceActiveOrder({ + symbol, + order_id: '123123123', + p_r_qty: 1, + p_r_price: '30000', + }) + ).toMatchObject({ + ret_code: API_ERROR_CODE.ORDER_NOT_FOUND_OR_TOO_LATE, + ret_msg: 'order not exists or too late to replace', + }); + }); + + it('placeConditionalOrder()', async () => { + expect( + await api.placeConditionalOrder({ + order_type: 'Limit', + side: 'Buy', + symbol, + qty: '1', + price: '8100', + base_price: '8300', + stop_px: '8150', + time_in_force: 'GoodTillCancel', + order_link_id: 'cus_order_id_1', + }) + ).toMatchObject({ + ret_code: API_ERROR_CODE.INSUFFICIENT_BALANCE, + ret_msg: 'Insufficient wallet balance', + }); + }); + + it('cancelConditionalOrder()', async () => { + expect( + await api.cancelConditionalOrder({ + symbol, + order_link_id: 'lkasmdflasd', + }) + ).toMatchObject({ + ret_code: API_ERROR_CODE.ORDER_NOT_FOUND_OR_TOO_LATE, + ret_msg: 'order not exists or too late to cancel', + }); + }); + + it('cancelAllConditionalOrders()', async () => { + expect( + await api.cancelAllConditionalOrders({ + symbol, + }) + ).toMatchObject(successResponseObject()); + }); + + it('replaceConditionalOrder()', async () => { + expect( + await api.replaceConditionalOrder({ + symbol, + p_r_price: '50000', + p_r_qty: 1, + }) + ).toMatchObject({ + ret_code: API_ERROR_CODE.ORDER_NOT_FOUND_OR_TOO_LATE, + ret_msg: 'order not exists or too late to replace', + }); + }); + + it('changePositionMargin()', async () => { + expect( + await api.changePositionMargin({ + symbol, + margin: '10', + }) + ).toMatchObject({ + ret_code: API_ERROR_CODE.POSITION_IS_CROSS_MARGIN, + ret_msg: 'position is in crossMargin', + }); + }); + + it('setTradingStop()', async () => { + expect( + await api.setTradingStop({ + symbol, + take_profit: 5555, + }) + ).toMatchObject({ + ret_code: API_ERROR_CODE.CANNOT_SET_TRADING_STOP_FOR_ZERO_POS, + ret_msg: 'can not set tp/sl/ts for zero position', + }); + }); + + it('setUserLeverage()', async () => { + expect( + await api.setUserLeverage({ + symbol, + leverage: 5, + }) + ).toMatchObject({ + result: 5, + ret_code: 0, + }); + }); + + it('setSlTpPositionMode()', async () => { + expect( + await api.setSlTpPositionMode({ + symbol, + tp_sl_mode: 'Full', + }) + ).toMatchObject({ + ret_code: API_ERROR_CODE.SAME_SLTP_MODE, + ret_msg: 'same tp sl mode2', + }); + }); + + it('setMarginType()', async () => { + expect( + await api.setMarginType({ + symbol, + is_isolated: false, + buy_leverage: 5, + sell_leverage: 5, + }) + ).toMatchObject(successResponseObject()); + }); + + it('setRiskLimit()', async () => { + expect( + await api.setRiskLimit({ + symbol, + risk_id: 'myriskid', + }) + ).toMatchObject({ + ret_code: API_ERROR_CODE.RISK_LIMIT_NOT_EXISTS, + ret_msg: 'risk limit not exists', + }); + }); +});