diff --git a/README.md b/README.md index 95086d4..52a5852 100644 --- a/README.md +++ b/README.md @@ -51,19 +51,19 @@ This connector is fully compatible with both TypeScript and pure JavaScript proj --- ## REST API Clients Each REST API group has a dedicated REST client. To avoid confusion, here are the available REST clients and the corresponding API groups: -| Class | Description | -|:------------------------------------------------------------------: |:-----------------------------------------------------------------------------------------------------------: | -| [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) | -| [InverseFuturesClient](src/inverse-futures-client.ts) | [Inverse Futures (v2) APIs](https://bybit-exchange.github.io/docs/futuresV2/inverse_futures/#t-introduction) | -| [SpotClientV3](src/spot-client-v3.ts) | [Spot Market (v3) APIs](https://bybit-exchange.github.io/docs/spot/v3/#t-introduction) | -| [~SpotClient~](src/spot-client.ts) (deprecated, v3 client recommended)| [Spot Market (v1) APIs](https://bybit-exchange.github.io/docs/spot/v1/#t-introduction) | -| [AccountAssetClient](src/account-asset-client.ts) | [Account Asset APIs](https://bybit-exchange.github.io/docs/account_asset/#t-introduction) | -| [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) | -| [CopyTradingClient](src/copy-trading-client.ts) | [Copy Trading APIs](https://bybit-exchange.github.io/docs/copy_trading/#t-introduction) | -| Derivatives V3 unified margin | Under Development | -| [WebsocketClient](src/websocket-client.ts) | All WebSocket Events (Public & Private for all API categories) | +| Class | Description | +|:------------------------------------------------------------------: |:----------------------------------------------------------------------------------------------------------------------------: | +| [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) | +| [InverseFuturesClient](src/inverse-futures-client.ts) | [Inverse Futures (v2) APIs](https://bybit-exchange.github.io/docs/futuresV2/inverse_futures/#t-introduction) | +| [USDCPerpetualClient](src/usdc-perpetual-client.ts) | [USDC Perpetual APIs](https://bybit-exchange.github.io/docs/usdc/option/?console#t-querydeliverylog) | +| [UnifiedMarginClient](src/unified-margin-client.ts) | [Derivatives (v3) unified margin APIs](https://bybit-exchange.github.io/docs/derivativesV3/unified_margin/#t-introduction) | +| [USDCOptionClient](src/usdc-option-client.ts) | [USDC Option APIs](https://bybit-exchange.github.io/docs/usdc/option/#t-introduction) | +| [SpotClientV3](src/spot-client-v3.ts) | [Spot Market (v3) APIs](https://bybit-exchange.github.io/docs/spot/v3/#t-introduction) | +| [~SpotClient~](src/spot-client.ts) (deprecated, v3 client recommended)| [Spot Market (v1) APIs](https://bybit-exchange.github.io/docs/spot/v1/#t-introduction) | +| [AccountAssetClient](src/account-asset-client.ts) | [Account Asset APIs](https://bybit-exchange.github.io/docs/account_asset/#t-introduction) | +| [CopyTradingClient](src/copy-trading-client.ts) | [Copy Trading APIs](https://bybit-exchange.github.io/docs/copy_trading/#t-introduction) | +| [WebsocketClient](src/websocket-client.ts) | All WebSocket Events (Public & Private for all API categories) | Examples for using each client can be found in: - the [examples](./examples) folder. diff --git a/src/types/request/index.ts b/src/types/request/index.ts index 77aaef5..8ee5bfd 100644 --- a/src/types/request/index.ts +++ b/src/types/request/index.ts @@ -5,3 +5,4 @@ export * from './usdt-perp'; export * from './usdc-perp'; export * from './usdc-options'; export * from './usdc-shared'; +export * from './unified-margin'; diff --git a/src/types/request/unified-margin.ts b/src/types/request/unified-margin.ts new file mode 100644 index 0000000..29c8e74 --- /dev/null +++ b/src/types/request/unified-margin.ts @@ -0,0 +1,247 @@ +import { KlineIntervalV3, OrderSide } from '../shared'; +import { USDCOrderFilter, USDCTimeInForce } from './usdc-shared'; + +export type UMCategory = 'linear' | 'inverse' | 'option'; +export type UMOrderType = 'Limit' | 'Market'; +export type UMDirection = 'prev' | 'next'; + +export interface UMCandlesRequest { + category: UMCategory; + symbol: string; + interval: KlineIntervalV3; + start: number; + end: number; + limit?: number; +} + +export interface UMInstrumentInfoRequest { + category: UMCategory; + symbol?: string; + baseCoin?: string; + limit?: string; + cursor?: string; +} + +export interface UMFundingRateHistoryRequest { + category: UMCategory; + symbol: string; + startTime?: number; + endTime?: number; + limit?: number; +} + +export interface UMOptionDeliveryPriceRequest { + category: UMCategory; + symbol?: string; + baseCoin?: string; + direction?: UMDirection; + limit?: string; + cursor?: string; +} + +export interface UMPublicTradesRequest { + category: UMCategory; + symbol: string; + baseCoin?: string; + optionType?: 'Call' | 'Put'; + limit?: string; +} + +export interface UMOpenInterestRequest { + category: UMCategory; + symbol: string; + interval: '5min' | '15min' | '30min' | '1h' | '4h' | '1d'; + startTime?: number; + endTime?: number; + limit?: number; +} + +export interface UMOrderRequest { + category: UMCategory; + symbol: string; + side: OrderSide; + positionIdx?: '0'; + orderType: UMOrderType; + qty: string; + price?: string; + basePrice?: string; + triggerPrice?: string; + triggerBy?: string; + iv?: string; + timeInForce: USDCTimeInForce; + orderLinkId?: string; + takeProfit?: number; + stopLoss?: number; + tpTriggerBy?: string; + slTriggerBy?: string; + reduceOnly?: boolean; + closeOnTrigger?: boolean; + mmp?: boolean; +} + +export interface UMModifyOrderRequest { + category: UMCategory; + symbol: string; + orderId?: string; + orderLinkId?: string; + iv?: string; + triggerPrice?: string; + qty?: string; + price?: string; + takeProfit?: number; + stopLoss?: number; + tpTriggerBy?: string; + slTriggerBy?: string; + triggerBy?: string; +} + +export interface UMCancelOrderRequest { + category: UMCategory; + symbol: string; + orderId?: string; + orderLinkId?: string; + orderFilter?: USDCOrderFilter; +} + +export interface UMActiveOrdersRequest { + category: UMCategory; + symbol?: string; + baseCoin?: string; + orderId?: string; + orderLinkId?: string; + orderFilter?: USDCOrderFilter; + direction?: UMDirection; + limit?: number; + cursor?: string; +} + +export interface UMHistoricOrdersRequest { + category: UMCategory; + symbol?: string; + baseCoin?: string; + orderId?: string; + orderLinkId?: string; + orderStatus?: string; + orderFilter?: USDCOrderFilter; + direction?: UMDirection; + limit?: number; + cursor?: string; +} + +export interface UMBatchOrder { + symbol: string; + side: OrderSide; + positionIdx?: '0'; + orderType: UMOrderType; + qty: string; + price?: string; + iv?: string; + timeInForce: USDCTimeInForce; + orderLinkId?: string; + reduceOnly?: boolean; + closeOnTrigger?: boolean; + mmp?: boolean; +} + +export interface UMBatchOrderReplace { + symbol: string; + orderId?: string; + orderLinkId?: string; + iv?: string; + qty?: string; + price?: string; +} + +export interface UMBatchOrderCancel { + symbol: string; + orderId?: string; + orderLinkId?: string; +} + +export interface UMCancelAllOrdersRequest { + category: UMCategory; + baseCoin?: string; + settleCoin?: string; + symbol?: string; + orderFilter?: USDCOrderFilter; +} + +export interface UMPositionsRequest { + category: UMCategory; + symbol?: string; + baseCoin?: string; + direction?: UMDirection; + limit?: number; + cursor?: string; +} + +export interface UMSetTPSLRequest { + category: UMCategory; + symbol: string; + takeProfit?: string; + stopLoss?: string; + trailingStop?: string; + tpTriggerBy?: string; + slTriggerBy?: string; + activePrice?: string; + slSize?: string; + tpSize?: string; + positionIdx?: '0'; +} + +export interface UM7DayTradingHistoryRequest { + category: UMCategory; + symbol: string; + baseCoin?: string; + orderId?: string; + orderLinkId?: string; + startTime?: number; + endTime?: number; + direction?: UMDirection; + limit?: number; + cursor?: string; + execType?: string; +} + +export interface UMOptionsSettlementHistoryRequest { + category: UMCategory; + symbol: string; + expDate?: string; + direction?: UMDirection; + limit?: number; + cursor?: string; +} + +export interface UMPerpSettlementHistoryRequest { + category: UMCategory; + symbol: string; + direction?: UMDirection; + limit?: number; + cursor?: string; +} + +export interface UMTransactionLogRequest { + category: UMCategory; + currency: string; + baseCoin?: string; + type?: string; + startTime?: number; + endTime?: number; + direction?: UMDirection; + limit?: number; + cursor?: string; +} + +export interface UMExchangeCoinsRequest { + fromCoin?: string; + toCoin?: string; +} + +export interface UMBorrowHistoryRequest { + currency: string; + startTime?: number; + endTime?: number; + direction?: UMDirection; + limit?: number; + cursor?: string; +} diff --git a/src/types/request/usdc-perp.ts b/src/types/request/usdc-perp.ts index 6f77789..553109a 100644 --- a/src/types/request/usdc-perp.ts +++ b/src/types/request/usdc-perp.ts @@ -1,5 +1,10 @@ import { OrderSide } from '../shared'; -import { USDCAPICategory, USDCOrderType, USDCTimeInForce } from './usdc-shared'; +import { + USDCAPICategory, + USDCOrderFilter, + USDCOrderType, + USDCTimeInForce, +} from './usdc-shared'; export interface USDCOpenInterestRequest { symbol: string; @@ -27,8 +32,6 @@ export interface USDCSymbolDirectionLimitCursor { cursor?: string; } -export type USDCOrderFilter = 'Order' | 'StopOrder'; - export interface USDCPerpOrderRequest { symbol: string; orderType: USDCOrderType; diff --git a/src/types/request/usdc-shared.ts b/src/types/request/usdc-shared.ts index f8faf59..4c388c2 100644 --- a/src/types/request/usdc-shared.ts +++ b/src/types/request/usdc-shared.ts @@ -1,12 +1,15 @@ export type USDCAPICategory = 'PERPETUAL' | 'OPTION'; export type USDCOrderType = 'Limit' | 'Market'; + export type USDCTimeInForce = | 'GoodTillCancel' | 'ImmediateOrCancel' | 'FillOrKill' | 'PostOnly'; +export type USDCOrderFilter = 'Order' | 'StopOrder'; + export interface USDCKlineRequest { symbol: string; period: string; diff --git a/src/types/shared.ts b/src/types/shared.ts index fdb7ced..88f465a 100644 --- a/src/types/shared.ts +++ b/src/types/shared.ts @@ -17,6 +17,21 @@ export type KlineInterval = | '1w' | '1M'; +export type KlineIntervalV3 = + | '1' + | '3' + | '5' + | '15' + | '30' + | '60' + | '120' + | '240' + | '360' + | '720' + | 'D' + | 'W' + | 'M'; + export interface APIResponse { ret_code: number; ret_msg: 'OK' | string; diff --git a/src/unified-margin-client.ts b/src/unified-margin-client.ts new file mode 100644 index 0000000..9c5b045 --- /dev/null +++ b/src/unified-margin-client.ts @@ -0,0 +1,391 @@ +import { + APIResponseWithTime, + APIResponseV3, + UMCategory, + UMCandlesRequest, + UMInstrumentInfoRequest, + UMFundingRateHistoryRequest, + UMOptionDeliveryPriceRequest, + UMPublicTradesRequest, + UMOpenInterestRequest, + UMOrderRequest, + UMModifyOrderRequest, + UMCancelOrderRequest, + UMActiveOrdersRequest, + UMHistoricOrdersRequest, + UMBatchOrder, + UMBatchOrderReplace, + UMBatchOrderCancel, + UMCancelAllOrdersRequest, + UMPositionsRequest, + UMSetTPSLRequest, + UM7DayTradingHistoryRequest, + UMOptionsSettlementHistoryRequest, + UMPerpSettlementHistoryRequest, + UMTransactionLogRequest, + InternalTransferRequest, + UMExchangeCoinsRequest, + UMBorrowHistoryRequest, +} from './types'; +import { REST_CLIENT_TYPE_ENUM } from './util'; +import BaseRestClient from './util/BaseRestClient'; + +/** + * REST API client for Derivatives V3 unified margin APIs + */ +export class UnifiedMarginClient extends BaseRestClient { + getClientType() { + return REST_CLIENT_TYPE_ENUM.v3; + } + + async fetchServerTime(): Promise { + const res = await this.getServerTime(); + return Number(res.time_now); + } + + /** + * + * Market Data Endpoints + * + */ + + /** Query order book info. Each side has a depth of 25 orders. */ + getOrderBook( + symbol: string, + category?: string, + limit?: number + ): Promise> { + return this.get('/derivatives/v3/public/order-book/L2', { + category, + symbol, + limit, + }); + } + + /** Get candles/klines */ + getCandles(params: UMCandlesRequest): Promise> { + return this.get('/derivatives/v3/public/kline', params); + } + + /** Get a symbol price/statistics ticker */ + getSymbolTicker( + category: UMCategory, + symbol?: string + ): Promise> { + return this.get('/derivatives/v3/public/tickers', { category, symbol }); + } + + /** Get trading rules per symbol/contract, incl price/amount/value/leverage filters */ + getInstrumentInfo( + params: UMInstrumentInfoRequest + ): Promise> { + return this.get('/derivatives/v3/public/instruments-info', params); + } + + /** Query mark price kline (like getCandles() but for mark price). */ + getMarkPriceCandles(params: UMCandlesRequest): Promise> { + return this.get('/derivatives/v3/public/mark-price-kline', params); + } + + /** Query Index Price Kline */ + getIndexPriceCandles(params: UMCandlesRequest): Promise> { + return this.get('/derivatives/v3/public/index-price-kline', params); + } + + /** + * The funding rate is generated every 8 hours at 00:00 UTC, 08:00 UTC and 16:00 UTC. + * For example, if a request is sent at 12:00 UTC, the funding rate generated earlier that day at 08:00 UTC will be sent. + */ + getFundingRateHistory( + params: UMFundingRateHistoryRequest + ): Promise> { + return this.get( + '/derivatives/v3/public/funding/history-funding-rate', + params + ); + } + + /** Get Risk Limit */ + getRiskLimit( + category: UMCategory, + symbol: string + ): Promise> { + return this.get('/derivatives/v3/public/risk-limit/list', { + category, + symbol, + }); + } + + /** Get option delivery price */ + getOptionDeliveryPrice( + params: UMOptionDeliveryPriceRequest + ): Promise> { + return this.get('/derivatives/v3/public/delivery-price', params); + } + + /** Get recent trades */ + getTrades(params: UMPublicTradesRequest): Promise> { + return this.get('/derivatives/v3/public/recent-trade', params); + } + + /** + * Gets the total amount of unsettled contracts. + * In other words, the total number of contracts held in open positions. + */ + getOpenInterest(params: UMOpenInterestRequest): Promise> { + return this.get('/derivatives/v3/public/open-interest', params); + } + + /** + * + * Unified Margin Account Endpoints + * + */ + + /** -> Order API */ + + /** Place an order */ + submitOrder(params: UMOrderRequest): Promise> { + return this.postPrivate('/unified/v3/private/order/create', params); + } + + /** Active order parameters (such as quantity, price) and stop order parameters cannot be modified in one request at the same time. Please request modification separately. */ + modifyOrder(params: UMModifyOrderRequest): Promise> { + return this.postPrivate('/unified/v3/private/order/replace', params); + } + + /** Cancel order */ + cancelOrder(params: UMCancelOrderRequest): Promise> { + return this.postPrivate('/unified/v3/private/order/cancel', params); + } + + /** Query Open Orders */ + getActiveOrders(params: UMActiveOrdersRequest): Promise> { + return this.getPrivate('/unified/v3/private/order/unfilled-orders', params); + } + + /** Query order history. As order creation/cancellation is asynchronous, the data returned from the interface may be delayed. To access order information in real-time, call getActiveOrders() */ + getHistoricOrders( + params: UMHistoricOrdersRequest + ): Promise> { + return this.getPrivate('/unified/v3/private/order/list', params); + } + + /** + * This API provides the batch order mode under the unified margin account. + * Max 10 per request + */ + batchSubmitOrders( + category: UMCategory, + orders: UMBatchOrder[] + ): Promise> { + return this.postPrivate('/unified/v3/private/order/create-batch', { + category, + request: orders, + }); + } + + /** + * This interface can modify the open order information in batches. + * Currently, it is not supported to modify the conditional order information. + * Please note that only unfilled or partial filled orders can be modified. + * If both futures and options orders are in one request, only the orders matching the category will be operated according to the category type + */ + batchReplaceOrders( + category: UMCategory, + orders: UMBatchOrderReplace[] + ): Promise> { + return this.postPrivate('/unified/v3/private/order/replace-batch', { + category, + request: orders, + }); + } + + /** + * This API provides batch cancellation under the unified margin account. + * Order cancellation of futures and options cannot be canceled in one request at the same time. + * If both futures and options orders are in one request, only the orders matching the category will be operated according to the category type. + */ + batchCancelOrders( + category: UMCategory, + orders: UMBatchOrderCancel[] + ): Promise> { + return this.postPrivate('/unified/v3/private/order/cancel-batch', { + category, + request: orders, + }); + } + + /** + * This API provides the cancellation of all open orders under the unified margin account. + * Order cancellation of futures and options cannot be canceled in one request at the same time. + * If both futures and options orders are in one request, only the orders matching the category will be operated according to the category type. + */ + cancelAllOrders( + params: UMCancelAllOrdersRequest + ): Promise> { + return this.postPrivate('/unified/v3/private/order/cancel-all', params); + } + + /** -> Positions API */ + + /** + * Query my positions real-time. Accessing personal list of positions. + * Users can access their position holding information through this interface, such as the number of position holdings and wallet balance. + */ + getPositions(params: UMPositionsRequest): Promise> { + return this.postPrivate('/unified/v3/private/position/list', params); + } + + /** Leverage setting. */ + setLeverage( + category: UMCategory, + symbol: string, + buyLeverage: number, + sellLeverage: number + ): Promise> { + return this.postPrivate('/unified/v3/private/position/set-leverage', { + category, + symbol, + buyLeverage, + sellLeverage, + }); + } + + /** + * Switching the TP/SL mode to the cross margin mode or selected positions. + * When you set the TP/SL mode on the selected positions, the quantity of take-profit or stop-loss orders can be smaller than the position size. Please use Trading-Stop endpoint. + */ + setTPSLMode( + category: UMCategory, + symbol: string, + tpSlMode: 1 | 0 + ): Promise> { + return this.postPrivate('/unified/v3/private/position/tpsl/switch-mode', { + category, + symbol, + tpSlMode, + }); + } + + /** Set risk limit */ + setRiskLimit( + category: UMCategory, + symbol: string, + riskId: number, + positionIdx: number + ): Promise> { + return this.postPrivate('/unified/v3/private/position/set-risk-limit', { + category, + symbol, + riskId, + positionIdx, + }); + } + + /** + * Set position TP/SL and trailing stop. + * Pass the following parameters, then the system will create conditional orders. + * If the position is closed, the system will cancel these orders, and adjust the position size. + */ + setTPSL(params: UMSetTPSLRequest): Promise> { + return this.postPrivate( + '/unified/v3/private/position/trading-stop', + params + ); + } + + /** + * Access the user's filled history, ranked by time in descending order. + * There might be multiple filled histories for an order. + */ + get7DayTradingHistory( + params: UM7DayTradingHistoryRequest + ): Promise> { + return this.getPrivate('/unified/v3/private/execution/list', params); + } + + /** Query the settlement history, ranked by time in descending order. */ + getOptionsSettlementHistory( + params: UMOptionsSettlementHistoryRequest + ): Promise> { + return this.getPrivate('/unified/v3/private/delivery-record', params); + } + + /** Query session settlement records, only for USDC perpetual */ + getUSDCPerpetualSettlementHistory( + params: UMPerpSettlementHistoryRequest + ): Promise> { + return this.getPrivate('/unified/v3/private/settlement-record', params); + } + + /** -> Account API */ + + /** Query wallet balance */ + getBalances(coin?: string): Promise> { + return this.getPrivate('/unified/v3/private/account/wallet/balance', { + coin, + }); + } + + /** Upgrade to unified margin account */ + upgradeToUnifiedMargin(): Promise> { + return this.postPrivate( + '/unified/v3/private/account/upgrade-unified-account' + ); + } + + /** Query trading history */ + getTransactionLog( + params: UMTransactionLogRequest + ): Promise> { + return this.getPrivate( + '/unified/v3/private/account/transaction-log', + params + ); + } + + /** Fund transfer between accounts (v2) */ + transferFunds(params: InternalTransferRequest): Promise> { + return this.postPrivate('/asset/v1/private/transfer', params); + } + + /** Exchange Coins */ + exchangeCoins(params?: UMExchangeCoinsRequest): Promise> { + return this.getPrivate( + '/asset/v2/private/exchange/exchange-order-all', + params + ); + } + + /** Get Borrow History */ + getBorrowHistory( + params?: UMBorrowHistoryRequest + ): Promise> { + return this.getPrivate( + '/unified/v3/private/account/borrow-history', + params + ); + } + + /** Get Borrow Rate */ + getBorrowRate(currency?: string): Promise> { + return this.getPrivate('/unified/v3/private/account/borrow-rate', { + currency, + }); + } + + /** + * + * API Data Endpoints + * + */ + + getServerTime(): Promise { + return this.get('/v2/public/time'); + } + + getAnnouncements(): Promise> { + return this.get('/v2/public/announcement'); + } +} diff --git a/src/util/BaseRestClient.ts b/src/util/BaseRestClient.ts index 6b9ad75..b5a7a13 100644 --- a/src/util/BaseRestClient.ts +++ b/src/util/BaseRestClient.ts @@ -270,7 +270,7 @@ export default abstract class BaseRestClient { params?: any, isPublicApi?: boolean ): Promise { - // Sanity check to make sure it's only ever signed by + // Sanity check to make sure it's only ever prefixed by one forward slash const requestUrl = [this.baseUrl, endpoint].join( endpoint.startsWith('/') ? '' : '/' );