From 5b44e31207b0335c798a41dc8cc8fba2d3e52566 Mon Sep 17 00:00:00 2001 From: tiagosiebler Date: Tue, 14 Feb 2023 17:31:11 +0000 Subject: [PATCH] v3.5.0: feat(): add market endpoints for v5 REST APIs, with tests --- package.json | 2 +- src/index.ts | 1 + src/rest-client-v5.ts | 222 ++++++++++++++++++ src/types/index.ts | 1 + src/types/request/index.ts | 1 + src/types/request/v5-market.ts | 120 ++++++++++ src/types/response/v5-market.ts | 298 ++++++++++++++++++++++++ src/types/v5-shared.ts | 1 + test/rest-client-v5/public.read.test.ts | 153 ++++++++++++ 9 files changed, 798 insertions(+), 1 deletion(-) create mode 100644 src/rest-client-v5.ts create mode 100644 src/types/request/v5-market.ts create mode 100644 src/types/response/v5-market.ts create mode 100644 src/types/v5-shared.ts create mode 100644 test/rest-client-v5/public.read.test.ts diff --git a/package.json b/package.json index 8e839a4..dbc484e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "bybit-api", - "version": "3.4.0", + "version": "3.5.0", "description": "Complete & robust node.js SDK for Bybit's REST APIs and WebSockets, with TypeScript & integration tests.", "main": "lib/index.js", "types": "lib/index.d.ts", diff --git a/src/index.ts b/src/index.ts index 1ef28bb..c93f1d3 100644 --- a/src/index.ts +++ b/src/index.ts @@ -4,6 +4,7 @@ export * from './copy-trading-client'; export * from './inverse-client'; export * from './inverse-futures-client'; export * from './linear-client'; +export * from './rest-client-v5'; export * from './spot-client'; export * from './spot-client-v3'; export * from './usdc-option-client'; diff --git a/src/rest-client-v5.ts b/src/rest-client-v5.ts new file mode 100644 index 0000000..8bd3a62 --- /dev/null +++ b/src/rest-client-v5.ts @@ -0,0 +1,222 @@ +import { + APIResponseV3WithTime, + APIResponseWithTime, + CategoryV5, + GetFundingRateHistoryParamsV5, + GetHistoricalVolatilityParamsV5, + GetIndexPriceKlineParamsV5, + GetInstrumentsInfoParamsV5, + GetInsuranceParamsV5, + GetKlineParamsV5, + GetMarkPriceKlineParamsV5, + GetOpenInterestParamsV5, + GetOptionDeliveryPriceParamsV5, + GetOrderbookParamsV5, + GetPremiumIndexPriceKlineParams, + GetPublicTradingHistoryParamsV5, + GetRiskLimitParamsV5, + GetTickersParamsV5, +} from './types'; +import { + CategoryListV5, + FundingRateHistoryResponseV5, + HistoricalVolatilityV5, + IndexPriceKlineResponseV5, + InstrumentInfoV5, + InsuranceResponseV5, + KlineResponseV5, + MarkPriceKlineResponseV5, + OpenInterestResponseV5, + OptionDeliveryPriceResponseV5, + OrderbookResponseV5, + PaginatedListV5, + PremiumIndexPriceKlineResponse, + PublicTradeV5, + RiskLimitV5, + TickersLinearInverseResponseV5, + TickersOptionResponseV5, + TickersSpotResponseV5, +} from './types/response/v5-market'; +import { REST_CLIENT_TYPE_ENUM } from './util'; +import BaseRestClient from './util/BaseRestClient'; + +/** + * REST API client for V5 REST APIs + * https://bybit-exchange.github.io/docs/v5/intro + */ +export class RestClientV5 extends BaseRestClient { + getClientType() { + return REST_CLIENT_TYPE_ENUM.v3; + } + + async fetchServerTime(): Promise { + const res = await this.getServerTime(); + return Number(res.time); + } + + getServerTime(): Promise< + APIResponseV3WithTime<{ timeSecond: string; timeNano: string }> + > { + return this.get('/v3/public/time'); + } + + /** + * + * Market APIs + * + */ + + /** + * Query the kline data. Charts are returned in groups based on the requested interval. + * Covers: Spot / Linear contract / Inverse contract + */ + getKline( + params: GetKlineParamsV5 + ): Promise> { + return this.get(`/v5/market/kline`, params); + } + + /** + * Query the mark price kline data. Charts are returned in groups based on the requested interval. + * Covers: Linear contract / Inverse contract + */ + getMarkPriceKline( + params: GetMarkPriceKlineParamsV5 + ): Promise> { + return this.get(`/v5/market/mark-price-kline`, params); + } + + /** + * Query the index price kline data. Charts are returned in groups based on the requested interval. + * Covers: Linear contract / Inverse contract + */ + getIndexPriceKline( + params: GetIndexPriceKlineParamsV5 + ): Promise> { + return this.get(`/v5/market/index-price-kline`, params); + } + + /** + * Retrieve the premium index price kline data. Charts are returned in groups based on the requested interval. + * Covers: Linear contract + */ + getPremiumIndexPriceKline( + params: GetPremiumIndexPriceKlineParams + ): Promise> { + return this.get(`/v5/market/premium-index-price-kline`, params); + } + + /** + * Query a list of instruments of online trading pair. + * Covers: Spot / Linear contract / Inverse contract / Option + * Note: Spot does not support pagination, so limit & cursor are invalid. + */ + getInstrumentsInfo( + params: GetInstrumentsInfoParamsV5 + ): Promise>> { + return this.get(`/v5/market/instruments-info`, params); + } + + /** + * Query orderbook data + * Covers: Spot / Linear contract / Inverse contract / Option + */ + getOrderbook( + params: GetOrderbookParamsV5 + ): Promise> { + return this.get(`/v5/market/orderbook`, params); + } + + /** + * Query the latest price snapshot, best bid/ask price, and trading volume in the last 24 hours. + * Covers: Spot / Linear contract / Inverse contract / Option + */ + getTickers( + params: GetTickersParamsV5 + ): Promise< + APIResponseV3WithTime< + | TickersLinearInverseResponseV5 + | TickersOptionResponseV5 + | TickersSpotResponseV5 + > + > { + return this.get(`/v5/market/tickers`, params); + } + + /** + * Query historical funding rate. Each symbol has a different funding interval. + * Covers: Linear contract / Inverse perpetual + */ + getFundingRateHistory( + params: GetFundingRateHistoryParamsV5 + ): Promise< + APIResponseV3WithTime< + CategoryListV5 + > + > { + return this.get(`/v5/market/funding/history`, params); + } + + /** + * Query recent public trading data in Bybit. + * Covers: Spot / Linear contract / Inverse contract / Option + */ + getPublicTradingHistory( + params: GetPublicTradingHistoryParamsV5 + ): Promise>> { + return this.get(`/v5/market/recent-trade`, params); + } + + /** + * Get open interest of each symbol. + * Covers: Linear contract / Inverse contract + */ + getOpenInterest( + params: GetOpenInterestParamsV5 + ): Promise> { + return this.get(`/v5/market/open-interest`, params); + } + + /** + * Query option historical volatility + * Covers: Option + */ + getHistoricalVolatility( + params: GetHistoricalVolatilityParamsV5 + ): Promise< + APIResponseV3WithTime> + > { + return this.get(`/v5/market/historical-volatility`, params); + } + + /** + * Query Bybit insurance pool data (BTC/USDT/USDC etc). The data is updated every 24 hours. + */ + getInsurance( + params?: GetInsuranceParamsV5 + ): Promise> { + return this.get(`/v5/market/insurance`, params); + } + + /** + * Query risk limit of futures + * Covers: Linear contract / Inverse contract + */ + getRiskLimit( + params?: GetRiskLimitParamsV5 + ): Promise< + APIResponseV3WithTime> + > { + return this.get(`/v5/market/risk-limit`, params); + } + + /** + * Get the delivery price for option + * Covers: Option + */ + getOptionDeliveryPrice( + params: GetOptionDeliveryPriceParamsV5 + ): Promise> { + return this.get(`/v5/market/delivery-price`, params); + } +} diff --git a/src/types/index.ts b/src/types/index.ts index 82b2b91..15b6b2d 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -1,4 +1,5 @@ export * from './response'; export * from './request'; export * from './shared'; +export * from './v5-shared'; export * from './websockets'; diff --git a/src/types/request/index.ts b/src/types/request/index.ts index bfbba68..2bee5d1 100644 --- a/src/types/request/index.ts +++ b/src/types/request/index.ts @@ -7,4 +7,5 @@ export * from './usdc-perp'; export * from './usdc-options'; export * from './usdc-shared'; export * from './unified-margin'; +export * from './v5-market'; export * from './contract'; diff --git a/src/types/request/v5-market.ts b/src/types/request/v5-market.ts new file mode 100644 index 0000000..c23ccdb --- /dev/null +++ b/src/types/request/v5-market.ts @@ -0,0 +1,120 @@ +import { KlineIntervalV3 } from '../shared'; +import { CategoryV5 } from '../v5-shared'; + +export interface GetKlineParamsV5 { + category: 'spot' | 'linear' | 'inverse'; + symbol: string; + interval: KlineIntervalV3; + start?: number; + end?: number; + limit?: number; +} + +export interface GetMarkPriceKlineParamsV5 { + category: 'linear' | 'inverse'; + symbol: string; + interval: KlineIntervalV3; + start?: number; + end?: number; + limit?: number; +} + +export interface GetIndexPriceKlineParamsV5 { + category: 'linear' | 'inverse'; + symbol: string; + interval: KlineIntervalV3; + start?: number; + end?: number; + limit?: number; +} + +export interface GetPremiumIndexPriceKlineParams { + category: 'linear'; + symbol: string; + interval: KlineIntervalV3; + start?: number; + end?: number; + limit?: number; +} + +export interface GetInstrumentsInfoParamsV5 { + category: CategoryV5; + symbol?: string; + baseCoin?: string; + limit?: number; + cursor?: string; +} + +export interface GetOrderbookParamsV5 { + category: CategoryV5; + symbol: string; + limit?: number; +} + +export interface GetTickersParamsV5 { + category: CategoryV5; + symbol?: string; + baseCoin?: string; + expDate?: string; +} + +export interface GetFundingRateHistoryParamsV5 { + category: 'linear' | 'inverse'; + symbol: string; + startTime?: number; + endTime?: number; + limit?: number; +} + +export type OptionType = 'Call' | 'Put'; + +export interface GetPublicTradingHistoryParamsV5 { + category: CategoryV5; + symbol: string; + baseCoin?: string; + optionType?: OptionType; + limit?: number; +} + +export type OpenInterestIntervalV5 = + | '5min' + | '15min' + | '30min' + | '1h' + | '4h' + | '1d'; + +export interface GetOpenInterestParamsV5 { + category: 'linear' | 'inverse'; + symbol: string; + intervalTime: OpenInterestIntervalV5; + startTime?: number; + endTime?: number; + limit?: number; + cursor?: string; +} + +export interface GetHistoricalVolatilityParamsV5 { + category: 'option'; + baseCoin?: string; + period?: number; + startTime?: number; + endTime?: number; +} + +export interface GetInsuranceParamsV5 { + coin?: string; +} + +export interface GetRiskLimitParamsV5 { + category?: 'linear' | 'inverse'; + symbol?: string; +} + +export interface GetOptionDeliveryPriceParamsV5 { + category: 'option'; + symbol?: string; + baseCoin?: string; + limit?: number; + cursor?: string; +} diff --git a/src/types/response/v5-market.ts b/src/types/response/v5-market.ts new file mode 100644 index 0000000..f53d863 --- /dev/null +++ b/src/types/response/v5-market.ts @@ -0,0 +1,298 @@ +import { CategoryV5 } from '../v5-shared'; + +/** + * Next page cursor does not exist for spot! + */ +export interface PaginatedListV5 { + nextPageCursor: string; + list: T[]; +} + +export interface CategoryListV5 { + category: TCategory; + list: T[]; +} + +/** + * OHLCVT candle used by v5 APIs +> list[0]: startTime string Start time of the candle (ms) +> list[1]: openPrice string Open price +> list[2]: highPrice string Highest price +> list[3]: lowPrice string Lowest price +> list[4]: closePrice string Close price. Is the last traded price when the candle is not closed +> list[5]: volume string Trade volume. Unit of contract: pieces of contract. Unit of spot: quantity of coins +> list[6]: turnover string Turnover. Unit of figure: quantity of quota coin + */ +export type KlineV5 = [string, string, string, string, string, string, string]; + +export interface KlineResponseV5 { + category: 'spot' | 'linear' | 'inverse'; + symbol: string; + list: KlineV5[]; +} + +/** + * OHLC candle used by v5 APIs +> list[0]: startTime string Start time of the candle (ms) +> list[1]: openPrice string Open price +> list[2]: highPrice string Highest price +> list[3]: lowPrice string Lowest price +> list[4]: closePrice string Close price. Is the last traded price when the candle is not closed + */ +export type OHLCV5 = [string, string, string, string, string]; + +export interface MarkPriceKlineResponseV5 { + category: 'linear' | 'inverse'; + symbol: string; + list: OHLCV5[]; +} + +export interface IndexPriceKlineResponseV5 { + category: 'linear' | 'inverse'; + symbol: string; + list: OHLCV5[]; +} + +export interface PremiumIndexPriceKlineResponse { + category: 'linear'; + symbol: string; + list: OHLCV5[]; +} + +export interface LinearInverseInstrumentInfoV5 { + category: 'linear' | 'inverse'; + symbol: string; + contractType: string; + status: string; + baseCoin: string; + quoteCoin: string; + launchTime: string; + deliveryTime: string; + deliveryFeeRate: string; + priceScale: string; + maxLeverage: string; + minOrderValue: string; + minOrderVolume: string; + makerFeeRate: string; + takerFeeRate: string; +} + +export interface OptionInstrumentInfoV5 { + category: 'option'; + symbol: string; + contractType: string; + status: string; + baseCoin: string; + quoteCoin: string; + launchTime: string; + deliveryTime: string; + deliveryFeeRate: string; + priceScale: string; + maxLeverage: string; + minOrderValue: string; + minOrderVolume: string; + makerFeeRate: string; + takerFeeRate: string; + settlementCurrency: string; + settlementPrice: string; + deliveryMethod: string; + optionType: string; + exercisePrice: string; + expirationTime: string; + blockMarginRatio: string; + marginType: string; + strike: string; +} + +export interface SpotInstrumentInfoV5 { + category: 'spot'; + symbol: string; + contractType: string; + status: string; + baseCoin: string; + quoteCoin: string; + launchTime: string; + priceScale: string; + maxLeverage: string; + minOrderValue: string; + minOrderVolume: string; + makerFeeRate: string; + takerFeeRate: string; +} + +export type InstrumentInfoV5 = + | LinearInverseInstrumentInfoV5 + | OptionInstrumentInfoV5 + | SpotInstrumentInfoV5; + +export interface OrderbookLevelV5 { + price: string; + size: string; +} + +export interface OrderbookResponseV5 { + s: string; + b: OrderbookLevelV5[]; + a: OrderbookLevelV5[]; + ts: number; + u: number; +} + +export interface TickerLinearInverseV5 { + symbol: string; + lastPrice: string; + indexPrice: string; + markPrice: string; + prevPrice24h: string; + price24hPcnt: string; + highPrice24h: string; + lowPrice24h: string; + prevPrice1h: string; + openInterest: string; + openInterestValue: string; + turnover24h: string; + volume24h: string; + fundingRate: string; + nextFundingTime: string; + predictedDeliveryPrice: string; + basisRate: string; + deliveryFeeRate: string; + deliveryTime: string; + ask1Size: string; + bid1Price: string; + ask1Price: string; + bid1Size: string; +} + +export interface TickerOptionV5 { + symbol: string; + bid1Price: string; + bid1Size: string; + bid1Iv: string; + ask1Price: string; + ask1Size: string; + ask1Iv: string; + lastPrice: string; + highPrice24h: string; + lowPrice24h: string; + markPrice: string; + indexPrice: string; + markIv: string; + underlyingPrice: string; + openInterest: string; + turnover24h: string; + volume24h: string; + totalVolume: string; + totalTurnover: string; + delta: string; + gamma: string; + vega: string; + theta: string; + predictedDeliveryPrice: string; + change24h: string; +} + +export interface TickerSpotV5 { + symbol: string; + bid1Price: string; + bid1Size: string; + ask1Price: string; + ask1Size: string; + lastPrice: string; + prevPrice24h: string; + price24hPcnt: string; + highPrice24h: string; + lowPrice24h: string; + turnover24h: string; + volume24h: string; + usdIndexPrice: string; +} + +export interface TickersSpotResponseV5 { + category: 'spot'; + list: TickerSpotV5[]; +} + +export interface TickersLinearInverseResponseV5 { + category: 'linear' | 'inverse'; + list: TickerLinearInverseV5[]; +} + +export interface TickersOptionResponseV5 { + category: 'option'; + list: TickerOptionV5[]; +} + +export interface FundingRateHistoryResponseV5 { + symbol: string; + fundingRate: string; + fundingRateTimestamp: string; +} + +export interface PublicTradeV5 { + execId: string; + symbol: string; + price: string; + size: string; + side: 'Buy' | 'Sell'; + time: string; + isBlockTrade: boolean; +} + +/** +> openInterest string Open interest +> timestamp string The timestamp (ms) +*/ +export type OpenInterestV5 = [string, string]; + +export interface OpenInterestResponseV5 { + category: 'linear' | 'inverse'; + symbol: string; + list: OpenInterestV5[]; + nextPageCursor?: string; +} + +export interface HistoricalVolatilityV5 { + period: number; + value: string; + time: string; +} + +export interface InsuranceDataV5 { + coin: string; + balance: string; + value: string; +} + +export interface InsuranceResponseV5 { + updatedTime: string; + list: InsuranceDataV5[]; +} + +export interface RiskLimitV5 { + id: number; + symbol: string; + riskLimitValue: string; + maintenanceMargin: number; + initialMargin: number; + section: any; + isLowestRisk: 0 | 1; + maxLeverage: string; +} + +export interface RiskLimitResponseV5 { + category: CategoryV5; + list: RiskLimitV5[]; +} + +export interface OptionDeliveryPriceV5 { + symbol: string; + deliveryPrice: string; + deliveryTime: string; +} + +export interface OptionDeliveryPriceResponseV5 { + category: CategoryV5; + list: OptionDeliveryPriceV5[]; + nextPageCursor?: string; +} diff --git a/src/types/v5-shared.ts b/src/types/v5-shared.ts new file mode 100644 index 0000000..bb60a40 --- /dev/null +++ b/src/types/v5-shared.ts @@ -0,0 +1 @@ +export type CategoryV5 = 'spot' | 'linear' | 'inverse' | 'option'; diff --git a/test/rest-client-v5/public.read.test.ts b/test/rest-client-v5/public.read.test.ts new file mode 100644 index 0000000..1ff95e2 --- /dev/null +++ b/test/rest-client-v5/public.read.test.ts @@ -0,0 +1,153 @@ +import { RestClientV5 } from '../../src'; +import { successResponseObjectV3 } from '../response.util'; + +describe('Public V5 REST API Endpoints', () => { + const API_KEY = undefined; + const API_SECRET = undefined; + + const api = new RestClientV5({ + key: API_KEY, + secret: API_SECRET, + testnet: false, + }); + + const linearSymbol = 'BTCUSDT'; + + describe('Misc Endpoints', () => { + it('fetchServerTime()', async () => { + expect(await api.fetchServerTime()).toEqual(expect.any(Number)); + }); + + it('getServerTime()', async () => { + expect(await api.getServerTime()).toMatchObject( + successResponseObjectV3() + ); + }); + }); + + describe('Market Endpoints', () => { + it('getKline()', async () => { + expect( + await api.getKline({ + category: 'linear', + interval: '1', + symbol: linearSymbol, + }) + ).toMatchObject(successResponseObjectV3()); + }); + + it('getMarkPriceKline()', async () => { + expect( + await api.getMarkPriceKline({ + category: 'linear', + interval: '1', + symbol: linearSymbol, + }) + ).toMatchObject(successResponseObjectV3()); + }); + + it('getIndexPriceKline()', async () => { + expect( + await api.getIndexPriceKline({ + category: 'linear', + interval: '1', + symbol: linearSymbol, + }) + ).toMatchObject(successResponseObjectV3()); + }); + + it('getPremiumIndexPriceKline()', async () => { + expect( + await api.getPremiumIndexPriceKline({ + category: 'linear', + interval: '1', + symbol: linearSymbol, + }) + ).toMatchObject(successResponseObjectV3()); + }); + + it('getInstrumentsInfo()', async () => { + expect( + await api.getInstrumentsInfo({ + category: 'linear', + symbol: linearSymbol, + }) + ).toMatchObject(successResponseObjectV3()); + }); + + it('getOrderbook()', async () => { + expect( + await api.getOrderbook({ + category: 'linear', + symbol: linearSymbol, + }) + ).toMatchObject(successResponseObjectV3()); + }); + + it('getTickers()', async () => { + expect( + await api.getTickers({ + category: 'linear', + symbol: linearSymbol, + }) + ).toMatchObject(successResponseObjectV3()); + }); + + it('getFundingRateHistory()', async () => { + expect( + await api.getFundingRateHistory({ + category: 'linear', + symbol: linearSymbol, + }) + ).toMatchObject(successResponseObjectV3()); + }); + + it('getPublicTradingHistory()', async () => { + expect( + await api.getPublicTradingHistory({ + category: 'linear', + symbol: linearSymbol, + }) + ).toMatchObject(successResponseObjectV3()); + }); + + it('getOpenInterest()', async () => { + expect( + await api.getOpenInterest({ + category: 'linear', + symbol: linearSymbol, + intervalTime: '15min', + }) + ).toMatchObject(successResponseObjectV3()); + }); + + it('getHistoricalVolatility()', async () => { + expect( + await api.getHistoricalVolatility({ + category: 'option', + }) + ).toMatchObject(successResponseObjectV3()); + }); + + it('getInsurance()', async () => { + expect(await api.getInsurance()).toMatchObject(successResponseObjectV3()); + }); + + it('getRiskLimit()', async () => { + expect( + await api.getRiskLimit({ + category: 'linear', + symbol: linearSymbol, + }) + ).toMatchObject(successResponseObjectV3()); + }); + + it('getOptionDeliveryPrice()', async () => { + expect( + await api.getOptionDeliveryPrice({ + category: 'option', + }) + ).toMatchObject(successResponseObjectV3()); + }); + }); +});