From a1c0887417d3b4d13482c98e8c1f90d40b237f07 Mon Sep 17 00:00:00 2001 From: tiagosiebler Date: Fri, 9 Sep 2022 15:26:47 +0100 Subject: [PATCH] copy trading API --- .github/workflows/npmpublish.yml | 12 +- src/constants/enum.ts | 1 + src/copy-trading-client.ts | 157 +++++++++++++++++++++++++ src/index.ts | 3 +- src/types/request/copy-trading.ts | 53 +++++++++ src/types/request/index.ts | 1 + src/util/WsStore.ts | 6 +- src/util/index.ts | 1 + src/{ => util}/logger.ts | 0 src/websocket-client.ts | 2 +- test/copy-trading/private.read.test.ts | 36 ++++++ test/copy-trading/public.read.test.ts | 26 ++++ 12 files changed, 282 insertions(+), 16 deletions(-) create mode 100644 src/copy-trading-client.ts create mode 100644 src/types/request/copy-trading.ts rename src/{ => util}/logger.ts (100%) create mode 100644 test/copy-trading/private.read.test.ts create mode 100644 test/copy-trading/public.read.test.ts diff --git a/.github/workflows/npmpublish.yml b/.github/workflows/npmpublish.yml index 7bbb04e..813e3f5 100644 --- a/.github/workflows/npmpublish.yml +++ b/.github/workflows/npmpublish.yml @@ -9,16 +9,6 @@ on: - master jobs: - build: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - uses: actions/setup-node@v1 - with: - node-version: 12 - #- run: npm ci - #- run: npm test - publish-npm: needs: build runs-on: ubuntu-latest @@ -37,7 +27,7 @@ jobs: - uses: actions/setup-node@v1 if: steps.version-updated.outputs.has-updated with: - node-version: 12 + node-version: 16 registry-url: https://registry.npmjs.org/ - run: npm ci --ignore-scripts diff --git a/src/constants/enum.ts b/src/constants/enum.ts index 18b23d9..3ef8f6b 100644 --- a/src/constants/enum.ts +++ b/src/constants/enum.ts @@ -16,6 +16,7 @@ export const API_ERROR_CODE = { SUCCESS: 0, /** This could mean bad request, incorrect value types or even incorrect/missing values */ PARAMS_MISSING_OR_WRONG: 10001, + INCORRECT_API_KEY_PERMISSIONS: 10005, ORDER_NOT_FOUND_OR_TOO_LATE: 20001, POSITION_STATUS_NOT_NORMAL: 30013, CANNOT_SET_TRADING_STOP_FOR_ZERO_POS: 30024, diff --git a/src/copy-trading-client.ts b/src/copy-trading-client.ts new file mode 100644 index 0000000..0ffe176 --- /dev/null +++ b/src/copy-trading-client.ts @@ -0,0 +1,157 @@ +import { + APIResponseWithTime, + CopyTradingCancelOrderRequest, + CopyTradingCloseOrderRequest, + CopyTradingOrderListRequest, + CopyTradingOrderRequest, + CopyTradingTradingStopRequest, + CopyTradingTransferRequest, + USDCAPIResponse, +} from './types'; +import { REST_CLIENT_TYPE_ENUM } from './util'; +import BaseRestClient from './util/BaseRestClient'; + +/** + * REST API client for USDC Perpetual APIs + */ +export class CopyTradingClient extends BaseRestClient { + getClientType() { + // Follows the same authentication mechanism as USDC APIs + return REST_CLIENT_TYPE_ENUM.usdc; + } + + async fetchServerTime(): Promise { + const res = await this.getServerTime(); + return Number(res.time_now); + } + + /** + * + * Market Data Endpoints + * + */ + + getSymbolList(): Promise> { + return this.get('/contract/v3/public/copytrading/symbol/list'); + } + + /** + * + * Account Data Endpoints + * + */ + + /** -> Order API */ + + /** Create order */ + submitOrder(params: CopyTradingOrderRequest): Promise> { + return this.postPrivate( + '/contract/v3/private/copytrading/order/create', + params + ); + } + + /** Set Trading Stop */ + setTradingStop( + params: CopyTradingTradingStopRequest + ): Promise> { + return this.postPrivate( + '/contract/v3/private/copytrading/order/trading-stop', + params + ); + } + + /** Query Order List */ + getActiveOrders( + params?: CopyTradingOrderListRequest + ): Promise> { + return this.getPrivate( + '/contract/v3/private/copytrading/order/list', + params + ); + } + + /** Cancel order */ + cancelOrder( + params: CopyTradingCancelOrderRequest + ): Promise> { + return this.postPrivate( + '/contract/v3/private/copytrading/order/cancel', + params + ); + } + + /** Close Order. This endpoint's rate_limit will decrease by 10 per request; ie, one request to this endpoint consumes 10 from the limit allowed per minute. */ + closeOrder( + params: CopyTradingCloseOrderRequest + ): Promise> { + return this.postPrivate('/contract/v3/private/copytrading/order/close', { + params, + }); + } + + /** -> Positions API */ + + /** Position List */ + getPositions(symbol?: string): Promise> { + return this.getPrivate('/contract/v3/private/copytrading/position/list', { + symbol, + }); + } + + /** Close Position */ + closePosition( + symbol: string, + positionIdx: string + ): Promise> { + return this.postPrivate('/contract/v3/private/copytrading/position/close', { + symbol, + positionIdx, + }); + } + + /** Only integers can be set to set the leverage */ + setLeverage( + symbol: string, + buyLeverage: string, + sellLeverage: string + ): Promise> { + return this.postPrivate( + '/contract/v3/private/copytrading/position/set-leverage', + { symbol, buyLeverage, sellLeverage } + ); + } + + /** + * + * Wallet Data Endpoints + * + */ + + /** Get Wallet Balance */ + getBalance(): Promise> { + return this.getPrivate('/contract/v3/private/copytrading/wallet/balance'); + } + + /** Transfer */ + transfer(params: CopyTradingTransferRequest): Promise> { + return this.postPrivate( + '/contract/v3/private/copytrading/wallet/transfer', + params + ); + } + + /** + * + * API Data Endpoints + * + */ + + getServerTime(): Promise { + return this.get('/v2/public/time'); + } + + getAnnouncements(): Promise> { + return this.get('/v2/public/announcement'); + } +} diff --git a/src/index.ts b/src/index.ts index 78627e2..1336734 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,4 +1,5 @@ export * from './account-asset-client'; +export * from './copy-trading-client'; export * from './inverse-client'; export * from './inverse-futures-client'; export * from './linear-client'; @@ -6,7 +7,7 @@ export * from './spot-client'; export * from './usdc-option-client'; export * from './usdc-perpetual-client'; export * from './websocket-client'; -export * from './logger'; +export * from './util/logger'; export * from './types'; export * from './util/WsStore'; export * from './constants/enum'; diff --git a/src/types/request/copy-trading.ts b/src/types/request/copy-trading.ts new file mode 100644 index 0000000..d61200e --- /dev/null +++ b/src/types/request/copy-trading.ts @@ -0,0 +1,53 @@ +import { OrderSide } from '../shared'; +import { USDCOrderType } from './usdc-shared'; + +export interface CopyTradingOrderRequest { + side: OrderSide; + symbol: string; + orderType: USDCOrderType; + price: string; + qty: string; + takeProfit?: string; + stopLoss?: string; + tpTriggerBy?: string; + slTriggerBy?: string; + orderLinkId?: string; +} + +export interface CopyTradingTradingStopRequest { + symbol: string; + parentOrderId: string; + takeProfit?: string; + stopLoss?: string; + tpTriggerBy?: string; + slTriggerBy?: string; + parentOrderLinkId?: string; +} + +export interface CopyTradingOrderListRequest { + symbol?: string; + orderId?: string; + orderLinkId?: string; + copyTradeOrderType?: string; +} + +export interface CopyTradingCancelOrderRequest { + symbol: string; + orderId?: string; + orderLinkId?: string; +} + +export interface CopyTradingCloseOrderRequest { + symbol: string; + orderLinkId?: string; + parentOrderId?: string; + parentOrderLinkId?: string; +} + +export interface CopyTradingTransferRequest { + transferId: string; + coin: string; + amount: string; + fromAccountType: string; + toAccountType: string; +} diff --git a/src/types/request/index.ts b/src/types/request/index.ts index 2b797e3..e80dc2f 100644 --- a/src/types/request/index.ts +++ b/src/types/request/index.ts @@ -1,4 +1,5 @@ export * from './account-asset'; +export * from './copy-trading'; export * from './usdt-perp'; export * from './usdc-perp'; export * from './usdc-options'; diff --git a/src/util/WsStore.ts b/src/util/WsStore.ts index 995106c..dd7360e 100644 --- a/src/util/WsStore.ts +++ b/src/util/WsStore.ts @@ -1,8 +1,8 @@ -import { WsConnectionState } from '../websocket-client'; -import { DefaultLogger } from '../logger'; - import WebSocket from 'isomorphic-ws'; +import { WsConnectionState } from '../websocket-client'; +import { DefaultLogger } from './logger'; + type WsTopic = string; type WsTopicList = Set; diff --git a/src/util/index.ts b/src/util/index.ts index 90c60e3..e25bf42 100644 --- a/src/util/index.ts +++ b/src/util/index.ts @@ -1,3 +1,4 @@ export * from './BaseRestClient'; export * from './requestUtils'; export * from './WsStore'; +export * from './logger'; diff --git a/src/logger.ts b/src/util/logger.ts similarity index 100% rename from src/logger.ts rename to src/util/logger.ts diff --git a/src/websocket-client.ts b/src/websocket-client.ts index 939058c..c8dd784 100644 --- a/src/websocket-client.ts +++ b/src/websocket-client.ts @@ -3,7 +3,7 @@ import WebSocket from 'isomorphic-ws'; import { InverseClient } from './inverse-client'; import { LinearClient } from './linear-client'; -import { DefaultLogger } from './logger'; +import { DefaultLogger } from './util/logger'; import { SpotClient } from './spot-client'; import { KlineInterval } from './types/shared'; import { signMessage } from './util/node-support'; diff --git a/test/copy-trading/private.read.test.ts b/test/copy-trading/private.read.test.ts new file mode 100644 index 0000000..f33c5e7 --- /dev/null +++ b/test/copy-trading/private.read.test.ts @@ -0,0 +1,36 @@ +import { API_ERROR_CODE, CopyTradingClient } from '../../src'; +import { successResponseObject } from '../response.util'; + +describe('Private Copy Trading 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 CopyTradingClient(API_KEY, API_SECRET, useLivenet); + + // Don't have copy trading properly enabled on the test account, so testing is very light + // (just make sure auth works and endpoint doesn't throw) + + it('getActiveOrders()', async () => { + expect(await api.getActiveOrders()).toMatchObject({ + retCode: API_ERROR_CODE.INCORRECT_API_KEY_PERMISSIONS, + }); + }); + + it('getPositions()', async () => { + expect(await api.getPositions()).toMatchObject({ + retCode: API_ERROR_CODE.INCORRECT_API_KEY_PERMISSIONS, + }); + }); + + it('getBalance()', async () => { + expect(await api.getBalance()).toMatchObject({ + retCode: API_ERROR_CODE.INCORRECT_API_KEY_PERMISSIONS, + }); + }); +}); diff --git a/test/copy-trading/public.read.test.ts b/test/copy-trading/public.read.test.ts new file mode 100644 index 0000000..89c24bb --- /dev/null +++ b/test/copy-trading/public.read.test.ts @@ -0,0 +1,26 @@ +import { CopyTradingClient } from '../../src'; +import { successResponseObject } from '../response.util'; + +describe('Public Copy Trading REST API Endpoints', () => { + const useLivenet = true; + const API_KEY = undefined; + const API_SECRET = undefined; + + const api = new CopyTradingClient(API_KEY, API_SECRET, useLivenet); + + it('getSymbolList()', async () => { + expect(await api.getSymbolList()).toMatchObject({ + result: { + list: expect.any(Array), + }, + }); + }); + + it('getServerTime()', async () => { + expect(await api.getServerTime()).toMatchObject(successResponseObject()); + }); + + it('getAnnouncements()', async () => { + expect(await api.getAnnouncements()).toMatchObject(successResponseObject()); + }); +});