diff --git a/CHANGELOG.md b/CHANGELOG.md index 4365a1f..9374ba8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,11 +1,102 @@ # Changelog -All notable changes to this project will be documented in this file. +## [0.1.1] — 2026-10-09 -The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), -and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +### Added +- `AccountService.demoApplyMoney(...)` +- `AccountService.getOptionAssetInfo(...)` +- `AccountService.getPayInfo(...)` +- `AccountService.getTradeInfoForAnalysis(...)` +- `AlphaService.getLpOrderList(...)` +- `AlphaService.getLpPayTokenList(...)` +- `AlphaService.getLpPayTokenPrice(...)` +- `AlphaService.getLpPoolInfo(...)` +- `AlphaService.getLpPoolList(...)` +- `AlphaService.getLpPositionList(...)` +- `AlphaService.executeLpRedeem(...)` +- `AlphaService.executeLpStake(...)` +- `AlphaService.executePredictionBuy(...)` +- `AlphaService.getPredictionEngineStatus(...)` +- `AlphaService.getPredictionEventDetail(...)` +- `AlphaService.getPredictionOrderBook(...)` +- `AlphaService.getPredictionOrderEstimate(...)` +- `AlphaService.getPredictionOrderList(...)` +- `AlphaService.getPredictionPayTokenList(...)` +- `AlphaService.getPredictionPortfolioSummary(...)` +- `AlphaService.getPredictionPositionHistory(...)` +- `AlphaService.getPredictionPositionList(...)` +- `AlphaService.getPredictionPriceHistory(...)` +- `AlphaService.executePredictionSell(...)` +- `AlphaService.getPredictionSideMarketList(...)` +- `AlphaService.getPredictionGroupStageDetail(...)` +- `AlphaService.getPredictionMatchList(...)` +- `AlphaService.getPredictionTimelineStages(...)` +- `AlphaService.getPredictionTokenPrice(...)` +- `AlphaService.getAssetDetail(...)` +- `AlphaService.getAssetList(...)` +- `AlphaService.getBizTokenDetails(...)` +- `AlphaService.getBizTokenList(...)` +- `AlphaService.getBizTokenPriceList(...)` +- `AlphaService.getOrderList(...)` +- `AlphaService.getPayTokenList(...)` +- `AlphaService.executePurchase(...)` +- `AlphaService.getTradeQuote(...)` +- `AlphaService.executeRedeem(...)` +- `AssetService.getOverview(...)` +- `AssetService.smallAssetQuote(...)` +- `AssetService.smallAssetConvert(...)` +- `AssetService.getSmallAssetConvertOrder(...)` +- `AssetService.getSmallAssetList(...)` +- `AssetService.setDefaultDepositToAccount(...)` +- `AssetService.limitOrderCallback(...)` +- `AssetService.coinConvertLimitQuery(...)` +- `AssetService.getOrderFromOpen(...)` +- `AssetService.getPortfolioMargin(...)` +- `AssetService.getTotalMembersAssets(...)` +- `AssetService.transferSubMemberSave(...)` +- `AssetService.getWithdrawAddresses(...)` +- `AssetService.getVaspList(...)` +- `CryptoLoanService.getFixedAvailableInventory(...)` +- `CryptoLoanService.getFlexibleAvailableInventory(...)` +- `EarnService.listAutoSavings(...)` +- `EarnService.editEarnAutoSavings(...)` +- `LendingService.insLoanAssociationUid(...)` +- `LendingService.insLoanCoinDeltaAmount(...)` +- `LendingService.insLoanDelayLiqStatus(...)` +- `LendingService.insLoanEnsureTokens(...)` +- `LendingService.insLoanEnsureTokensConvert(...)` +- `LendingService.insLoanGetLoanOrder(...)` +- `LendingService.insLoanLtvConvert(...)` +- `LendingService.insLoanProductInfos(...)` +- `LendingService.insLoanRepaidHistory(...)` +- `LendingService.insLoanRepayLoan(...)` +- `MarketService.getNewDeliveryPrice(...)` +- `MarketService.getOptionBaseCoins(...)` +- `PositionService.getSymbolInfo(...)` +- `SpotMarginService.getTradeCoinState(...)` +- `SpotMarginService.queryFixedAvailableInventory(...)` +- `SpotMarginService.accountFixedBorrow(...)` +- `SpotMarginService.queryFixedBorrowContracts(...)` +- `SpotMarginService.queryFixedBorrowOrders(...)` +- `SpotMarginService.queryFixedBorrowMarket(...)` +- `SpotMarginService.renewFixedBorrow(...)` +- `SpotMarginService.getTradeFlexibleAvailableInventory(...)` +- `SpotMarginService.getTradeAutoRepayMode(...)` +- `SpotMarginService.queryBorrowLiability(...)` +- `SpotMarginService.getTradeMaxBorrowable(...)` +- `SpotMarginService.getTradeRepaymentAvailableAmount(...)` +- `SpotMarginService.setAutoRepayMode(...)` +- `SpotMarginService.spotMarginSetLeverage(...)` +- `SpotMarginService.getTradeState(...)` +- `SpotMarginService.spotMarginSwitchMode(...)` +- `UserService.queryReferralCode(...)` + +### Fixed +- Align Alpha prediction, LP, and trade request fields and TypeScript types with the documented API contracts. +- Serialize GET array parameters as repeated query keys so Auto Savings sends and signs `coins=BTC&coins=ETH`. +- Correct API documentation links for newly added service methods. -## [Unreleased] — targeting 0.1.0 +## [0.1.0] — 2026-07-17 ### Added - `AccountService.batchSetCollateral(...)` diff --git a/README.md b/README.md index 28657eb..94444b7 100644 --- a/README.md +++ b/README.md @@ -8,9 +8,9 @@ Official lightweight TypeScript / JavaScript connector for the [Bybit V5 REST API](https://bybit-exchange.github.io/docs/v5/intro). -`bybit-official-ts-sdk` is a thin, typed wrapper around the Bybit V5 HTTP endpoints. It ships as a single npm package with one service class per API group (`market`, `trade`, `account`, `position`, `asset`, `user`, `affiliate`, `broker`, `crypto-loan`, `rfq`, `spot-margin`, `earn`, `p2p`, `bot`). Its goal is the same as [`pybit`](https://github.com/bybit-exchange/pybit) on the Python side: an easy-to-use, high-performance connector with a small dependency footprint. +`bybit-official-ts-sdk` is a thin, typed wrapper around the Bybit V5 HTTP endpoints. It ships as a single npm package with one service class per API group (`market`, `trade`, `account`, `position`, `asset`, `user`, `affiliate`, `broker`, `crypto-loan`, `institutional-loan`, `alpha`, `rfq`, `spot-margin`, `earn`, `p2p`, `bot`). Its goal is the same as [`pybit`](https://github.com/bybit-exchange/pybit) on the Python side: an easy-to-use, high-performance connector with a small dependency footprint. -The client currently exposes REST endpoints across **14 service modules**, all reachable from a single `BybitClient`. +The client currently exposes REST endpoints across **16 service modules**, all reachable from a single `BybitClient`. Capabilities in this release: @@ -20,7 +20,7 @@ Capabilities in this release: - Account: wallet balance, margin mode, collateral, fee rate, transaction log - Assets: deposit / withdraw / internal-transfer / universal-transfer / convert - Users & sub-accounts, API-key management -- Crypto Loan (flexible + fixed), Earn (Advance / RWA / PWM / Liquidity Mining), Spot Margin +- Crypto Loan (flexible + fixed), Institutional Loan, Alpha, Earn (Advance / RWA / PWM / Liquidity Mining), Spot Margin - RFQ (block trades), Affiliate, Broker, P2P, Bot (grid / futures-grid / futures-combo / futures-martingale / DCA) - Typed error hierarchy — network / timeout / rate-limit / auth / parse / API errors - Rate-limit budget headers surfaced per response @@ -286,11 +286,13 @@ client.market // MarketService — public market data (kline, tick client.trade // TradeService — orders (create / amend / cancel / batch / history) client.position // PositionService — positions, leverage, TP/SL, move-position client.account // AccountService — wallet, margin, collateral, fee-rate, transfer log +client.alpha // AlphaService — Alpha trading, prediction markets, liquidity pools client.asset // AssetService — deposit / withdraw / transfer / convert / coin info client.user // UserService — sub-accounts, API-key management client.affiliate // AffiliateService — sub-affiliate lists client.broker // BrokerService — broker earnings, distributions client.cryptoLoan // CryptoLoanService — flexible / fixed crypto loans +client.lending // LendingService — institutional lending client.rfq // RfqService — request-for-quote (block trades) client.spotMargin // SpotMarginService — UTA spot margin client.earn // EarnService — earn, liquidity mining, RWA, PWM, hold-to-earn diff --git a/package-lock.json b/package-lock.json index 2d96c4b..a17db26 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,15 +1,15 @@ { "name": "bybit-official-ts-sdk", - "version": "0.1.0", + "version": "0.1.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "bybit-official-ts-sdk", - "version": "0.1.0", + "version": "0.1.1", "license": "MIT", "dependencies": { - "axios": "^1.7.0" + "axios": "^1.20.0" }, "devDependencies": { "@types/jest": "^29.0.0", @@ -1668,12 +1668,13 @@ "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" }, "node_modules/axios": { - "version": "1.18.1", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.18.1.tgz", - "integrity": "sha512-3nTvFlvpn9Zu/RkHUqtc7/+al4UpRW5az71ap5zccp6e8RAYEzhMTecX8Dz1wWDYrPpUoB1HAQEGEAEvUr7S9g==", + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.20.0.tgz", + "integrity": "sha512-r8aOh8j9cGKpgQAqpzrUHnSIc6a59Y3Xf/cv8sy1DrHCkZHzQGEuoq1tARk6qSyDdtQGSDgpb9kFlruzPvrgwg==", + "license": "MIT", "dependencies": { "follow-redirects": "^1.16.0", - "form-data": "^4.0.5", + "form-data": "^4.0.6", "https-proxy-agent": "^5.0.1", "proxy-from-env": "^2.1.0" } diff --git a/package.json b/package.json index d398f7b..816a2ce 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "bybit-official-ts-sdk", - "version": "0.1.0", + "version": "0.1.1", "description": "Official Bybit V5 REST API connector for Node.js (TypeScript-first, axios-based).", "keywords": [ "bybit", @@ -57,10 +57,12 @@ "format": "prettier --write \"src/**/*.ts\"", "smoke": "node scripts/dist-smoke.js", "prepublishOnly": "npm run build && npm run smoke", + "typecheck:test": "tsc -p tsconfig.test.json", + "pretest": "npm run typecheck:test", "test": "jest" }, "dependencies": { - "axios": "^1.7.0" + "axios": "^1.20.0" }, "devDependencies": { "typescript": "^5.4.0", diff --git a/src/client.ts b/src/client.ts index ebc5075..20f812f 100644 --- a/src/client.ts +++ b/src/client.ts @@ -6,11 +6,13 @@ import { type RestClientOptions } from './config.js' // gen-sdk-js:client-imports:start import { AccountService } from './rest-api/account.js' import { AffiliateService } from './rest-api/affiliate.js' +import { AlphaService } from './rest-api/alpha.js' import { AssetService } from './rest-api/asset.js' import { BotService } from './rest-api/bot.js' import { BrokerService } from './rest-api/broker.js' import { CryptoLoanService } from './rest-api/crypto-loan.js' import { EarnService } from './rest-api/earn.js' +import { LendingService } from './rest-api/lending.js' import { MarketService } from './rest-api/market.js' import { P2pService } from './rest-api/p2p.js' import { PositionService } from './rest-api/position.js' @@ -37,11 +39,13 @@ export class BybitClient { // gen-sdk-js:client-fields:start public readonly account: AccountService public readonly affiliate: AffiliateService + public readonly alpha: AlphaService public readonly asset: AssetService public readonly bot: BotService public readonly broker: BrokerService public readonly cryptoLoan: CryptoLoanService public readonly earn: EarnService + public readonly lending: LendingService public readonly market: MarketService public readonly p2p: P2pService public readonly position: PositionService @@ -62,11 +66,13 @@ export class BybitClient { // gen-sdk-js:client-inits:start this.account = new AccountService(this.http, this.options) this.affiliate = new AffiliateService(this.http, this.options) + this.alpha = new AlphaService(this.http, this.options) this.asset = new AssetService(this.http, this.options) this.bot = new BotService(this.http, this.options) this.broker = new BrokerService(this.http, this.options) this.cryptoLoan = new CryptoLoanService(this.http, this.options) this.earn = new EarnService(this.http, this.options) + this.lending = new LendingService(this.http, this.options) this.market = new MarketService(this.http, this.options) this.p2p = new P2pService(this.http, this.options) this.position = new PositionService(this.http, this.options) diff --git a/src/http/request.ts b/src/http/request.ts index 127b72b..d17b6bf 100644 --- a/src/http/request.ts +++ b/src/http/request.ts @@ -61,7 +61,11 @@ function serializeQuery(params: Record | undefined): string { const entries: [string, string][] = [] for (const [k, v] of Object.entries(params)) { if (!isNotNull(v)) continue - entries.push([k, typeof v === 'object' ? JSON.stringify(v) : String(v)]) + const values = Array.isArray(v) ? v : [v] + for (const value of values) { + if (!isNotNull(value)) continue + entries.push([k, typeof value === 'object' ? JSON.stringify(value) : String(value)]) + } } entries.sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0)) return new URLSearchParams(entries).toString() diff --git a/src/rest-api/account.ts b/src/rest-api/account.ts index 6b95877..4a17283 100644 --- a/src/rest-api/account.ts +++ b/src/rest-api/account.ts @@ -442,4 +442,65 @@ export class AccountService { signed: true, }) } + + /** + * Apply demo funds + * @see https://bybit-exchange.github.io/docs/v5/demo + */ + async demoApplyMoney(params: { + adjustType?: number + utaDemoApplyMoney?: Array> + }): Promise> { + return requestJson(this.http, this.opts, { + method: 'POST', + path: '/v5/account/demo-apply-money', + signed: true, + body: params, + }) + } + + /** + * Get Option Asset Info + * @see https://bybit-exchange.github.io/docs/v5/account/option-asset-info + */ + async getOptionAssetInfo(): Promise> { + return requestJson(this.http, this.opts, { + method: 'GET', + path: '/v5/account/option-asset-info', + signed: true, + }) + } + + /** + * Get Pay Info + * @see https://bybit-exchange.github.io/docs/v5/account/pay-info + */ + async getPayInfo(params: { + coin?: string + }): Promise> { + return requestJson(this.http, this.opts, { + method: 'GET', + path: '/v5/account/pay-info', + signed: true, + query: params, + }) + } + + /** + * Get Trade Info For Analysis + * @see https://bybit-exchange.github.io/docs/v5/account/trade-info-for-analysis + */ + async getTradeInfoForAnalysis(params: { + symbol?: string + startTime?: number + endTime?: number + }): Promise> { + return requestJson(this.http, this.opts, { + method: 'GET', + path: '/v5/account/trade-info-for-analysis', + signed: true, + query: params, + }) + } + } diff --git a/src/rest-api/alpha.ts b/src/rest-api/alpha.ts new file mode 100644 index 0000000..cc6894d --- /dev/null +++ b/src/rest-api/alpha.ts @@ -0,0 +1,624 @@ +import type { AxiosInstance } from 'axios' +import { requestJson } from '../http/request.js' +import type { ApiResponse } from '../types/common.js' +import type { RestClientOptions } from '../config.js' + +export class AlphaService { + protected readonly opts!: RestClientOptions + + constructor( + protected readonly http: AxiosInstance, + opts: RestClientOptions, + ) { + Object.defineProperty(this, 'opts', { + value: opts, + writable: false, + enumerable: false, + configurable: false, + }) + } + + /** + * Get LP order history with status and execution details + * @see https://bybit-exchange.github.io/docs/v5/alpha/lp/order-list + */ + async getLpOrderList(params: { + orderType?: number + tokenCode?: string + orderStatus?: number[] + days?: number + limit?: number + pageIndex?: number + poolAddress?: string + }): Promise> { + return requestJson(this.http, this.opts, { + method: 'POST', + path: '/v5/alpha/lp/order-list', + signed: true, + body: params, + }) + } + + /** + * Get list of supported payment tokens + * @see https://bybit-exchange.github.io/docs/v5/alpha/lp/pay-token-list + */ + async getLpPayTokenList(params: { + chainCode?: string + tokenAddress?: string + }): Promise> { + return requestJson(this.http, this.opts, { + method: 'POST', + path: '/v5/alpha/lp/pay-token-list', + signed: true, + body: params, + }) + } + + /** + * Get current prices for payment tokens + * @see https://bybit-exchange.github.io/docs/v5/alpha/lp/pay-token-price + */ + async getLpPayTokenPrice(params: { + tokenCode: string[] + chainCode?: string + }): Promise> { + return requestJson(this.http, this.opts, { + method: 'POST', + path: '/v5/alpha/lp/pay-token-price', + signed: true, + body: params, + }) + } + + /** + * Get detailed information for a specific LP pool + * @see https://bybit-exchange.github.io/docs/v5/alpha/lp/pool-info + */ + async getLpPoolInfo(params: { + poolAddress: string + }): Promise> { + return requestJson(this.http, this.opts, { + method: 'POST', + path: '/v5/alpha/lp/pool-info', + signed: true, + body: params, + }) + } + + /** + * Get LP pool list with optional filters + * @see https://bybit-exchange.github.io/docs/v5/alpha/lp/pool-list + */ + async getLpPoolList(params: { + tokenSymbol?: string + }): Promise> { + return requestJson(this.http, this.opts, { + method: 'POST', + path: '/v5/alpha/lp/pool-list', + signed: true, + body: params, + }) + } + + /** + * Get user's LP positions with rewards and current value + * @see https://bybit-exchange.github.io/docs/v5/alpha/lp/position-list + */ + async getLpPositionList(): Promise> { + return requestJson(this.http, this.opts, { + method: 'POST', + path: '/v5/alpha/lp/position-list', + signed: true, + }) + } + + /** + * Redeem (withdraw) liquidity from a position + * @see https://bybit-exchange.github.io/docs/v5/alpha/lp/redeem + */ + async executeLpRedeem(params: { + positionId: number + poolAddress: string + dercRatio: string + receiveTokenCode?: string + }): Promise> { + return requestJson(this.http, this.opts, { + method: 'POST', + path: '/v5/alpha/lp/redeem', + signed: true, + body: params, + }) + } + + /** + * Stake tokens into an LP pool + * @see https://bybit-exchange.github.io/docs/v5/alpha/lp/stake + */ + async executeLpStake(params: { + positionId: number + poolAddress: string + payTokenAmount: string + payTokenCode: string + rangeUpper?: string + rangeLower?: string + priceUpper?: string + priceLower?: string + }): Promise> { + return requestJson(this.http, this.opts, { + method: 'POST', + path: '/v5/alpha/lp/stake', + signed: true, + body: params, + }) + } + + /** + * Buy prediction outcome tokens with USDC + * @see https://bybit-exchange.github.io/docs/v5/alpha/prediction/buy + */ + async executePredictionBuy(params: { + tokenId: string + amount: string + payTokenCode: string + orderType: number + slippage: string + eventId: string + }): Promise> { + return requestJson(this.http, this.opts, { + method: 'POST', + path: '/v5/alpha/prediction/buy', + signed: true, + body: params, + }) + } + + /** + * Get prediction market matching engine availability status + * @see https://bybit-exchange.github.io/docs/v5/alpha/prediction/engine-status + */ + async getPredictionEngineStatus(): Promise> { + return requestJson(this.http, this.opts, { + method: 'GET', + path: '/v5/alpha/prediction/engine-status', + signed: true, + }) + } + + /** + * Get prediction event detail with all markets and outcomes + * @see https://bybit-exchange.github.io/docs/v5/alpha/prediction/event-detail + */ + async getPredictionEventDetail(params: { + eventId?: string + slug?: string + hasMoreMarkets?: boolean + }): Promise> { + return requestJson(this.http, this.opts, { + method: 'POST', + path: '/v5/alpha/prediction/event-detail', + signed: true, + body: params, + }) + } + + /** + * Get full order book snapshot for prediction tokens + * @see https://bybit-exchange.github.io/docs/v5/alpha/prediction/order-book + */ + async getPredictionOrderBook(params: { + tokenIds: string[] + }): Promise> { + return requestJson(this.http, this.opts, { + method: 'POST', + path: '/v5/alpha/prediction/order-book', + signed: true, + body: params, + }) + } + + /** + * Estimate buy or sell order fill amount and fees before execution + * @see https://bybit-exchange.github.io/docs/v5/alpha/prediction/order-estimate + */ + async getPredictionOrderEstimate(params: { + tokenId: string + side: number + eventId: string + amount: string + orderType: number + payTokenCode?: string + }): Promise> { + return requestJson(this.http, this.opts, { + method: 'POST', + path: '/v5/alpha/prediction/order-estimate', + signed: true, + body: params, + }) + } + + /** + * Get user's prediction market order history + * @see https://bybit-exchange.github.io/docs/v5/alpha/prediction/order-list + */ + async getPredictionOrderList(params: { + status?: number + tokenId?: string + limit?: number + pageIndex?: number + eventId?: string + side?: number + days?: number + }): Promise> { + return requestJson(this.http, this.opts, { + method: 'POST', + path: '/v5/alpha/prediction/order-list', + signed: true, + body: params, + }) + } + + /** + * Get available payment tokens (USDC) for prediction market + * @see https://bybit-exchange.github.io/docs/v5/alpha/prediction/pay-token-list + */ + async getPredictionPayTokenList(): Promise> { + return requestJson(this.http, this.opts, { + method: 'GET', + path: '/v5/alpha/prediction/pay-token-list', + signed: true, + }) + } + + /** + * Get user's prediction market portfolio overview + * @see https://bybit-exchange.github.io/docs/v5/alpha/prediction/portfolio-summary + */ + async getPredictionPortfolioSummary(params?: { + eventType?: number + }): Promise> { + return requestJson(this.http, this.opts, { + method: 'POST', + path: '/v5/alpha/prediction/portfolio-summary', + signed: true, + body: params, + }) + } + + /** + * Get user's historical closed prediction market positions + * @see https://bybit-exchange.github.io/docs/v5/alpha/prediction/position-history + */ + async getPredictionPositionHistory(params: { + tokenId?: string + eventId?: string + result?: number + days?: number + limit?: number + pageIndex?: number + }): Promise> { + return requestJson(this.http, this.opts, { + method: 'POST', + path: '/v5/alpha/prediction/position-history', + signed: true, + body: params, + }) + } + + /** + * Get user's current open prediction market positions + * @see https://bybit-exchange.github.io/docs/v5/alpha/prediction/position-list + */ + async getPredictionPositionList(params: { + tokenId?: string + eventId?: string + limit?: number + pageIndex?: number + }): Promise> { + return requestJson(this.http, this.opts, { + method: 'POST', + path: '/v5/alpha/prediction/position-list', + signed: true, + body: params, + }) + } + + /** + * Get historical price chart data for prediction tokens + * @see https://bybit-exchange.github.io/docs/v5/alpha/prediction/price-history + */ + async getPredictionPriceHistory(params: { + tokenId: string + interval: string + }): Promise> { + return requestJson(this.http, this.opts, { + method: 'POST', + path: '/v5/alpha/prediction/price-history', + signed: true, + body: params, + }) + } + + /** + * Sell prediction outcome token shares for USDC + * @see https://bybit-exchange.github.io/docs/v5/alpha/prediction/sell + */ + async executePredictionSell(params: { + tokenId: string + size: string + orderType: number + slippage: string + eventId: string + toTokenCode?: string + }): Promise> { + return requestJson(this.http, this.opts, { + method: 'POST', + path: '/v5/alpha/prediction/sell', + signed: true, + body: params, + }) + } + + /** + * Get related side markets for a sports event + * @see https://bybit-exchange.github.io/docs/v5/alpha/prediction/side-market-list + */ + async getPredictionSideMarketList(params: { + eventId: string + sortBy?: string + marketType?: number + limit?: number + pageIndex?: number + }): Promise> { + return requestJson(this.http, this.opts, { + method: 'POST', + path: '/v5/alpha/prediction/side-market-list', + signed: true, + body: params, + }) + } + + /** + * Get group standings and results for a tournament stage + * @see https://bybit-exchange.github.io/docs/v5/alpha/prediction/sports-group-stage-detail + */ + async getPredictionGroupStageDetail(params: { + eventType: number + groupName?: string + }): Promise> { + return requestJson(this.http, this.opts, { + method: 'POST', + path: '/v5/alpha/prediction/sports/group-stage-detail', + signed: true, + body: params, + }) + } + + /** + * Get match list for a sports prediction event + * @see https://bybit-exchange.github.io/docs/v5/alpha/prediction/sports-match-list + */ + async getPredictionMatchList(params: { + eventType: number + status?: number + startTime?: number + endTime?: number + stageCode?: string + limit?: number + pageIndex?: number + }): Promise> { + return requestJson(this.http, this.opts, { + method: 'POST', + path: '/v5/alpha/prediction/sports/match-list', + signed: true, + body: params, + }) + } + + /** + * Get tournament timeline stages for a sports event + * @see https://bybit-exchange.github.io/docs/v5/alpha/prediction/sports-timeline-stages + */ + async getPredictionTimelineStages(params: { + eventType: number + }): Promise> { + return requestJson(this.http, this.opts, { + method: 'GET', + path: '/v5/alpha/prediction/sports/timeline-stages', + signed: true, + query: params, + }) + } + + /** + * Get real-time prices for prediction outcome tokens + * @see https://bybit-exchange.github.io/docs/v5/alpha/prediction/token-price + */ + async getPredictionTokenPrice(params: { + tokenIds: string[] + }): Promise> { + return requestJson(this.http, this.opts, { + method: 'POST', + path: '/v5/alpha/prediction/token-price', + signed: true, + body: params, + }) + } + + /** + * Get holding details for a specific token including quantity, PnL, and cost basis + * @see https://bybit-exchange.github.io/docs/v5/alpha/trade/asset-detail + */ + async getAssetDetail(params: { + chainCode: string + tokenAddress: string + }): Promise> { + return requestJson(this.http, this.opts, { + method: 'POST', + path: '/v5/alpha/trade/asset-detail', + signed: true, + body: params, + }) + } + + /** + * Get user's on-chain token portfolio with holdings, PnL, and market value + * @see https://bybit-exchange.github.io/docs/v5/alpha/trade/asset-list + */ + async getAssetList(): Promise> { + return requestJson(this.http, this.opts, { + method: 'POST', + path: '/v5/alpha/trade/asset-list', + signed: true, + }) + } + + /** + * Get token project details including description, social links, risk flag, and order limits + * @see https://bybit-exchange.github.io/docs/v5/alpha/trade/biz-token-details + */ + async getBizTokenDetails(params: { + chainCode: string + tokenAddress: string + }): Promise> { + return requestJson(this.http, this.opts, { + method: 'POST', + path: '/v5/alpha/trade/biz-token-details', + signed: true, + body: params, + }) + } + + /** + * Get on-chain tradable tokens with DEX token codes, risk flags, and order limits + * @see https://bybit-exchange.github.io/docs/v5/alpha/trade/biz-token-list + */ + async getBizTokenList(params: { + tokenTag?: number + }): Promise> { + return requestJson(this.http, this.opts, { + method: 'POST', + path: '/v5/alpha/trade/biz-token-list', + signed: true, + body: params, + }) + } + + /** + * Batch query token prices, 24h change, volume, market cap, liquidity, and holders by chain+address + * @see https://bybit-exchange.github.io/docs/v5/alpha/trade/biz-token-price-list + */ + async getBizTokenPriceList(params: { + tokenAddressInfo: Array> + }): Promise> { + return requestJson(this.http, this.opts, { + method: 'POST', + path: '/v5/alpha/trade/biz-token-price-list', + signed: true, + body: params, + }) + } + + /** + * Get trade order history with status, fees, and execution details + * @see https://bybit-exchange.github.io/docs/v5/alpha/trade/order-list + */ + async getOrderList(params: { + tradeType?: number + tokenCode?: string + orderStatus?: number[] + days?: number + limit: number + pageIndex: number + direction?: string + }): Promise> { + return requestJson(this.http, this.opts, { + method: 'POST', + path: '/v5/alpha/trade/order-list', + signed: true, + body: params, + }) + } + + /** + * Get available payment tokens (USDT, USDC, etc.) with CEX token codes and supported chains + * @see https://bybit-exchange.github.io/docs/v5/alpha/trade/pay-token-list + */ + async getPayTokenList(params: { + chainCode: string + tokenAddress: string + }): Promise> { + return requestJson(this.http, this.opts, { + method: 'POST', + path: '/v5/alpha/trade/pay-token-list', + signed: true, + body: params, + }) + } + + /** + * Execute a buy order to purchase on-chain tokens with USDT/USDC, returns order number + * @see https://bybit-exchange.github.io/docs/v5/alpha/trade/trade-purchase + */ + async executePurchase(params: { + fromTokenCode: string + fromTokenAmount: string + toTokenCode: string + slippage: string + quoteData: string + gas: string + quoteMode: number + correctingCode: string + tenant?: string + }): Promise> { + return requestJson(this.http, this.opts, { + method: 'POST', + path: '/v5/alpha/trade/purchase', + signed: true, + body: params, + }) + } + + /** + * Get estimated price, fees, slippage, and gas for an on-chain token trade + * @see https://bybit-exchange.github.io/docs/v5/alpha/trade/trade-quote + */ + async getTradeQuote(params: { + tradeType: number + fromTokenCode: string + fromTokenAmount: string + toTokenCode: string + quoteMode?: number + }): Promise> { + return requestJson(this.http, this.opts, { + method: 'POST', + path: '/v5/alpha/trade/quote', + signed: true, + body: params, + }) + } + + /** + * Execute a sell order to redeem on-chain tokens for USDT/USDC, returns order number + * @see https://bybit-exchange.github.io/docs/v5/alpha/trade/trade-redeem + */ + async executeRedeem(params: { + fromTokenCode: string + fromTokenAmount: string + toTokenCode: string + slippage: string + quoteData: string + gas: string + quoteMode: number + correctingCode: string + tenant?: string + }): Promise> { + return requestJson(this.http, this.opts, { + method: 'POST', + path: '/v5/alpha/trade/redeem', + signed: true, + body: params, + }) + } + +} diff --git a/src/rest-api/asset.ts b/src/rest-api/asset.ts index 7235bb0..a0ceb36 100644 --- a/src/rest-api/asset.ts +++ b/src/rest-api/asset.ts @@ -559,4 +559,241 @@ export class AssetService { query: params, }) } + + /** + * Get Asset Overview + * @see https://bybit-exchange.github.io/docs/v5/asset/balance/asset-overview + */ + async getOverview(params: { + accountType?: string + memberId?: string + valuationCurrency?: string + }): Promise> { + return requestJson(this.http, this.opts, { + method: 'GET', + path: '/v5/asset/asset-overview', + signed: true, + query: params, + }) + } + + /** + * Small asset get quote + * @see https://bybit-exchange.github.io/docs/v5/asset/convert-small-balance/request-quote + */ + async smallAssetQuote(params: { + accountType: string + toCoin: string + fromCoinList: Array> + }): Promise> { + return requestJson(this.http, this.opts, { + method: 'POST', + path: '/v5/asset/covert/get-quote', + signed: true, + body: params, + }) + } + + /** + * Small asset confirm conversion + * @see https://bybit-exchange.github.io/docs/v5/asset/convert-small-balance/confirm-quote + */ + async smallAssetConvert(params: { + quoteId: string + }): Promise> { + return requestJson(this.http, this.opts, { + method: 'POST', + path: '/v5/asset/covert/small-balance-execute', + signed: true, + body: params, + }) + } + + /** + * Small asset conversion history query + * @see https://bybit-exchange.github.io/docs/v5/asset/convert-small-balance/exchange-history + */ + async getSmallAssetConvertOrder(params: { + accountType?: string + quoteId?: string + cursor?: string + size?: string + startTime?: string + endTime?: string + }): Promise> { + return requestJson(this.http, this.opts, { + method: 'GET', + path: '/v5/asset/covert/small-balance-history', + signed: true, + query: params, + }) + } + + /** + * Small asset conversion list query + * @see https://bybit-exchange.github.io/docs/v5/asset/convert-small-balance/small-balanc-coins + */ + async getSmallAssetList(params: { + accountType: string + fromCoin?: string + }): Promise> { + return requestJson(this.http, this.opts, { + method: 'GET', + path: '/v5/asset/covert/small-balance-list', + signed: true, + query: params, + }) + } + + /** + * Set Deposit Account + * @see https://bybit-exchange.github.io/docs/v5/asset/deposit/set-deposit-acct + */ + async setDefaultDepositToAccount(params: { + accountType: string + }): Promise> { + return requestJson(this.http, this.opts, { + method: 'POST', + path: '/v5/asset/deposit/deposit-to-account', + signed: true, + body: params, + }) + } + + /** + * Limit order callback notification + */ + async limitOrderCallback(params: { + exchangeTxId: string + optionType: number + errorCode?: string + timeStamp: number + sign: string + appId: string + }): Promise> { + return requestJson(this.http, this.opts, { + method: 'POST', + path: '/v5/asset/exchange/limit-order/callback', + signed: true, + body: params, + }) + } + + /** + * Query coin conversion limit + */ + async coinConvertLimitQuery(params: { + fromCoin: string + fromCoinType?: number + toCoin: string + toCoinType?: number + accountType: string + }): Promise> { + return requestJson(this.http, this.opts, { + method: 'GET', + path: '/v5/asset/exchange/query-convert-limit', + signed: true, + query: params, + }) + } + + /** + * Query conversion order list + */ + async getOrderFromOpen(params: { + accountType?: number + cursor?: string + limit?: number + toCoin?: string + fromCoin?: string + startTime?: number + endTime?: number + type?: number + exchangeStatus?: number + direction?: string + }): Promise> { + return requestJson(this.http, this.opts, { + method: 'GET', + path: '/v5/asset/exchange/query-order-list', + signed: true, + query: params, + }) + } + + /** + * Get Portfolio Margin Info + * @see https://bybit-exchange.github.io/docs/v5/asset/portfolio-margin + */ + async getPortfolioMargin(params: { + baseCoin?: string + }): Promise> { + return requestJson(this.http, this.opts, { + method: 'GET', + path: '/v5/asset/portfolio-margin', + signed: true, + query: params, + }) + } + + /** + * Get Total Members Assets + * @see https://bybit-exchange.github.io/docs/v5/asset/total-members-assets + */ + async getTotalMembersAssets(params: { + coin?: string + }): Promise> { + return requestJson(this.http, this.opts, { + method: 'GET', + path: '/v5/asset/total-members-assets', + signed: true, + query: params, + }) + } + + /** + * Save Transferable Sub Member List + * @see https://bybit-exchange.github.io/docs/v5/abandon/enable-unitransfer-subuid + */ + async transferSubMemberSave(params: { + subMemberIds: string + }): Promise> { + return requestJson(this.http, this.opts, { + method: 'POST', + path: '/v5/asset/transfer/save-transfer-sub-member', + signed: true, + body: params, + }) + } + + /** + * Get Withdrawal Address List + * @see https://bybit-exchange.github.io/docs/v5/asset/withdraw/withdraw-address + */ + async getWithdrawAddresses(params: { + coin?: string + chain?: string + addressType?: number + limit?: number + cursor?: string + }): Promise> { + return requestJson(this.http, this.opts, { + method: 'GET', + path: '/v5/asset/withdraw/query-address', + signed: true, + query: params, + }) + } + + /** + * Get Available VASPs + * @see https://bybit-exchange.github.io/docs/v5/asset/withdraw/vasp-list + */ + async getVaspList(): Promise> { + return requestJson(this.http, this.opts, { + method: 'GET', + path: '/v5/asset/withdraw/vasp/list', + signed: true, + }) + } + } diff --git a/src/rest-api/crypto-loan.ts b/src/rest-api/crypto-loan.ts index 60238a7..3a979e3 100644 --- a/src/rest-api/crypto-loan.ts +++ b/src/rest-api/crypto-loan.ts @@ -588,4 +588,37 @@ export class CryptoLoanService { }, }) } + + /** + * Get Available Inventory + * @see https://bybit-exchange.github.io/docs/v5/new-crypto-loan/fixed/available-inventory + */ + async getFixedAvailableInventory(params: { + currency: string + term: string + annualRate: string + }): Promise> { + return requestJson(this.http, this.opts, { + method: 'GET', + path: '/v5/crypto-loan-fixed/available-inventory', + signed: true, + query: params, + }) + } + + /** + * Get Available Inventory + * @see https://bybit-exchange.github.io/docs/v5/new-crypto-loan/flexible/available-inventory + */ + async getFlexibleAvailableInventory(params: { + currency: string + }): Promise> { + return requestJson(this.http, this.opts, { + method: 'GET', + path: '/v5/crypto-loan-flexible/available-inventory', + signed: true, + query: params, + }) + } + } diff --git a/src/rest-api/earn.ts b/src/rest-api/earn.ts index ba67311..dc663e4 100644 --- a/src/rest-api/earn.ts +++ b/src/rest-api/earn.ts @@ -1563,4 +1563,37 @@ export class EarnService { }, }) } + + /** + * Get Auto Savings Settings + * @see https://bybit-exchange.github.io/docs/v5/finance/earn/flexible-saving/auto-savings + */ + async listAutoSavings(params: { + coins?: string[] + }): Promise> { + return requestJson(this.http, this.opts, { + method: 'GET', + path: '/v5/earn/flexible-saving/auto-savings', + signed: true, + query: params, + }) + } + + /** + * Edit Auto Savings Settings + * @see https://bybit-exchange.github.io/docs/v5/finance/earn/flexible-saving/auto-savings + */ + async editEarnAutoSavings(params: { + coin?: string + isSelected: boolean + purchaseImmediately?: boolean + }): Promise> { + return requestJson(this.http, this.opts, { + method: 'POST', + path: '/v5/earn/flexible-saving/auto-savings', + signed: true, + body: params, + }) + } + } diff --git a/src/rest-api/index.ts b/src/rest-api/index.ts index 74af6a3..898154a 100644 --- a/src/rest-api/index.ts +++ b/src/rest-api/index.ts @@ -3,11 +3,13 @@ // gen-sdk-js:service-exports:start export { AccountService } from './account.js' export { AffiliateService } from './affiliate.js' +export { AlphaService } from './alpha.js' export { AssetService } from './asset.js' export { BotService } from './bot.js' export { BrokerService } from './broker.js' export { CryptoLoanService } from './crypto-loan.js' export { EarnService } from './earn.js' +export { LendingService } from './lending.js' export { MarketService } from './market.js' export { P2pService } from './p2p.js' export { PositionService } from './position.js' diff --git a/src/rest-api/lending.ts b/src/rest-api/lending.ts new file mode 100644 index 0000000..62cbd7a --- /dev/null +++ b/src/rest-api/lending.ts @@ -0,0 +1,173 @@ +import type { AxiosInstance } from 'axios' +import { requestJson } from '../http/request.js' +import type { ApiResponse } from '../types/common.js' +import type { RestClientOptions } from '../config.js' + +export class LendingService { + protected readonly opts!: RestClientOptions + + constructor( + protected readonly http: AxiosInstance, + opts: RestClientOptions, + ) { + Object.defineProperty(this, 'opts', { + value: opts, + writable: false, + enumerable: false, + configurable: false, + }) + } + + /** + * Bind/Unbind UID + * @see https://bybit-exchange.github.io/docs/v5/otc/bind-uid + */ + async insLoanAssociationUid(params: { + uid: string + operate: string + }): Promise> { + return requestJson(this.http, this.opts, { + method: 'POST', + path: '/v5/ins-loan/association-uid', + signed: true, + body: params, + }) + } + + /** + * Get Coin Delta Amount + * @see https://bybit-exchange.github.io/docs/v5/otc/coin-delta-amount + */ + async insLoanCoinDeltaAmount(params: { + coin?: string + }): Promise> { + return requestJson(this.http, this.opts, { + method: 'GET', + path: '/v5/ins-loan/coin-delta-amount', + signed: true, + query: params, + }) + } + + /** + * Get Delay Liquidation Status + * API key must belong to an institutional lending account. + * @see https://bybit-exchange.github.io/docs/v5/otc/delay-liq-status + */ + async insLoanDelayLiqStatus(): Promise> { + return requestJson(this.http, this.opts, { + method: 'GET', + path: '/v5/ins-loan/delay-liq-status', + signed: true, + }) + } + + /** + * Get Margin Tokens + * @see https://bybit-exchange.github.io/docs/v5/abandon/margin-coin-info + */ + async insLoanEnsureTokens(params: { + productId?: string + }): Promise> { + return requestJson(this.http, this.opts, { + method: 'GET', + path: '/v5/ins-loan/ensure-tokens', + signed: true, + query: params, + }) + } + + /** + * Get Margin Token Conversion Details + * @see https://bybit-exchange.github.io/docs/v5/otc/margin-coin-convert-info + */ + async insLoanEnsureTokensConvert(params: { + productId?: string + }): Promise> { + return requestJson(this.http, this.opts, { + method: 'GET', + path: '/v5/ins-loan/ensure-tokens-convert', + signed: true, + query: params, + }) + } + + /** + * Get Loan Orders + * @see https://bybit-exchange.github.io/docs/v5/otc/loan-info + */ + async insLoanGetLoanOrder(params: { + orderId?: string + startTime?: number + endTime?: number + limit?: number + }): Promise> { + return requestJson(this.http, this.opts, { + method: 'GET', + path: '/v5/ins-loan/loan-order', + signed: true, + query: params, + }) + } + + /** + * Get LTV with Conversion Details + * @see https://bybit-exchange.github.io/docs/v5/otc/ltv-convert + */ + async insLoanLtvConvert(): Promise> { + return requestJson(this.http, this.opts, { + method: 'GET', + path: '/v5/ins-loan/ltv-convert', + signed: true, + }) + } + + /** + * Get Product Infos + * @see https://bybit-exchange.github.io/docs/v5/otc/margin-product-info + */ + async insLoanProductInfos(params: { + productId?: string + }): Promise> { + return requestJson(this.http, this.opts, { + method: 'GET', + path: '/v5/ins-loan/product-infos', + signed: true, + query: params, + }) + } + + /** + * Get Repaid History + * @see https://bybit-exchange.github.io/docs/v5/otc/repay-info + */ + async insLoanRepaidHistory(params: { + startTime?: number + endTime?: number + limit?: number + }): Promise> { + return requestJson(this.http, this.opts, { + method: 'GET', + path: '/v5/ins-loan/repaid-history', + signed: true, + query: params, + }) + } + + /** + * Repay Loan + * @see https://bybit-exchange.github.io/docs/v5/otc/repay + */ + async insLoanRepayLoan(params: { + token: string + quantity: string + }): Promise> { + return requestJson(this.http, this.opts, { + method: 'POST', + path: '/v5/ins-loan/repay-loan', + signed: true, + body: params, + }) + } + +} diff --git a/src/rest-api/market.ts b/src/rest-api/market.ts index 6e27485..93db482 100644 --- a/src/rest-api/market.ts +++ b/src/rest-api/market.ts @@ -493,4 +493,37 @@ export class MarketService { }, }) } + + /** + * Get New Delivery Price + * @see https://bybit-exchange.github.io/docs/v5/market/new-delivery-price + */ + async getNewDeliveryPrice(params: { + category: string + baseCoin: string + settleCoin?: string + }): Promise> { + return requestJson(this.http, this.opts, { + method: 'GET', + path: '/v5/market/new-delivery-price', + signed: false, + query: params, + }) + } + + /** + * Get Option Base Coins + * @see https://bybit-exchange.github.io/docs/v5/market/option-base-coins + */ + async getOptionBaseCoins(params: { + underlyingType?: number + }): Promise> { + return requestJson(this.http, this.opts, { + method: 'GET', + path: '/v5/market/option-base-coins', + signed: false, + query: params, + }) + } + } diff --git a/src/rest-api/position.ts b/src/rest-api/position.ts index 064113d..2e70b01 100644 --- a/src/rest-api/position.ts +++ b/src/rest-api/position.ts @@ -298,4 +298,21 @@ export class PositionService { }, }) } + + /** + * Get Futures Leverage + * @see https://bybit-exchange.github.io/docs/v5/position/batch-lvg + */ + async getSymbolInfo(params: { + category: string + symbol?: string + }): Promise> { + return requestJson(this.http, this.opts, { + method: 'GET', + path: '/v5/position/symbol-info', + signed: true, + query: params, + }) + } + } diff --git a/src/rest-api/spot-margin.ts b/src/rest-api/spot-margin.ts index 991443e..d33c533 100644 --- a/src/rest-api/spot-margin.ts +++ b/src/rest-api/spot-margin.ts @@ -84,4 +84,265 @@ export class SpotMarginService { }, }) } + + /** + * Get Spot Margin Coin State + * @see https://bybit-exchange.github.io/docs/v5/spot-margin-uta/coinstate + */ + async getTradeCoinState(params: { + currency?: string + }): Promise> { + return requestJson(this.http, this.opts, { + method: 'GET', + path: '/v5/spot-margin-trade/coinstate', + signed: true, + query: params, + }) + } + + /** + * Query Fixed-Rate Available Inventory + * @see https://bybit-exchange.github.io/docs/v5/spot-margin-uta/fixed-available-inventory + */ + async queryFixedAvailableInventory(params: { + currency: string + term: string + annualRate: string + }): Promise> { + return requestJson(this.http, this.opts, { + method: 'GET', + path: '/v5/spot-margin-trade/fixed-available-inventory', + signed: true, + query: params, + }) + } + + /** + * Fixed-Rate Borrow + * @see https://bybit-exchange.github.io/docs/v5/spot-margin-uta/fixedborrow + */ + async accountFixedBorrow(params: { + orderCurrency: string + orderAmount: string + annualRate: string + term: string + repayType?: string + strategyType?: string + }): Promise> { + return requestJson(this.http, this.opts, { + method: 'POST', + path: '/v5/spot-margin-trade/fixedborrow', + signed: true, + body: params, + }) + } + + /** + * Query Fixed-Rate Borrow Contracts + * @see https://bybit-exchange.github.io/docs/v5/spot-margin-uta/fixedborrow-contract-info + */ + async queryFixedBorrowContracts(params: { + orderId?: string + orderCurrency?: string + term?: string + limit?: string + cursor?: string + }): Promise> { + return requestJson(this.http, this.opts, { + method: 'GET', + path: '/v5/spot-margin-trade/fixedborrow-contract-info', + signed: true, + query: params, + }) + } + + /** + * Query Fixed-Rate Borrow Orders + * @see https://bybit-exchange.github.io/docs/v5/spot-margin-uta/fixedborrow-order-info + */ + async queryFixedBorrowOrders(params: { + orderId?: string + orderCurrency?: string + state?: string + term?: string + limit?: string + cursor?: string + }): Promise> { + return requestJson(this.http, this.opts, { + method: 'GET', + path: '/v5/spot-margin-trade/fixedborrow-order-info', + signed: true, + query: params, + }) + } + + /** + * Query Fixed-Rate Borrow Market + * @see https://bybit-exchange.github.io/docs/v5/spot-margin-uta/fixedborrow-order-quote + */ + async queryFixedBorrowMarket(params: { + orderCurrency: string + term?: string + orderBy: string + sort?: number + limit?: number + }): Promise> { + return requestJson(this.http, this.opts, { + method: 'GET', + path: '/v5/spot-margin-trade/fixedborrow-order-quote', + signed: true, + query: params, + }) + } + + /** + * Renew Fixed-Rate Borrow + * @see https://bybit-exchange.github.io/docs/v5/spot-margin-uta/fixedborrow-renew + */ + async renewFixedBorrow(params: { + loanId: string + qty?: string + }): Promise> { + return requestJson(this.http, this.opts, { + method: 'POST', + path: '/v5/spot-margin-trade/fixedborrow-renew', + signed: true, + body: params, + }) + } + + /** + * Get Flexible Available Inventory + * @see https://bybit-exchange.github.io/docs/v5/spot-margin-uta/flexible-available-inventory + */ + async getTradeFlexibleAvailableInventory(params: { + currency: string + }): Promise> { + return requestJson(this.http, this.opts, { + method: 'GET', + path: '/v5/spot-margin-trade/flexible-available-inventory', + signed: true, + query: params, + }) + } + + /** + * Get Auto Repay Mode + * @see https://bybit-exchange.github.io/docs/v5/spot-margin-uta/get-auto-repay-mode + */ + async getTradeAutoRepayMode(params: { + currency?: string + }): Promise> { + return requestJson(this.http, this.opts, { + method: 'GET', + path: '/v5/spot-margin-trade/get-auto-repay-mode', + signed: true, + query: params, + }) + } + + /** + * Query Borrow Liability + * @see https://bybit-exchange.github.io/docs/v5/spot-margin-uta/liability + */ + async queryBorrowLiability(params: { + currency: string + }): Promise> { + return requestJson(this.http, this.opts, { + method: 'GET', + path: '/v5/spot-margin-trade/liability', + signed: true, + query: params, + }) + } + + /** + * Get Max Borrowable Amount + * @see https://bybit-exchange.github.io/docs/v5/spot-margin-uta/max-borrowable + */ + async getTradeMaxBorrowable(params: { + currency: string + }): Promise> { + return requestJson(this.http, this.opts, { + method: 'GET', + path: '/v5/spot-margin-trade/max-borrowable', + signed: true, + query: params, + }) + } + + /** + * Get Repayment Available Amount + * @see https://bybit-exchange.github.io/docs/v5/spot-margin-uta/repayment-available-amount + */ + async getTradeRepaymentAvailableAmount(params: { + currency: string + }): Promise> { + return requestJson(this.http, this.opts, { + method: 'GET', + path: '/v5/spot-margin-trade/repayment-available-amount', + signed: true, + query: params, + }) + } + + /** + * Set Auto Repay Mode + * @see https://bybit-exchange.github.io/docs/v5/spot-margin-uta/set-auto-repay-mode + */ + async setAutoRepayMode(params: { + currency?: string + autoRepayMode: string + }): Promise> { + return requestJson(this.http, this.opts, { + method: 'POST', + path: '/v5/spot-margin-trade/set-auto-repay-mode', + signed: true, + body: params, + }) + } + + /** + * Set spot cross margin leverage + * @see https://bybit-exchange.github.io/docs/v5/spot-margin-uta/set-leverage + */ + async spotMarginSetLeverage(params: { + leverage: string + currency?: string + }): Promise> { + return requestJson(this.http, this.opts, { + method: 'POST', + path: '/v5/spot-margin-trade/set-leverage', + signed: true, + body: params, + }) + } + + /** + * Get Spot Margin Trade Status + * @see https://bybit-exchange.github.io/docs/v5/spot-margin-uta/status + */ + async getTradeState(): Promise> { + return requestJson(this.http, this.opts, { + method: 'GET', + path: '/v5/spot-margin-trade/state', + signed: true, + }) + } + + /** + * Toggle spot cross margin mode + * @see https://bybit-exchange.github.io/docs/v5/spot-margin-uta/switch-mode + */ + async spotMarginSwitchMode(params: { + spotMarginMode: string + }): Promise> { + return requestJson(this.http, this.opts, { + method: 'POST', + path: '/v5/spot-margin-trade/switch-mode', + signed: true, + body: params, + }) + } + } diff --git a/src/rest-api/user.ts b/src/rest-api/user.ts index 4913e44..1545536 100644 --- a/src/rest-api/user.ts +++ b/src/rest-api/user.ts @@ -334,4 +334,17 @@ export class UserService { }, }) } + + /** + * Query Referral Code + * @see https://bybit-exchange.github.io/docs/v5/user/referral-code + */ + async queryReferralCode(): Promise> { + return requestJson(this.http, this.opts, { + method: 'GET', + path: '/v5/user/invitation/code', + signed: true, + }) + } + } diff --git a/tests/alpha.test.ts b/tests/alpha.test.ts new file mode 100644 index 0000000..68a2f7a --- /dev/null +++ b/tests/alpha.test.ts @@ -0,0 +1,259 @@ +import axios, { type AxiosRequestConfig } from 'axios' +import { BybitClient } from '../src/client' + +const goodBody = { retCode: 0, retMsg: 'OK', result: {}, retExtInfo: {}, time: 1 } + +function capturingClient(): { client: BybitClient; calls: AxiosRequestConfig[] } { + const calls: AxiosRequestConfig[] = [] + const instance = axios.create() + ;(instance as unknown as { request: (config: AxiosRequestConfig) => unknown }).request = ( + config, + ) => { + calls.push(config) + return Promise.resolve({ status: 200, data: goodBody, headers: {}, statusText: '', config }) + } + return { + client: new BybitClient({ apiKey: 'K', apiSecret: 'S', axiosInstance: instance }), + calls, + } +} + +function expectPost( + calls: AxiosRequestConfig[], + path: string, + body: Record, +): void { + const call = calls.at(-1) + expect(call?.method).toBe('POST') + expect(call?.url).toBe(path) + expect(JSON.parse(String(call?.data))).toEqual(body) +} + +describe('AlphaService — official request contracts', () => { + it('sends string arrays for batch token requests', async () => { + const { client, calls } = capturingClient() + + await client.alpha.getLpPayTokenPrice({ tokenCode: ['CEX_1', 'CEX_2'], chainCode: 'SOL' }) + expectPost(calls, '/v5/alpha/lp/pay-token-price', { + tokenCode: ['CEX_1', 'CEX_2'], + chainCode: 'SOL', + }) + + await client.alpha.getPredictionOrderBook({ tokenIds: ['token_yes_123', 'token_no_123'] }) + expectPost(calls, '/v5/alpha/prediction/order-book', { + tokenIds: ['token_yes_123', 'token_no_123'], + }) + + await client.alpha.getPredictionTokenPrice({ tokenIds: ['token_yes_123', 'token_no_123'] }) + expectPost(calls, '/v5/alpha/prediction/token-price', { + tokenIds: ['token_yes_123', 'token_no_123'], + }) + }) + + it('uses numeric prediction enums for buy, sell, and estimate', async () => { + const { client, calls } = capturingClient() + + await client.alpha.executePredictionBuy({ + tokenId: 'token_yes_123', + amount: '100', + payTokenCode: 'USDC', + orderType: 1, + slippage: '0.05', + eventId: 'event_123', + }) + expectPost(calls, '/v5/alpha/prediction/buy', { + tokenId: 'token_yes_123', + amount: '100', + payTokenCode: 'USDC', + orderType: 1, + slippage: '0.05', + eventId: 'event_123', + }) + + await client.alpha.executePredictionSell({ + tokenId: 'token_yes_123', + size: '50', + orderType: 1, + slippage: '0.05', + eventId: 'event_123', + toTokenCode: 'USDC', + }) + expectPost(calls, '/v5/alpha/prediction/sell', { + tokenId: 'token_yes_123', + size: '50', + orderType: 1, + slippage: '0.05', + eventId: 'event_123', + toTokenCode: 'USDC', + }) + + await client.alpha.getPredictionOrderEstimate({ + tokenId: 'token_yes_123', + side: 1, + eventId: 'event_123', + amount: '100', + orderType: 1, + payTokenCode: 'USDC', + }) + expectPost(calls, '/v5/alpha/prediction/order-estimate', { + tokenId: 'token_yes_123', + side: 1, + eventId: 'event_123', + amount: '100', + orderType: 1, + payTokenCode: 'USDC', + }) + }) + + it('sends the documented price history and side market fields', async () => { + const { client, calls } = capturingClient() + + await client.alpha.getPredictionPriceHistory({ tokenId: 'token_yes_123', interval: '1H' }) + expectPost(calls, '/v5/alpha/prediction/price-history', { + tokenId: 'token_yes_123', + interval: '1H', + }) + + await client.alpha.getPredictionSideMarketList({ + eventId: 'event_123', + sortBy: 'volume', + marketType: 1, + limit: 20, + pageIndex: 1, + }) + expectPost(calls, '/v5/alpha/prediction/side-market-list', { + eventId: 'event_123', + sortBy: 'volume', + marketType: 1, + limit: 20, + pageIndex: 1, + }) + }) + + it('sends documented filters for positions and portfolio summary', async () => { + const { client, calls } = capturingClient() + + await client.alpha.getPredictionPositionHistory({ + tokenId: 'token_yes_123', + eventId: 'event_123', + result: 1, + days: 30, + limit: 20, + pageIndex: 1, + }) + expectPost(calls, '/v5/alpha/prediction/position-history', { + tokenId: 'token_yes_123', + eventId: 'event_123', + result: 1, + days: 30, + limit: 20, + pageIndex: 1, + }) + + await client.alpha.getPredictionPositionList({ + tokenId: 'token_yes_123', + eventId: 'event_123', + limit: 20, + pageIndex: 1, + }) + expectPost(calls, '/v5/alpha/prediction/position-list', { + tokenId: 'token_yes_123', + eventId: 'event_123', + limit: 20, + pageIndex: 1, + }) + + await client.alpha.getPredictionPortfolioSummary({ eventType: 1 }) + expectPost(calls, '/v5/alpha/prediction/portfolio-summary', { eventType: 1 }) + }) + + it('uses numeric prediction order filters', async () => { + const { client, calls } = capturingClient() + + await client.alpha.getPredictionOrderList({ + status: 2, + tokenId: 'token_yes_123', + eventId: 'event_123', + side: 1, + days: 30, + limit: 20, + pageIndex: 1, + }) + expectPost(calls, '/v5/alpha/prediction/order-list', { + status: 2, + tokenId: 'token_yes_123', + eventId: 'event_123', + side: 1, + days: 30, + limit: 20, + pageIndex: 1, + }) + }) + + it('sends the documented sports prediction fields', async () => { + const { client, calls } = capturingClient() + + await client.alpha.getPredictionGroupStageDetail({ eventType: 1, groupName: 'A' }) + expectPost(calls, '/v5/alpha/prediction/sports/group-stage-detail', { + eventType: 1, + groupName: 'A', + }) + + await client.alpha.getPredictionMatchList({ + eventType: 1, + status: 2, + startTime: 1_780_000_000_000, + endTime: 1_790_000_000_000, + stageCode: 'GROUP_STAGE', + limit: 20, + pageIndex: 1, + }) + expectPost(calls, '/v5/alpha/prediction/sports/match-list', { + eventType: 1, + status: 2, + startTime: 1_780_000_000_000, + endTime: 1_790_000_000_000, + stageCode: 'GROUP_STAGE', + limit: 20, + pageIndex: 1, + }) + + await client.alpha.getPredictionTimelineStages({ eventType: 1 }) + const timelineCall = calls.at(-1) + expect(timelineCall?.method).toBe('GET') + expect(timelineCall?.url).toBe( + '/v5/alpha/prediction/sports/timeline-stages?eventType=1', + ) + }) + + it('sends numeric trade order statuses with required pagination', async () => { + const { client, calls } = capturingClient() + + await client.alpha.getLpOrderList({ orderStatus: [1, 2] }) + expectPost(calls, '/v5/alpha/lp/order-list', { orderStatus: [1, 2] }) + + await client.alpha.getOrderList({ + tradeType: 1, + tokenCode: 'DEX_123', + orderStatus: [1, 2], + days: 30, + limit: 20, + pageIndex: 1, + direction: 'next', + }) + expectPost(calls, '/v5/alpha/trade/order-list', { + tradeType: 1, + tokenCode: 'DEX_123', + orderStatus: [1, 2], + days: 30, + limit: 20, + pageIndex: 1, + direction: 'next', + }) + + if (false) { + // @ts-expect-error limit and pageIndex are required by the API contract + await client.alpha.getOrderList({ tradeType: 1 }) + } + }) +}) diff --git a/tests/client.test.ts b/tests/client.test.ts index 92ac1e3..de90c75 100644 --- a/tests/client.test.ts +++ b/tests/client.test.ts @@ -6,11 +6,11 @@ import { BASE_URL_MAINNET, BASE_URL_TESTNET, DEFAULT_TIMEOUT_MS } from '../src/c const anyOpts = (o: unknown) => o as never describe('BybitClient — service surface', () => { - it('exposes all 14 service instances on the client', () => { + it('exposes all 16 service instances on the client', () => { const c = new BybitClient() for (const svc of [ - 'account', 'affiliate', 'asset', 'bot', 'broker', 'cryptoLoan', - 'earn', 'market', 'p2p', 'position', 'rfq', 'spotMargin', 'trade', 'user', + 'account', 'affiliate', 'alpha', 'asset', 'bot', 'broker', 'cryptoLoan', + 'earn', 'lending', 'market', 'p2p', 'position', 'rfq', 'spotMargin', 'trade', 'user', ]) { expect((c as unknown as Record)[svc]).toBeDefined() } diff --git a/tests/earn.test.ts b/tests/earn.test.ts new file mode 100644 index 0000000..1db40a6 --- /dev/null +++ b/tests/earn.test.ts @@ -0,0 +1,23 @@ +import axios, { type AxiosRequestConfig } from 'axios' +import { BybitClient } from '../src/client' + +const goodBody = { retCode: 0, retMsg: 'OK', result: {}, retExtInfo: {}, time: 1 } + +describe('EarnService — official request contracts', () => { + it('sends Auto Savings coins as repeated query parameters', async () => { + let captured: AxiosRequestConfig | undefined + const instance = axios.create() + ;(instance as unknown as { request: (config: AxiosRequestConfig) => unknown }).request = ( + config, + ) => { + captured = config + return Promise.resolve({ status: 200, data: goodBody, headers: {}, statusText: '', config }) + } + const client = new BybitClient({ apiKey: 'K', apiSecret: 'S', axiosInstance: instance }) + + await client.earn.listAutoSavings({ coins: ['BTC', 'ETH'] }) + + expect(captured?.method).toBe('GET') + expect(captured?.url).toBe('/v5/earn/flexible-saving/auto-savings?coins=BTC&coins=ETH') + }) +}) diff --git a/tests/request.test.ts b/tests/request.test.ts index 36959d4..5d52075 100644 --- a/tests/request.test.ts +++ b/tests/request.test.ts @@ -60,6 +60,30 @@ describe('requestJson — signing', () => { expect(headers['X-BAPI-SIGN']).toBe(expected) }) + it('repeats array query parameters in both the URL and signature payload', async () => { + let captured: AxiosRequestConfig | undefined + const http = fakeHttp((cfg) => { + captured = cfg + return { status: 200, data: goodBody } + }) + await requestJson(http, { apiKey: 'K', apiSecret: 'S', recvWindow: '5000' }, { + method: 'GET', + path: '/v5/earn/flexible-saving/auto-savings', + signed: true, + query: { coins: ['BTC', 'ETH'] }, + }) + + const headers = captured!.headers as Record + const query = 'coins=BTC&coins=ETH' + expect(captured!.url).toBe('/v5/earn/flexible-saving/auto-savings?' + query) + const ts = headers['X-BAPI-TIMESTAMP'] + const expected = crypto + .createHmac('sha256', 'S') + .update(ts + 'K' + '5000' + query) + .digest('hex') + expect(headers['X-BAPI-SIGN']).toBe(expected) + }) + it('signs POST requests over the exact bytes it puts on the wire', async () => { let captured: AxiosRequestConfig | undefined const http = fakeHttp((cfg) => { diff --git a/tests/services.smoke.test.ts b/tests/services.smoke.test.ts index 0df6787..238d7a8 100644 --- a/tests/services.smoke.test.ts +++ b/tests/services.smoke.test.ts @@ -10,8 +10,8 @@ import axios from 'axios' import { BybitClient } from '../src/client' const SERVICES = [ - 'account', 'affiliate', 'asset', 'bot', 'broker', 'cryptoLoan', - 'earn', 'market', 'p2p', 'position', 'rfq', 'spotMargin', 'trade', 'user', + 'account', 'affiliate', 'alpha', 'asset', 'bot', 'broker', 'cryptoLoan', + 'earn', 'lending', 'market', 'p2p', 'position', 'rfq', 'spotMargin', 'trade', 'user', ] as const // Well-formed placeholder for every field the SDK is known to send. Unknown fields @@ -163,6 +163,11 @@ describe('every service method → one HTTP request', () => { client = new BybitClient({ apiKey: 'K', apiSecret: 'S', axiosInstance: c.instance }) }) + it('tracks every service exposed by BybitClient', () => { + const exposedServices = Object.keys(client).filter((name) => name !== 'http').sort() + expect([...SERVICES].sort()).toEqual(exposedServices) + }) + for (const svcName of SERVICES) { describe(svcName, () => { it('does not lose any methods to a bad build', () => { diff --git a/tsconfig.test.json b/tsconfig.test.json new file mode 100644 index 0000000..5ef9dbe --- /dev/null +++ b/tsconfig.test.json @@ -0,0 +1,11 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "rootDir": ".", + "noEmit": true, + "declaration": false, + "sourceMap": false + }, + "include": ["src/**/*", "tests/**/*"], + "exclude": ["node_modules", "dist", "coverage", "examples"] +}