From 28f420154c6dafe1dfa2a1d1f59880d307999658 Mon Sep 17 00:00:00 2001 From: doris-xiao-bybit Date: Wed, 28 Oct 2026 15:41:45 +0800 Subject: [PATCH 1/3] update sdk version --- CHANGELOG.md | 98 +++++ composer.json | 2 +- phpunit.xml.dist | 5 - src/Bybit.php | 2 +- src/Client.php | 30 ++ src/RestApi/AlphaService.php | 681 +++++++++++++++++++++++++++++ src/RestApi/EventService.php | 89 ++++ src/RestApi/FiatService.php | 127 ++++++ src/RestApi/LendingService.php | 138 ++++++ src/RestApi/PreUpgradeService.php | 141 ++++++ src/RestApi/ReferralService.php | 65 +++ src/RestApi/SpotMarginService.php | 33 ++ src/RestApi/SpotXService.php | 134 ++++++ src/RestApi/SpreadTradeService.php | 215 +++++++++ src/RestApi/StrategyService.php | 85 ++++ src/RestApi/TaxService.php | 49 +++ tests/RestApiContractTest.php | 146 ++++++- tests/RestApiSmokeTest.php | 14 +- 18 files changed, 2042 insertions(+), 12 deletions(-) create mode 100644 src/RestApi/AlphaService.php create mode 100644 src/RestApi/EventService.php create mode 100644 src/RestApi/FiatService.php create mode 100644 src/RestApi/LendingService.php create mode 100644 src/RestApi/PreUpgradeService.php create mode 100644 src/RestApi/ReferralService.php create mode 100644 src/RestApi/SpotXService.php create mode 100644 src/RestApi/SpreadTradeService.php create mode 100644 src/RestApi/StrategyService.php create mode 100644 src/RestApi/TaxService.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 9b10c57..00ba9c6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,102 @@ # Changelog + +## 0.1.2 — 2026-10-28 + +### Added +- `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(...)` +- `EventService::getEcOrderHistory(...)` +- `EventService::getEcActiveOrders(...)` +- `EventService::getEcPositionInfo(...)` +- `EventService::getEcSettlements(...)` +- `EventService::getEcTradeHistory(...)` +- `TaxService::batchCreateTaxReports(...)` +- `TaxService::batchQueryTaxReports(...)` +- `FiatService::queryBalance(...)` +- `FiatService::queryCoinList(...)` +- `FiatService::queryTradeHistory(...)` +- `FiatService::applyQuote(...)` +- `FiatService::getReferencePrice(...)` +- `FiatService::confirmQuote(...)` +- `FiatService::queryTrade(...)` +- `LendingService::insLoanAssociationUid(...)` +- `LendingService::insLoanCoinDeltaAmount(...)` +- `LendingService::insLoanDelayLiqStatus(...)` +- `LendingService::insLoanEnsureTokensConvert(...)` +- `LendingService::insLoanGetLoanOrder(...)` +- `LendingService::insLoanLtvConvert(...)` +- `LendingService::insLoanProductInfos(...)` +- `LendingService::insLoanRepaidHistory(...)` +- `LendingService::insLoanRepayLoan(...)` +- `PreUpgradeService::getTransactionLog(...)` +- `PreUpgradeService::getDeliveryRecord(...)` +- `PreUpgradeService::getSettlementRecord(...)` +- `PreUpgradeService::getExecutionList(...)` +- `PreUpgradeService::getOrderHistory(...)` +- `PreUpgradeService::getClosedPnl(...)` +- `ReferralService::getCampaignRewards(...)` +- `ReferralService::getCommissionRecords(...)` +- `ReferralService::getUserIdentityProfile(...)` +- `ReferralService::getUserInvitations(...)` +- `SpotMarginService::queryFixedBorrowPenaltyInterest(...)` +- `SpotMarginService::cancelFixedBorrowOrder(...)` +- `SpotXService::getLaunchpoolProjectList(...)` +- `SpotXService::getLaunchpoolUserActivityLog(...)` +- `SpotXService::getLaunchpoolUserCurrentStaking(...)` +- `SpotXService::getLaunchpoolUserHistory(...)` +- `SpotXService::getPuzzleProjectList(...)` +- `SpotXService::getTokenSplashProjectList(...)` +- `SpotXService::getTokenSplashUserActivityParams(...)` +- `SpreadTradeService::getHistory(...)` +- `SpreadTradeService::getSpreadInstrumentsInfo(...)` +- `SpreadTradeService::getSpreadMaxQty(...)` +- `SpreadTradeService::amendSpreadOrder(...)` +- `SpreadTradeService::cancelSpreadOrder(...)` +- `SpreadTradeService::cancelAllSpreadOrders(...)` +- `SpreadTradeService::createSpreadOrder(...)` +- `SpreadTradeService::getSpreadOrderHistory(...)` +- `SpreadTradeService::getSpreadOpenOrders(...)` +- `SpreadTradeService::getSpreadOrderbook(...)` +- `SpreadTradeService::getSpreadRecentTrades(...)` +- `SpreadTradeService::getSpreadTickers(...)` +- `StrategyService::createStrategy(...)` +- `StrategyService::queryList(...)` +- `StrategyService::queryOrderList(...)` +- `StrategyService::stopStrategy(...)` + ## 0.1.1 — 2026-10-09 ### Added diff --git a/composer.json b/composer.json index 21361a7..497190e 100644 --- a/composer.json +++ b/composer.json @@ -22,7 +22,7 @@ "require": { "php": ">=8.1", "ext-json": "*", - "guzzlehttp/guzzle": "^7.5" + "guzzlehttp/guzzle": "^7.16.1" }, "require-dev": { "phpunit/phpunit": "^10.5", diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 397a1ca..79376df 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -18,9 +18,4 @@ src - - - - - diff --git a/src/Bybit.php b/src/Bybit.php index 18a2013..1e0ba79 100644 --- a/src/Bybit.php +++ b/src/Bybit.php @@ -9,7 +9,7 @@ */ final class Bybit { - public const VERSION = '0.1.1'; + public const VERSION = '0.1.2'; public const BASE_URL_MAINNET = 'https://api.bybit.com'; public const BASE_URL_TESTNET = 'https://api-testnet.bybit.com'; diff --git a/src/Client.php b/src/Client.php index ebf1cfa..a8ab362 100644 --- a/src/Client.php +++ b/src/Client.php @@ -7,16 +7,26 @@ // gen-sdk-php:service-uses:start use Bybit\RestApi\AccountService; use Bybit\RestApi\AffiliateService; +use Bybit\RestApi\AlphaService; use Bybit\RestApi\AssetService; use Bybit\RestApi\BotService; use Bybit\RestApi\BrokerService; use Bybit\RestApi\CryptoLoanService; use Bybit\RestApi\EarnService; +use Bybit\RestApi\EventService; +use Bybit\RestApi\FiatService; +use Bybit\RestApi\LendingService; use Bybit\RestApi\MarketService; use Bybit\RestApi\P2pService; use Bybit\RestApi\PositionService; +use Bybit\RestApi\PreUpgradeService; +use Bybit\RestApi\ReferralService; use Bybit\RestApi\RfqService; use Bybit\RestApi\SpotMarginService; +use Bybit\RestApi\SpotXService; +use Bybit\RestApi\SpreadTradeService; +use Bybit\RestApi\StrategyService; +use Bybit\RestApi\TaxService; use Bybit\RestApi\TradeService; use Bybit\RestApi\UserService; @@ -30,16 +40,26 @@ final class Client // gen-sdk-php:client-properties:start public readonly AccountService $account; public readonly AffiliateService $affiliate; + public readonly AlphaService $alpha; public readonly AssetService $asset; public readonly BotService $bot; public readonly BrokerService $broker; public readonly CryptoLoanService $cryptoLoan; public readonly EarnService $earn; + public readonly EventService $event; + public readonly FiatService $fiat; + public readonly LendingService $lending; public readonly MarketService $market; public readonly P2pService $p2p; public readonly PositionService $position; + public readonly PreUpgradeService $preUpgrade; + public readonly ReferralService $referral; public readonly RfqService $rfq; public readonly SpotMarginService $spotMargin; + public readonly SpotXService $spotX; + public readonly SpreadTradeService $spreadTrade; + public readonly StrategyService $strategy; + public readonly TaxService $tax; public readonly TradeService $trade; public readonly UserService $user; // gen-sdk-php:client-properties:end @@ -52,16 +72,26 @@ public function __construct(?Configuration $config = null) // gen-sdk-php:client-inits:start $this->account = new AccountService($this->session); $this->affiliate = new AffiliateService($this->session); + $this->alpha = new AlphaService($this->session); $this->asset = new AssetService($this->session); $this->bot = new BotService($this->session); $this->broker = new BrokerService($this->session); $this->cryptoLoan = new CryptoLoanService($this->session); $this->earn = new EarnService($this->session); + $this->event = new EventService($this->session); + $this->fiat = new FiatService($this->session); + $this->lending = new LendingService($this->session); $this->market = new MarketService($this->session); $this->p2p = new P2pService($this->session); $this->position = new PositionService($this->session); + $this->preUpgrade = new PreUpgradeService($this->session); + $this->referral = new ReferralService($this->session); $this->rfq = new RfqService($this->session); $this->spotMargin = new SpotMarginService($this->session); + $this->spotX = new SpotXService($this->session); + $this->spreadTrade = new SpreadTradeService($this->session); + $this->strategy = new StrategyService($this->session); + $this->tax = new TaxService($this->session); $this->trade = new TradeService($this->session); $this->user = new UserService($this->session); // gen-sdk-php:client-inits:end diff --git a/src/RestApi/AlphaService.php b/src/RestApi/AlphaService.php new file mode 100644 index 0000000..deb2401 --- /dev/null +++ b/src/RestApi/AlphaService.php @@ -0,0 +1,681 @@ +session->signRequest('POST', '/v5/alpha/lp/order-list', $options); + } + + /** + * Get list of supported payment tokens + * + * POST /v5/alpha/lp/pay-token-list + * + * @param array $options + * @return array Bybit V5 ApiResponse envelope (retCode / retMsg / result / retExtInfo / time). + * @see https://bybit-exchange.github.io/docs/v5/alpha/lp/pay-token-list + */ + public function getLpPayTokenList(array $options = []): array + { + return $this->session->signRequest('POST', '/v5/alpha/lp/pay-token-list', $options); + } + + /** + * Get current prices for payment tokens + * + * POST /v5/alpha/lp/pay-token-price + * + * @param array $tokenCode Array of token codes to query (e.g., ["CEX_1", "CEX_2"]). + * @param array $options + * @return array Bybit V5 ApiResponse envelope (retCode / retMsg / result / retExtInfo / time). + * @see https://bybit-exchange.github.io/docs/v5/alpha/lp/pay-token-price + */ + public function getLpPayTokenPrice(array $tokenCode, array $options = []): array + { + return $this->session->signRequest( + 'POST', + '/v5/alpha/lp/pay-token-price', + array_merge($options, ['tokenCode' => $tokenCode]) + ); + } + + /** + * Get detailed information for a specific LP pool + * + * POST /v5/alpha/lp/pool-info + * + * @param string $poolAddress Pool contract address (from getLPPoolList). + * @param array $options + * @return array Bybit V5 ApiResponse envelope (retCode / retMsg / result / retExtInfo / time). + * @see https://bybit-exchange.github.io/docs/v5/alpha/lp/pool-info + */ + public function getLpPoolInfo(string $poolAddress, array $options = []): array + { + return $this->session->signRequest( + 'POST', + '/v5/alpha/lp/pool-info', + array_merge($options, ['poolAddress' => $poolAddress]) + ); + } + + /** + * Get LP pool list with optional filters + * + * POST /v5/alpha/lp/pool-list + * + * @param array $options + * @return array Bybit V5 ApiResponse envelope (retCode / retMsg / result / retExtInfo / time). + * @see https://bybit-exchange.github.io/docs/v5/alpha/lp/pool-list + */ + public function getLpPoolList(array $options = []): array + { + return $this->session->signRequest('POST', '/v5/alpha/lp/pool-list', $options); + } + + /** + * Get user's LP positions with rewards and current value + * + * POST /v5/alpha/lp/position-list + * + * @param array $options + * @return array Bybit V5 ApiResponse envelope (retCode / retMsg / result / retExtInfo / time). + * @see https://bybit-exchange.github.io/docs/v5/alpha/lp/position-list + */ + public function getLpPositionList(array $options = []): array + { + return $this->session->signRequest('POST', '/v5/alpha/lp/position-list', $options); + } + + /** + * Redeem (withdraw) liquidity from a position + * + * POST /v5/alpha/lp/redeem + * + * @param int $positionId Position ID (from getLPPositionList). + * @param string $poolAddress Pool contract address. + * @param string $dercRatio Reduction ratio (0-1). +- "0.25" = redeem 25% +- "0.5" = redeem 50% +- "1" = close entire position (redeem 100%) + + * @param array $options + * @return array Bybit V5 ApiResponse envelope (retCode / retMsg / result / retExtInfo / time). + * @see https://bybit-exchange.github.io/docs/v5/alpha/lp/redeem + */ + public function executeLpRedeem(int $positionId, string $poolAddress, string $dercRatio, array $options = []): array + { + return $this->session->signRequest( + 'POST', + '/v5/alpha/lp/redeem', + array_merge($options, ['positionId' => $positionId, 'poolAddress' => $poolAddress, 'dercRatio' => $dercRatio]) + ); + } + + /** + * Stake tokens into an LP pool + * + * POST /v5/alpha/lp/stake + * + * @param int $positionId Position ID. Use `0` to create a new position, or provide an existing position ID to add liquidity. + + * @param string $poolAddress Pool contract address (from getLPPoolInfo). + * @param string $payTokenAmount Payment token amount (positive decimal as string). + * @param string $payTokenCode Payment token code (e.g., "CEX_1" for USDT). + * @param array $options + * @return array Bybit V5 ApiResponse envelope (retCode / retMsg / result / retExtInfo / time). + * @see https://bybit-exchange.github.io/docs/v5/alpha/lp/stake + */ + public function executeLpStake(int $positionId, string $poolAddress, string $payTokenAmount, string $payTokenCode, array $options = []): array + { + return $this->session->signRequest( + 'POST', + '/v5/alpha/lp/stake', + array_merge($options, ['positionId' => $positionId, 'poolAddress' => $poolAddress, 'payTokenAmount' => $payTokenAmount, 'payTokenCode' => $payTokenCode]) + ); + } + + /** + * Buy prediction outcome tokens with USDC + * + * POST /v5/alpha/prediction/buy + * + * @param string $tokenId Outcome token ID to buy (from getPredictionEventDetail). + * @param string $amount USDC amount to invest (positive decimal as string). + * @param string $payTokenCode Payment token code. Phase 1 fixed to "USDC". + * @param int $orderType + * @param string $slippage Maximum acceptable price slippage as decimal (e.g., "0.05" = 5% tolerance). + * @param string $eventId Event ID associated with the token. + * @param array $options + * @return array Bybit V5 ApiResponse envelope (retCode / retMsg / result / retExtInfo / time). + * @see https://bybit-exchange.github.io/docs/v5/alpha/prediction/buy + */ + public function executePredictionBuy(string $tokenId, string $amount, string $payTokenCode, int $orderType, string $slippage, string $eventId, array $options = []): array + { + return $this->session->signRequest( + 'POST', + '/v5/alpha/prediction/buy', + array_merge($options, ['tokenId' => $tokenId, 'amount' => $amount, 'payTokenCode' => $payTokenCode, 'orderType' => $orderType, 'slippage' => $slippage, 'eventId' => $eventId]) + ); + } + + /** + * Get prediction market matching engine availability status + * + * GET /v5/alpha/prediction/engine-status + * + * @param array $options + * @return array Bybit V5 ApiResponse envelope (retCode / retMsg / result / retExtInfo / time). + * @see https://bybit-exchange.github.io/docs/v5/alpha/prediction/engine-status + */ + public function getPredictionEngineStatus(array $options = []): array + { + return $this->session->signRequest('GET', '/v5/alpha/prediction/engine-status', $options); + } + + /** + * Get prediction event detail with all markets and outcomes + * + * POST /v5/alpha/prediction/event-detail + * + * @param array $options + * @return array Bybit V5 ApiResponse envelope (retCode / retMsg / result / retExtInfo / time). + * @see https://bybit-exchange.github.io/docs/v5/alpha/prediction/event-detail + */ + public function getPredictionEventDetail(array $options = []): array + { + return $this->session->signRequest('POST', '/v5/alpha/prediction/event-detail', $options); + } + + /** + * Get full order book snapshot for prediction tokens + * + * POST /v5/alpha/prediction/order-book + * + * @param array $tokenIds List of outcome token IDs. Maximum 20. + * @param array $options + * @return array Bybit V5 ApiResponse envelope (retCode / retMsg / result / retExtInfo / time). + * @see https://bybit-exchange.github.io/docs/v5/alpha/prediction/order-book + */ + public function getPredictionOrderBook(array $tokenIds, array $options = []): array + { + return $this->session->signRequest( + 'POST', + '/v5/alpha/prediction/order-book', + array_merge($options, ['tokenIds' => $tokenIds]) + ); + } + + /** + * Estimate buy or sell order fill amount and fees before execution + * + * POST /v5/alpha/prediction/order-estimate + * + * @param string $tokenId Outcome token ID (from getPredictionEventDetail or getPredictionMarketList). + * @param int $side + * @param string $eventId Event ID associated with this token. + * @param string $amount For BUY: USDC amount to invest (e.g., "100"). +For SELL: number of shares to sell (e.g., "50"). + + * @param int $orderType + * @param array $options + * @return array Bybit V5 ApiResponse envelope (retCode / retMsg / result / retExtInfo / time). + * @see https://bybit-exchange.github.io/docs/v5/alpha/prediction/order-estimate + */ + public function getPredictionOrderEstimate(string $tokenId, int $side, string $eventId, string $amount, int $orderType, array $options = []): array + { + return $this->session->signRequest( + 'POST', + '/v5/alpha/prediction/order-estimate', + array_merge($options, ['tokenId' => $tokenId, 'side' => $side, 'eventId' => $eventId, 'amount' => $amount, 'orderType' => $orderType]) + ); + } + + /** + * Get user's prediction market order history + * + * POST /v5/alpha/prediction/order-list + * + * @param array $options + * @return array Bybit V5 ApiResponse envelope (retCode / retMsg / result / retExtInfo / time). + * @see https://bybit-exchange.github.io/docs/v5/alpha/prediction/order-list + */ + public function getPredictionOrderList(array $options = []): array + { + return $this->session->signRequest('POST', '/v5/alpha/prediction/order-list', $options); + } + + /** + * Get available payment tokens (USDC) for prediction market + * + * GET /v5/alpha/prediction/pay-token-list + * + * @param array $options + * @return array Bybit V5 ApiResponse envelope (retCode / retMsg / result / retExtInfo / time). + * @see https://bybit-exchange.github.io/docs/v5/alpha/prediction/pay-token-list + */ + public function getPredictionPayTokenList(array $options = []): array + { + return $this->session->signRequest('GET', '/v5/alpha/prediction/pay-token-list', $options); + } + + /** + * Get user's prediction market portfolio overview + * + * POST /v5/alpha/prediction/portfolio-summary + * + * @param array $options + * @return array Bybit V5 ApiResponse envelope (retCode / retMsg / result / retExtInfo / time). + * @see https://bybit-exchange.github.io/docs/v5/alpha/prediction/portfolio-summary + */ + public function getPredictionPortfolioSummary(array $options = []): array + { + return $this->session->signRequest('POST', '/v5/alpha/prediction/portfolio-summary', $options); + } + + /** + * Get user's historical closed prediction market positions + * + * POST /v5/alpha/prediction/position-history + * + * @param array $options + * @return array Bybit V5 ApiResponse envelope (retCode / retMsg / result / retExtInfo / time). + * @see https://bybit-exchange.github.io/docs/v5/alpha/prediction/position-history + */ + public function getPredictionPositionHistory(array $options = []): array + { + return $this->session->signRequest('POST', '/v5/alpha/prediction/position-history', $options); + } + + /** + * Get user's current open prediction market positions + * + * POST /v5/alpha/prediction/position-list + * + * @param array $options + * @return array Bybit V5 ApiResponse envelope (retCode / retMsg / result / retExtInfo / time). + * @see https://bybit-exchange.github.io/docs/v5/alpha/prediction/position-list + */ + public function getPredictionPositionList(array $options = []): array + { + return $this->session->signRequest('POST', '/v5/alpha/prediction/position-list', $options); + } + + /** + * Get historical price chart data for prediction tokens + * + * POST /v5/alpha/prediction/price-history + * + * @param string $tokenId Outcome token ID. + * @param string $interval + * @param array $options + * @return array Bybit V5 ApiResponse envelope (retCode / retMsg / result / retExtInfo / time). + * @see https://bybit-exchange.github.io/docs/v5/alpha/prediction/price-history + */ + public function getPredictionPriceHistory(string $tokenId, string $interval, array $options = []): array + { + return $this->session->signRequest( + 'POST', + '/v5/alpha/prediction/price-history', + array_merge($options, ['tokenId' => $tokenId, 'interval' => $interval]) + ); + } + + /** + * Sell prediction outcome token shares for USDC + * + * POST /v5/alpha/prediction/sell + * + * @param string $tokenId Outcome token ID to sell (from getPredictionPositionList). + * @param string $size Number of shares to sell (positive decimal as string). + * @param int $orderType + * @param string $slippage Maximum acceptable price slippage as decimal (e.g., "0.05" = 5% tolerance). + * @param string $eventId Event ID associated with the token. + * @param array $options + * @return array Bybit V5 ApiResponse envelope (retCode / retMsg / result / retExtInfo / time). + * @see https://bybit-exchange.github.io/docs/v5/alpha/prediction/sell + */ + public function executePredictionSell(string $tokenId, string $size, int $orderType, string $slippage, string $eventId, array $options = []): array + { + return $this->session->signRequest( + 'POST', + '/v5/alpha/prediction/sell', + array_merge($options, ['tokenId' => $tokenId, 'size' => $size, 'orderType' => $orderType, 'slippage' => $slippage, 'eventId' => $eventId]) + ); + } + + /** + * Get related side markets for a sports event + * + * POST /v5/alpha/prediction/side-market-list + * + * @param string $eventId Event ID to query markets for. + * @param array $options + * @return array Bybit V5 ApiResponse envelope (retCode / retMsg / result / retExtInfo / time). + * @see https://bybit-exchange.github.io/docs/v5/alpha/prediction/side-market-list + */ + public function getPredictionSideMarketList(string $eventId, array $options = []): array + { + return $this->session->signRequest( + 'POST', + '/v5/alpha/prediction/side-market-list', + array_merge($options, ['eventId' => $eventId]) + ); + } + + /** + * Get group standings and results for a tournament stage + * + * POST /v5/alpha/prediction/sports/group-stage-detail + * + * @param int $eventType Sports event type. + * @param array $options + * @return array Bybit V5 ApiResponse envelope (retCode / retMsg / result / retExtInfo / time). + * @see https://bybit-exchange.github.io/docs/v5/alpha/prediction/sports-group-stage-detail + */ + public function getPredictionGroupStageDetail(int $eventType, array $options = []): array + { + return $this->session->signRequest( + 'POST', + '/v5/alpha/prediction/sports/group-stage-detail', + array_merge($options, ['eventType' => $eventType]) + ); + } + + /** + * Get match list for a sports prediction event + * + * POST /v5/alpha/prediction/sports/match-list + * + * @param int $eventType Sports event type. + * @param array $options + * @return array Bybit V5 ApiResponse envelope (retCode / retMsg / result / retExtInfo / time). + * @see https://bybit-exchange.github.io/docs/v5/alpha/prediction/sports-match-list + */ + public function getPredictionMatchList(int $eventType, array $options = []): array + { + return $this->session->signRequest( + 'POST', + '/v5/alpha/prediction/sports/match-list', + array_merge($options, ['eventType' => $eventType]) + ); + } + + /** + * Get tournament timeline stages for a sports event + * + * GET /v5/alpha/prediction/sports/timeline-stages + * + * @param int $eventType Sports event type. + * @param array $options + * @return array Bybit V5 ApiResponse envelope (retCode / retMsg / result / retExtInfo / time). + * @see https://bybit-exchange.github.io/docs/v5/alpha/prediction/sports-timeline-stages + */ + public function getPredictionTimelineStages(int $eventType, array $options = []): array + { + return $this->session->signRequest( + 'GET', + '/v5/alpha/prediction/sports/timeline-stages', + array_merge($options, ['eventType' => $eventType]) + ); + } + + /** + * Get real-time prices for prediction outcome tokens + * + * POST /v5/alpha/prediction/token-price + * + * @param array $tokenIds List of outcome token IDs to query. Maximum 20. + * @param array $options + * @return array Bybit V5 ApiResponse envelope (retCode / retMsg / result / retExtInfo / time). + * @see https://bybit-exchange.github.io/docs/v5/alpha/prediction/token-price + */ + public function getPredictionTokenPrice(array $tokenIds, array $options = []): array + { + return $this->session->signRequest( + 'POST', + '/v5/alpha/prediction/token-price', + array_merge($options, ['tokenIds' => $tokenIds]) + ); + } + + /** + * Get holding details for a specific token including quantity, PnL, and cost basis + * + * POST /v5/alpha/trade/asset-detail + * + * @param string $chainCode Blockchain code (ETH, SOL, BSC, etc.). + * @param string $tokenAddress Token contract address on chain. + * @param array $options + * @return array Bybit V5 ApiResponse envelope (retCode / retMsg / result / retExtInfo / time). + * @see https://bybit-exchange.github.io/docs/v5/alpha/trade/asset-detail + */ + public function getAssetDetail(string $chainCode, string $tokenAddress, array $options = []): array + { + return $this->session->signRequest( + 'POST', + '/v5/alpha/trade/asset-detail', + array_merge($options, ['chainCode' => $chainCode, 'tokenAddress' => $tokenAddress]) + ); + } + + /** + * Get user's on-chain token portfolio with holdings, PnL, and market value + * + * POST /v5/alpha/trade/asset-list + * + * @param array $options + * @return array Bybit V5 ApiResponse envelope (retCode / retMsg / result / retExtInfo / time). + * @see https://bybit-exchange.github.io/docs/v5/alpha/trade/asset-list + */ + public function getAssetList(array $options = []): array + { + return $this->session->signRequest('POST', '/v5/alpha/trade/asset-list', $options); + } + + /** + * Get token project details including description, social links, risk flag, and order limits + * + * POST /v5/alpha/trade/biz-token-details + * + * @param string $chainCode Blockchain code (ETH, SOL, BSC, etc.). + * @param string $tokenAddress Token contract address on chain. + * @param array $options + * @return array Bybit V5 ApiResponse envelope (retCode / retMsg / result / retExtInfo / time). + * @see https://bybit-exchange.github.io/docs/v5/alpha/trade/biz-token-details + */ + public function getBizTokenDetails(string $chainCode, string $tokenAddress, array $options = []): array + { + return $this->session->signRequest( + 'POST', + '/v5/alpha/trade/biz-token-details', + array_merge($options, ['chainCode' => $chainCode, 'tokenAddress' => $tokenAddress]) + ); + } + + /** + * Get on-chain tradable tokens with DEX token codes, risk flags, and order limits + * + * POST /v5/alpha/trade/biz-token-list + * + * @param array $options + * @return array Bybit V5 ApiResponse envelope (retCode / retMsg / result / retExtInfo / time). + * @see https://bybit-exchange.github.io/docs/v5/alpha/trade/biz-token-list + */ + public function getBizTokenList(array $options = []): array + { + return $this->session->signRequest('POST', '/v5/alpha/trade/biz-token-list', $options); + } + + /** + * Batch query token prices, 24h change, volume, market cap, liquidity, and holders by chain+address + * + * POST /v5/alpha/trade/biz-token-price-list + * + * @param array $tokenAddressInfo List of token identifiers to query. Maximum 20 items per request. + * @param array $options + * @return array Bybit V5 ApiResponse envelope (retCode / retMsg / result / retExtInfo / time). + * @see https://bybit-exchange.github.io/docs/v5/alpha/trade/biz-token-price-list + */ + public function getBizTokenPriceList(array $tokenAddressInfo, array $options = []): array + { + return $this->session->signRequest( + 'POST', + '/v5/alpha/trade/biz-token-price-list', + array_merge($options, ['tokenAddressInfo' => $tokenAddressInfo]) + ); + } + + /** + * Get trade order history with status, fees, and execution details + * + * POST /v5/alpha/trade/order-list + * + * @param int $limit Results per page. + * @param int $pageIndex Page number, starting from 1. + * @param array $options + * @return array Bybit V5 ApiResponse envelope (retCode / retMsg / result / retExtInfo / time). + * @see https://bybit-exchange.github.io/docs/v5/alpha/trade/order-list + */ + public function getOrderList(int $limit, int $pageIndex, array $options = []): array + { + return $this->session->signRequest( + 'POST', + '/v5/alpha/trade/order-list', + array_merge($options, ['limit' => $limit, 'pageIndex' => $pageIndex]) + ); + } + + /** + * Get available payment tokens (USDT, USDC, etc.) with CEX token codes and supported chains + * + * POST /v5/alpha/trade/pay-token-list + * + * @param string $chainCode Blockchain code (e.g. SOL, MANTLE). + * @param string $tokenAddress Token contract address on chain. + * @param array $options + * @return array Bybit V5 ApiResponse envelope (retCode / retMsg / result / retExtInfo / time). + * @see https://bybit-exchange.github.io/docs/v5/alpha/trade/pay-token-list + */ + public function getPayTokenList(string $chainCode, string $tokenAddress, array $options = []): array + { + return $this->session->signRequest( + 'POST', + '/v5/alpha/trade/pay-token-list', + array_merge($options, ['chainCode' => $chainCode, 'tokenAddress' => $tokenAddress]) + ); + } + + /** + * Execute a buy order to purchase on-chain tokens with USDT/USDC, returns order number + * + * POST /v5/alpha/trade/purchase + * + * @param string $fromTokenCode Payment token code (`CEX_`, e.g. `CEX_1` for USDT). Must match the quote request. + * @param string $fromTokenAmount Payment amount (positive decimal as string). Must match the quote request. + * @param string $toTokenCode Target on-chain token code (`DEX_`). Must match the quote request. + * @param string $slippage Slippage tolerance as decimal. +- `0.005` = 0.5% +- `0.01` = 1% +- `0.05` = 5% + + * @param string $quoteData Base64-encoded quote data. **Must pass as-is from `/quote` response.** + * @param string $gas Estimated gas fee. **Must pass as-is from `/quote` response.** + * @param int $quoteMode Quote mode. Must be consistent with the `/quote` request. +- `0`: Auto +- `1`: Price Priority +- `2`: Success Rate Priority + + * @param string $correctingCode MD5 checksum for data integrity. **Must pass as-is from `/quote` response.** + * @param array $options + * @return array Bybit V5 ApiResponse envelope (retCode / retMsg / result / retExtInfo / time). + * @see https://bybit-exchange.github.io/docs/v5/alpha/trade/trade-purchase + */ + public function executePurchase(string $fromTokenCode, string $fromTokenAmount, string $toTokenCode, string $slippage, string $quoteData, string $gas, int $quoteMode, string $correctingCode, array $options = []): array + { + return $this->session->signRequest( + 'POST', + '/v5/alpha/trade/purchase', + array_merge($options, ['fromTokenCode' => $fromTokenCode, 'fromTokenAmount' => $fromTokenAmount, 'toTokenCode' => $toTokenCode, 'slippage' => $slippage, 'quoteData' => $quoteData, 'gas' => $gas, 'quoteMode' => $quoteMode, 'correctingCode' => $correctingCode]) + ); + } + + /** + * Get estimated price, fees, slippage, and gas for an on-chain token trade + * + * POST /v5/alpha/trade/quote + * + * @param int $tradeType Trade type. +- `1`: Purchase (buy on-chain token with payment token) +- `2`: Redeem (sell on-chain token for payment token) + + * @param string $fromTokenCode Source token code. Format: `CEX_` or `DEX_`. +- Purchase: CEX token code (e.g. `CEX_1` for USDT). Get from `getPayTokenList`. +- Redeem: DEX token code (e.g. `DEX_123`). Get from `getBizTokenList` or `getAssetList`. + + * @param string $fromTokenAmount Amount to pay (string-formatted positive decimal for precision). Must be greater than 0. + * @param string $toTokenCode Target token code. Format: `CEX_` or `DEX_`. +- Purchase: DEX token code (e.g. `DEX_123`). Get from `getBizTokenList`. +- Redeem: CEX token code (e.g. `CEX_1` for USDT). Get from `getPayTokenList`. + + * @param array $options + * @return array Bybit V5 ApiResponse envelope (retCode / retMsg / result / retExtInfo / time). + * @see https://bybit-exchange.github.io/docs/v5/alpha/trade/trade-quote + */ + public function getTradeQuote(int $tradeType, string $fromTokenCode, string $fromTokenAmount, string $toTokenCode, array $options = []): array + { + return $this->session->signRequest( + 'POST', + '/v5/alpha/trade/quote', + array_merge($options, ['tradeType' => $tradeType, 'fromTokenCode' => $fromTokenCode, 'fromTokenAmount' => $fromTokenAmount, 'toTokenCode' => $toTokenCode]) + ); + } + + /** + * Execute a sell order to redeem on-chain tokens for USDT/USDC, returns order number + * + * POST /v5/alpha/trade/redeem + * + * @param string $fromTokenCode On-chain token to sell (`DEX_`). Must match the quote request. + * @param string $fromTokenAmount Amount to sell (positive decimal as string). Must match the quote request. + * @param string $toTokenCode Payment token to receive (`CEX_`, e.g. `CEX_1` for USDT). Must match the quote request. + * @param string $slippage Slippage tolerance as decimal. +- `0.005` = 0.5% +- `0.01` = 1% +- `0.05` = 5% + + * @param string $quoteData Base64-encoded quote data. **Must pass as-is from `/quote` response.** + * @param string $gas Estimated gas fee. **Must pass as-is from `/quote` response.** + * @param int $quoteMode Quote mode. Must be consistent with the `/quote` request. +- `0`: Auto +- `1`: Price Priority +- `2`: Success Rate Priority + + * @param string $correctingCode MD5 checksum for data integrity. **Must pass as-is from `/quote` response.** + * @param array $options + * @return array Bybit V5 ApiResponse envelope (retCode / retMsg / result / retExtInfo / time). + * @see https://bybit-exchange.github.io/docs/v5/alpha/trade/trade-redeem + */ + public function executeRedeem(string $fromTokenCode, string $fromTokenAmount, string $toTokenCode, string $slippage, string $quoteData, string $gas, int $quoteMode, string $correctingCode, array $options = []): array + { + return $this->session->signRequest( + 'POST', + '/v5/alpha/trade/redeem', + array_merge($options, ['fromTokenCode' => $fromTokenCode, 'fromTokenAmount' => $fromTokenAmount, 'toTokenCode' => $toTokenCode, 'slippage' => $slippage, 'quoteData' => $quoteData, 'gas' => $gas, 'quoteMode' => $quoteMode, 'correctingCode' => $correctingCode]) + ); + } + +} diff --git a/src/RestApi/EventService.php b/src/RestApi/EventService.php new file mode 100644 index 0000000..b7c87af --- /dev/null +++ b/src/RestApi/EventService.php @@ -0,0 +1,89 @@ +session->signRequest('GET', '/v5/event/order-list', $options); + } + + /** + * Get Event Contract Active Orders + * + * GET /v5/event/order-realtime + * + * @param array $options + * @return array Bybit V5 ApiResponse envelope (retCode / retMsg / result / retExtInfo / time). + * @see https://bybit-exchange.github.io/docs/v5/event/trade/open-order + */ + public function getEcActiveOrders(array $options = []): array + { + return $this->session->signRequest('GET', '/v5/event/order-realtime', $options); + } + + /** + * Get Event Contract Position Info + * + * GET /v5/event/positions + * + * @param array $options + * @return array Bybit V5 ApiResponse envelope (retCode / retMsg / result / retExtInfo / time). + * @see https://bybit-exchange.github.io/docs/v5/event/trade/position + */ + public function getEcPositionInfo(array $options = []): array + { + return $this->session->signRequest('GET', '/v5/event/positions', $options); + } + + /** + * Get Event Contract Settlement Records + * + * GET /v5/event/settlements + * + * @param string $symbol Symbol name, e.g. `BTCUSDT-EC` + * @param array $options + * @return array Bybit V5 ApiResponse envelope (retCode / retMsg / result / retExtInfo / time). + * @see https://bybit-exchange.github.io/docs/v5/event/trade/settlement + */ + public function getEcSettlements(string $symbol, array $options = []): array + { + return $this->session->signRequest( + 'GET', + '/v5/event/settlements', + array_merge($options, ['symbol' => $symbol]) + ); + } + + /** + * Get Event Contract Trade History + * + * GET /v5/event/trades + * + * @param string $symbol Symbol name, e.g. `BTCUSDT-EC` + * @param array $options + * @return array Bybit V5 ApiResponse envelope (retCode / retMsg / result / retExtInfo / time). + * @see https://bybit-exchange.github.io/docs/v5/event/trade/execution + */ + public function getEcTradeHistory(string $symbol, array $options = []): array + { + return $this->session->signRequest( + 'GET', + '/v5/event/trades', + array_merge($options, ['symbol' => $symbol]) + ); + } + +} diff --git a/src/RestApi/FiatService.php b/src/RestApi/FiatService.php new file mode 100644 index 0000000..3972b60 --- /dev/null +++ b/src/RestApi/FiatService.php @@ -0,0 +1,127 @@ +session->signRequest('GET', '/v5/fiat/balance-query', $options); + } + + /** + * Get Trading Pairs + * + * GET /v5/fiat/query-coin-list + * + * @param array $options + * @return array Bybit V5 ApiResponse envelope (retCode / retMsg / result / retExtInfo / time). + * @see https://bybit-exchange.github.io/docs/v5/asset/fiat-convert/query-coin-list + */ + public function queryCoinList(array $options = []): array + { + return $this->session->signRequest('GET', '/v5/fiat/query-coin-list', $options); + } + + /** + * Query Trade History + * + * GET /v5/fiat/query-trade-history + * + * @param array $options + * @return array Bybit V5 ApiResponse envelope (retCode / retMsg / result / retExtInfo / time). + * @see https://bybit-exchange.github.io/docs/v5/asset/fiat-convert/query-trade-history + */ + public function queryTradeHistory(array $options = []): array + { + return $this->session->signRequest('GET', '/v5/fiat/query-trade-history', $options); + } + + /** + * Request a Quote + * + * POST /v5/fiat/quote-apply + * + * @param string $fromCoin Convert from coin (coin to sell) + * @param string $fromCoinType From coin type + * @param string $toCoin Convert to coin (coin to buy) + * @param string $toCoinType To coin type + * @param string $requestAmount Request coin amount (the amount you want to sell) + * @param array $options + * @return array Bybit V5 ApiResponse envelope (retCode / retMsg / result / retExtInfo / time). + * @see https://bybit-exchange.github.io/docs/v5/asset/fiat-convert/quote-apply + */ + public function applyQuote(string $fromCoin, string $fromCoinType, string $toCoin, string $toCoinType, string $requestAmount, array $options = []): array + { + return $this->session->signRequest( + 'POST', + '/v5/fiat/quote-apply', + array_merge($options, ['fromCoin' => $fromCoin, 'fromCoinType' => $fromCoinType, 'toCoin' => $toCoin, 'toCoinType' => $toCoinType, 'requestAmount' => $requestAmount]) + ); + } + + /** + * Get Reference Price + * + * GET /v5/fiat/reference-price + * + * @param string $symbol Coin pair, format: "FIAT-CRYPTO", e.g., "EUR-USDT" + * @param array $options + * @return array Bybit V5 ApiResponse envelope (retCode / retMsg / result / retExtInfo / time). + * @see https://bybit-exchange.github.io/docs/v5/asset/fiat-convert/reference-price + */ + public function getReferencePrice(string $symbol, array $options = []): array + { + return $this->session->signRequest( + 'GET', + '/v5/fiat/reference-price', + array_merge($options, ['symbol' => $symbol]) + ); + } + + /** + * Confirm Quote and Execute Trade + * + * POST /v5/fiat/trade-execute + * + * @param string $quoteTxId Quote transaction ID from the quote request + * @param string $subUserId The user's sub userId in Bybit + * @param array $options + * @return array Bybit V5 ApiResponse envelope (retCode / retMsg / result / retExtInfo / time). + * @see https://bybit-exchange.github.io/docs/v5/asset/fiat-convert/confirm-quote + */ + public function confirmQuote(string $quoteTxId, string $subUserId, array $options = []): array + { + return $this->session->signRequest( + 'POST', + '/v5/fiat/trade-execute', + array_merge($options, ['quoteTxId' => $quoteTxId, 'subUserId' => $subUserId]) + ); + } + + /** + * Query Trade Status + * + * GET /v5/fiat/trade-query + * + * @param array $options + * @return array Bybit V5 ApiResponse envelope (retCode / retMsg / result / retExtInfo / time). + * @see https://bybit-exchange.github.io/docs/v5/asset/fiat-convert/query-trade + */ + public function queryTrade(array $options = []): array + { + return $this->session->signRequest('GET', '/v5/fiat/trade-query', $options); + } + +} diff --git a/src/RestApi/LendingService.php b/src/RestApi/LendingService.php new file mode 100644 index 0000000..ac54c0c --- /dev/null +++ b/src/RestApi/LendingService.php @@ -0,0 +1,138 @@ +session->signRequest( + 'POST', + '/v5/ins-loan/association-uid', + array_merge($options, ['uid' => $uid, 'operate' => $operate]) + ); + } + + /** + * Get Coin Delta Amount + * + * GET /v5/ins-loan/coin-delta-amount + * + * @param array $options + * @return array Bybit V5 ApiResponse envelope (retCode / retMsg / result / retExtInfo / time). + */ + public function insLoanCoinDeltaAmount(array $options = []): array + { + return $this->session->signRequest('GET', '/v5/ins-loan/coin-delta-amount', $options); + } + + /** + * Get Delay Liquidation Status + * + * GET /v5/ins-loan/delay-liq-status + * + * @param array $options + * @return array Bybit V5 ApiResponse envelope (retCode / retMsg / result / retExtInfo / time). + */ + public function insLoanDelayLiqStatus(array $options = []): array + { + return $this->session->signRequest('GET', '/v5/ins-loan/delay-liq-status', $options); + } + + /** + * Get Margin Token Conversion Details + * + * GET /v5/ins-loan/ensure-tokens-convert + * + * @param array $options + * @return array Bybit V5 ApiResponse envelope (retCode / retMsg / result / retExtInfo / time). + */ + public function insLoanEnsureTokensConvert(array $options = []): array + { + return $this->session->signRequest('GET', '/v5/ins-loan/ensure-tokens-convert', $options); + } + + /** + * Get Loan Orders + * + * GET /v5/ins-loan/loan-order + * + * @param array $options + * @return array Bybit V5 ApiResponse envelope (retCode / retMsg / result / retExtInfo / time). + */ + public function insLoanGetLoanOrder(array $options = []): array + { + return $this->session->signRequest('GET', '/v5/ins-loan/loan-order', $options); + } + + /** + * Get LTV with Conversion Details + * + * GET /v5/ins-loan/ltv-convert + * + * @param array $options + * @return array Bybit V5 ApiResponse envelope (retCode / retMsg / result / retExtInfo / time). + */ + public function insLoanLtvConvert(array $options = []): array + { + return $this->session->signRequest('GET', '/v5/ins-loan/ltv-convert', $options); + } + + /** + * Get Product Infos + * + * GET /v5/ins-loan/product-infos + * + * @param array $options + * @return array Bybit V5 ApiResponse envelope (retCode / retMsg / result / retExtInfo / time). + */ + public function insLoanProductInfos(array $options = []): array + { + return $this->session->publicRequest('GET', '/v5/ins-loan/product-infos', $options); + } + + /** + * Get Repaid History + * + * GET /v5/ins-loan/repaid-history + * + * @param array $options + * @return array Bybit V5 ApiResponse envelope (retCode / retMsg / result / retExtInfo / time). + */ + public function insLoanRepaidHistory(array $options = []): array + { + return $this->session->signRequest('GET', '/v5/ins-loan/repaid-history', $options); + } + + /** + * Repay Loan + * + * POST /v5/ins-loan/repay-loan + * + * @param string $token Repayment coin name, uppercase only. e.g. `USDT`, `BTC`. + * @param string $quantity Repayment quantity. + * @param array $options + * @return array Bybit V5 ApiResponse envelope (retCode / retMsg / result / retExtInfo / time). + */ + public function insLoanRepayLoan(string $token, string $quantity, array $options = []): array + { + return $this->session->signRequest( + 'POST', + '/v5/ins-loan/repay-loan', + array_merge($options, ['token' => $token, 'quantity' => $quantity]) + ); + } + +} diff --git a/src/RestApi/PreUpgradeService.php b/src/RestApi/PreUpgradeService.php new file mode 100644 index 0000000..7ecb521 --- /dev/null +++ b/src/RestApi/PreUpgradeService.php @@ -0,0 +1,141 @@ +session->signRequest( + 'GET', + '/v5/pre-upgrade/account/transaction-log', + array_merge($options, ['category' => $category]) + ); + } + + /** + * Get Pre-upgrade Delivery Record + * + * GET /v5/pre-upgrade/asset/delivery-record + * + * @param string $category Product type: +- `option`: Options + + * @param array $options + * @return array Bybit V5 ApiResponse envelope (retCode / retMsg / result / retExtInfo / time). + * @see https://bybit-exchange.github.io/docs/v5/pre-upgrade/delivery + */ + public function getDeliveryRecord(string $category, array $options = []): array + { + return $this->session->signRequest( + 'GET', + '/v5/pre-upgrade/asset/delivery-record', + array_merge($options, ['category' => $category]) + ); + } + + /** + * Get Pre-upgrade Settlement Record + * + * GET /v5/pre-upgrade/asset/settlement-record + * + * @param string $category Product type: +- `linear`: USDC perpetual + + * @param array $options + * @return array Bybit V5 ApiResponse envelope (retCode / retMsg / result / retExtInfo / time). + * @see https://bybit-exchange.github.io/docs/v5/pre-upgrade/settlement + */ + public function getSettlementRecord(string $category, array $options = []): array + { + return $this->session->signRequest( + 'GET', + '/v5/pre-upgrade/asset/settlement-record', + array_merge($options, ['category' => $category]) + ); + } + + /** + * Get Pre-upgrade Execution List + * + * GET /v5/pre-upgrade/execution/list + * + * @param string $category Product type: +- `linear`: USDT perpetual, USDC contract +- `inverse`: Inverse perpetual, Inverse futures +- `option`: Options +- `spot`: Spot trading + + * @param array $options + * @return array Bybit V5 ApiResponse envelope (retCode / retMsg / result / retExtInfo / time). + * @see https://bybit-exchange.github.io/docs/v5/pre-upgrade/execution + */ + public function getExecutionList(string $category, array $options = []): array + { + return $this->session->signRequest( + 'GET', + '/v5/pre-upgrade/execution/list', + array_merge($options, ['category' => $category]) + ); + } + + /** + * Get Pre-upgrade Order History + * + * GET /v5/pre-upgrade/order/history + * + * @param string $category Product type: +- `linear`: USDT perpetual, USDC contract +- `inverse`: Inverse perpetual, Inverse futures +- `option`: Options +- `spot`: Spot trading + + * @param array $options + * @return array Bybit V5 ApiResponse envelope (retCode / retMsg / result / retExtInfo / time). + * @see https://bybit-exchange.github.io/docs/v5/pre-upgrade/order-list + */ + public function getOrderHistory(string $category, array $options = []): array + { + return $this->session->signRequest( + 'GET', + '/v5/pre-upgrade/order/history', + array_merge($options, ['category' => $category]) + ); + } + + /** + * Get Pre-Upgrade Closed PnL + * + * GET /v5/pre-upgrade/position/closed-pnl + * + * @param string $category Product type. + * @param string $symbol Contract name. + * @param array $options + * @return array Bybit V5 ApiResponse envelope (retCode / retMsg / result / retExtInfo / time). + * @see https://bybit-exchange.github.io/docs/v5/pre-upgrade/close-pnl + */ + public function getClosedPnl(string $category, string $symbol, array $options = []): array + { + return $this->session->signRequest( + 'GET', + '/v5/pre-upgrade/position/closed-pnl', + array_merge($options, ['category' => $category, 'symbol' => $symbol]) + ); + } + +} diff --git a/src/RestApi/ReferralService.php b/src/RestApi/ReferralService.php new file mode 100644 index 0000000..d475fe3 --- /dev/null +++ b/src/RestApi/ReferralService.php @@ -0,0 +1,65 @@ +session->signRequest('POST', '/v5/referral/campaign/rewards', $options); + } + + /** + * Get Referral Commission Records + * + * POST /v5/referral/commission/records + * + * @param array $options + * @return array Bybit V5 ApiResponse envelope (retCode / retMsg / result / retExtInfo / time). + * @see https://bybit-exchange.github.io/docs/v5/referral/referral-commission-records + */ + public function getCommissionRecords(array $options = []): array + { + return $this->session->signRequest('POST', '/v5/referral/commission/records', $options); + } + + /** + * Get Referral User Identity Profile + * + * POST /v5/referral/user/identity-profile + * + * @param array $options + * @return array Bybit V5 ApiResponse envelope (retCode / retMsg / result / retExtInfo / time). + * @see https://bybit-exchange.github.io/docs/v5/referral/referral-user-identity-profile + */ + public function getUserIdentityProfile(array $options = []): array + { + return $this->session->signRequest('POST', '/v5/referral/user/identity-profile', $options); + } + + /** + * Get referral user invitations + * + * POST /v5/referral/user/invitations + * + * @param array $options + * @return array Bybit V5 ApiResponse envelope (retCode / retMsg / result / retExtInfo / time). + * @see https://bybit-exchange.github.io/docs/v5/referral/referral-user-invitations + */ + public function getUserInvitations(array $options = []): array + { + return $this->session->signRequest('POST', '/v5/referral/user/invitations', $options); + } + +} diff --git a/src/RestApi/SpotMarginService.php b/src/RestApi/SpotMarginService.php index b2a14b6..5dcc099 100644 --- a/src/RestApi/SpotMarginService.php +++ b/src/RestApi/SpotMarginService.php @@ -354,4 +354,37 @@ public function spotMarginSwitchMode(string $spotMarginMode, array $options = [] ); } + /** + * Query Fixed-Rate Borrow Penalty Interest + * + * GET /v5/spot-margin-trade/fixedborrow-interest-accrued + * + * @param array $options + * @return array Bybit V5 ApiResponse envelope (retCode / retMsg / result / retExtInfo / time). + * @see https://bybit-exchange.github.io/docs/v5/spot-margin-uta/fixedborrow-interest-accrued + */ + public function queryFixedBorrowPenaltyInterest(array $options = []): array + { + return $this->session->signRequest('GET', '/v5/spot-margin-trade/fixedborrow-interest-accrued', $options); + } + + /** + * Cancel Fixed-Rate Borrow Order + * + * POST /v5/spot-margin-trade/fixedborrow-order-cancel + * + * @param string $orderId Fixed-rate borrow order ID, not the contract match ID. + * @param array $options + * @return array Bybit V5 ApiResponse envelope (retCode / retMsg / result / retExtInfo / time). + * @see https://bybit-exchange.github.io/docs/v5/spot-margin-uta/fixedborrow-order-cancel + */ + public function cancelFixedBorrowOrder(string $orderId, array $options = []): array + { + return $this->session->signRequest( + 'POST', + '/v5/spot-margin-trade/fixedborrow-order-cancel', + array_merge($options, ['orderId' => $orderId]) + ); + } + } diff --git a/src/RestApi/SpotXService.php b/src/RestApi/SpotXService.php new file mode 100644 index 0000000..e8681ae --- /dev/null +++ b/src/RestApi/SpotXService.php @@ -0,0 +1,134 @@ +session->publicRequest( + 'GET', + '/v5/spot-x/launchpool/project/list', + array_merge($options, ['status' => $status]) + ); + } + + /** + * Get user's staking operation records + * + * POST /v5/spot-x/launchpool/user/activity-log + * + * @param array $options + * @return array Bybit V5 ApiResponse envelope (retCode / retMsg / result / retExtInfo / time). + * @see https://bybit-exchange.github.io/docs/v5/finance/spot-x/launchpool/launchpool-activity-log + */ + public function getLaunchpoolUserActivityLog(array $options = []): array + { + return $this->session->signRequest('POST', '/v5/spot-x/launchpool/user/activity-log', $options); + } + + /** + * Get user's active staking positions + * + * GET /v5/spot-x/launchpool/user/current-staking + * + * @param array $options + * @return array Bybit V5 ApiResponse envelope (retCode / retMsg / result / retExtInfo / time). + * @see https://bybit-exchange.github.io/docs/v5/finance/spot-x/launchpool/launchpool-current-staking + */ + public function getLaunchpoolUserCurrentStaking(array $options = []): array + { + return $this->session->signRequest('GET', '/v5/spot-x/launchpool/user/current-staking', $options); + } + + /** + * Get user's completed staking position history + * + * POST /v5/spot-x/launchpool/user/history + * + * @param array $options + * @return array Bybit V5 ApiResponse envelope (retCode / retMsg / result / retExtInfo / time). + * @see https://bybit-exchange.github.io/docs/v5/finance/spot-x/launchpool/launchpool-user-history + */ + public function getLaunchpoolUserHistory(array $options = []): array + { + return $this->session->signRequest('POST', '/v5/spot-x/launchpool/user/history', $options); + } + + /** + * Get Puzzle project (activity) list + * + * GET /v5/spot-x/puzzle/project/list + * + * @param int $status Activity phase filter. +- `0` — Upcoming (not yet started) +- `1` — Ongoing (in progress) +- `2` — Ended + + * @param array $options + * @return array Bybit V5 ApiResponse envelope (retCode / retMsg / result / retExtInfo / time). + * @see https://bybit-exchange.github.io/docs/v5/finance/spot-x/puzzle/puzzle-project-list + */ + public function getPuzzleProjectList(int $status, array $options = []): array + { + return $this->session->publicRequest( + 'GET', + '/v5/spot-x/puzzle/project/list', + array_merge($options, ['status' => $status]) + ); + } + + /** + * Get Token Splash project (activity) list + * + * GET /v5/spot-x/token-splash/project/list + * + * @param int $status Activity phase filter. +- `0` — Upcoming (registration not yet started) +- `1` — Ongoing (activity in progress) +- `2` — Ended (announcement time has passed) + + * @param array $options + * @return array Bybit V5 ApiResponse envelope (retCode / retMsg / result / retExtInfo / time). + * @see https://bybit-exchange.github.io/docs/v5/finance/spot-x/token-splash/token-splash-project-list + */ + public function getTokenSplashProjectList(int $status, array $options = []): array + { + return $this->session->publicRequest( + 'GET', + '/v5/spot-x/token-splash/project/list', + array_merge($options, ['status' => $status]) + ); + } + + /** + * Get user's Token Splash trade-task progress + * + * GET /v5/spot-x/token-splash/user/activity-params + * + * @param array $options + * @return array Bybit V5 ApiResponse envelope (retCode / retMsg / result / retExtInfo / time). + * @see https://bybit-exchange.github.io/docs/v5/finance/spot-x/token-splash/token-splash-user-activity-params + */ + public function getTokenSplashUserActivityParams(array $options = []): array + { + return $this->session->signRequest('GET', '/v5/spot-x/token-splash/user/activity-params', $options); + } + +} diff --git a/src/RestApi/SpreadTradeService.php b/src/RestApi/SpreadTradeService.php new file mode 100644 index 0000000..36dded9 --- /dev/null +++ b/src/RestApi/SpreadTradeService.php @@ -0,0 +1,215 @@ +session->signRequest('GET', '/v5/spread/execution/list', $options); + } + + /** + * Get Spread Instruments Info + * + * GET /v5/spread/instrument + * + * @param array $options + * @return array Bybit V5 ApiResponse envelope (retCode / retMsg / result / retExtInfo / time). + * @see https://bybit-exchange.github.io/docs/v5/spread/market/instrument + */ + public function getSpreadInstrumentsInfo(array $options = []): array + { + return $this->session->publicRequest('GET', '/v5/spread/instrument', $options); + } + + /** + * Get Spread Wallet Balance + * + * GET /v5/spread/max-qty + * + * @param string $symbol Spread trading pair. + * @param string $side Order side: +- `1`: Buy +- `2`: Sell + + * @param string $orderPrice Order price. + * @param array $options + * @return array Bybit V5 ApiResponse envelope (retCode / retMsg / result / retExtInfo / time). + * @see https://bybit-exchange.github.io/docs/v5/spread/trade/max-qty + */ + public function getSpreadMaxQty(string $symbol, string $side, string $orderPrice, array $options = []): array + { + return $this->session->signRequest( + 'GET', + '/v5/spread/max-qty', + array_merge($options, ['symbol' => $symbol, 'side' => $side, 'orderPrice' => $orderPrice]) + ); + } + + /** + * Amend Order + * + * POST /v5/spread/order/amend + * + * @param string $symbol Spread combination symbol name. + * @param array $options + * @return array Bybit V5 ApiResponse envelope (retCode / retMsg / result / retExtInfo / time). + * @see https://bybit-exchange.github.io/docs/v5/spread/trade/amend-order + */ + public function amendSpreadOrder(string $symbol, array $options = []): array + { + return $this->session->signRequest( + 'POST', + '/v5/spread/order/amend', + array_merge($options, ['symbol' => $symbol]) + ); + } + + /** + * Cancel Order + * + * POST /v5/spread/order/cancel + * + * @param array $options + * @return array Bybit V5 ApiResponse envelope (retCode / retMsg / result / retExtInfo / time). + * @see https://bybit-exchange.github.io/docs/v5/spread/trade/cancel-order + */ + public function cancelSpreadOrder(array $options = []): array + { + return $this->session->signRequest('POST', '/v5/spread/order/cancel', $options); + } + + /** + * Cancel All Orders + * + * POST /v5/spread/order/cancel-all + * + * @param array $options + * @return array Bybit V5 ApiResponse envelope (retCode / retMsg / result / retExtInfo / time). + * @see https://bybit-exchange.github.io/docs/v5/spread/trade/cancel-all + */ + public function cancelAllSpreadOrders(array $options = []): array + { + return $this->session->signRequest('POST', '/v5/spread/order/cancel-all', $options); + } + + /** + * Create Order + * + * POST /v5/spread/order/create + * + * @param string $symbol Spread combination symbol name. + * @param string $side Order direction. + * @param string $orderType Order type. + * @param string $qty Order quantity (string-formatted number). + * @param array $options + * @return array Bybit V5 ApiResponse envelope (retCode / retMsg / result / retExtInfo / time). + * @see https://bybit-exchange.github.io/docs/v5/spread/trade/create-order + */ + public function createSpreadOrder(string $symbol, string $side, string $orderType, string $qty, array $options = []): array + { + return $this->session->signRequest( + 'POST', + '/v5/spread/order/create', + array_merge($options, ['symbol' => $symbol, 'side' => $side, 'orderType' => $orderType, 'qty' => $qty]) + ); + } + + /** + * Get Order History + * + * GET /v5/spread/order/history + * + * @param array $options + * @return array Bybit V5 ApiResponse envelope (retCode / retMsg / result / retExtInfo / time). + * @see https://bybit-exchange.github.io/docs/v5/spread/trade/order-history + */ + public function getSpreadOrderHistory(array $options = []): array + { + return $this->session->signRequest('GET', '/v5/spread/order/history', $options); + } + + /** + * Get Open Orders + * + * GET /v5/spread/order/realtime + * + * @param array $options + * @return array Bybit V5 ApiResponse envelope (retCode / retMsg / result / retExtInfo / time). + * @see https://bybit-exchange.github.io/docs/v5/spread/trade/open-order + */ + public function getSpreadOpenOrders(array $options = []): array + { + return $this->session->signRequest('GET', '/v5/spread/order/realtime', $options); + } + + /** + * Get Spread Orderbook + * + * GET /v5/spread/orderbook + * + * @param string $symbol Spread combination symbol name, e.g. `SOLUSDT_SOL/USDT` + * @param array $options + * @return array Bybit V5 ApiResponse envelope (retCode / retMsg / result / retExtInfo / time). + * @see https://bybit-exchange.github.io/docs/v5/spread/market/orderbook + */ + public function getSpreadOrderbook(string $symbol, array $options = []): array + { + return $this->session->publicRequest( + 'GET', + '/v5/spread/orderbook', + array_merge($options, ['symbol' => $symbol]) + ); + } + + /** + * Get Spread Recent Public Trades + * + * GET /v5/spread/recent-trade + * + * @param string $symbol Spread combination symbol name, e.g. `SOLUSDT_SOL/USDT` + * @param array $options + * @return array Bybit V5 ApiResponse envelope (retCode / retMsg / result / retExtInfo / time). + * @see https://bybit-exchange.github.io/docs/v5/spread/market/recent-trade + */ + public function getSpreadRecentTrades(string $symbol, array $options = []): array + { + return $this->session->publicRequest( + 'GET', + '/v5/spread/recent-trade', + array_merge($options, ['symbol' => $symbol]) + ); + } + + /** + * Get Spread Tickers + * + * GET /v5/spread/tickers + * + * @param string $symbol Spread combination symbol name, e.g. `SOLUSDT_SOL/USDT` + * @param array $options + * @return array Bybit V5 ApiResponse envelope (retCode / retMsg / result / retExtInfo / time). + * @see https://bybit-exchange.github.io/docs/v5/spread/market/tickers + */ + public function getSpreadTickers(string $symbol, array $options = []): array + { + return $this->session->publicRequest( + 'GET', + '/v5/spread/tickers', + array_merge($options, ['symbol' => $symbol]) + ); + } + +} diff --git a/src/RestApi/StrategyService.php b/src/RestApi/StrategyService.php new file mode 100644 index 0000000..d8a673c --- /dev/null +++ b/src/RestApi/StrategyService.php @@ -0,0 +1,85 @@ +session->signRequest( + 'POST', + '/v5/strategy/create', + $params + ); + } + + /** + * Query trading strategy list with filters + * + * GET /v5/strategy/list + * + * @param array $options + * @return array Bybit V5 ApiResponse envelope (retCode / retMsg / result / retExtInfo / time). + * @see https://bybit-exchange.github.io/docs/v5/strategy/strategy-list + */ + public function queryList(array $options = []): array + { + return $this->session->signRequest('GET', '/v5/strategy/list', $options); + } + + /** + * Query orders created by a specific strategy + * + * GET /v5/strategy/order-list + * + * @param string $strategyId Strategy ID to query orders for (UUID format). +This is the parent strategy whose child orders you want to retrieve. +Obtain from strategy creation response or strategy list query. + + * @param array $options + * @return array Bybit V5 ApiResponse envelope (retCode / retMsg / result / retExtInfo / time). + * @see https://bybit-exchange.github.io/docs/v5/strategy/order-list + */ + public function queryOrderList(string $strategyId, array $options = []): array + { + return $this->session->signRequest( + 'GET', + '/v5/strategy/order-list', + array_merge($options, ['strategyId' => $strategyId]) + ); + } + + /** + * Stop a running strategy + * + * POST /v5/strategy/stop + * + * @param string $strategyId Strategy ID to stop (UUID format). +Obtained from strategy creation response or strategy list query. +Only Running or Untriggered strategies can be stopped. + + * @param array $options + * @return array Bybit V5 ApiResponse envelope (retCode / retMsg / result / retExtInfo / time). + * @see https://bybit-exchange.github.io/docs/v5/strategy/stop-strategy + */ + public function stopStrategy(string $strategyId, array $options = []): array + { + return $this->session->signRequest( + 'POST', + '/v5/strategy/stop', + array_merge($options, ['strategyId' => $strategyId]) + ); + } + +} diff --git a/src/RestApi/TaxService.php b/src/RestApi/TaxService.php new file mode 100644 index 0000000..36a071f --- /dev/null +++ b/src/RestApi/TaxService.php @@ -0,0 +1,49 @@ +session->signRequest( + 'POST', + '/v5/fht/compliance/tax/private/batch_create', + array_merge($options, ['startTime' => $startTime, 'endTime' => $endTime, 'items' => $items]) + ); + } + + /** + * Query batch tax report status + * + * GET /v5/fht/compliance/tax/private/batch_query + * + * @param string $batchId Batch ID returned by `batch_create` + * @param array $options + * @return array Bybit V5 ApiResponse envelope (retCode / retMsg / result / retExtInfo / time). + * @see https://bybit-exchange.github.io/docs/v5/tax/batch-query + */ + public function batchQueryTaxReports(string $batchId, array $options = []): array + { + return $this->session->signRequest( + 'GET', + '/v5/fht/compliance/tax/private/batch_query', + array_merge($options, ['batchId' => $batchId]) + ); + } + +} diff --git a/tests/RestApiContractTest.php b/tests/RestApiContractTest.php index 6e65d06..44f32df 100644 --- a/tests/RestApiContractTest.php +++ b/tests/RestApiContractTest.php @@ -57,6 +57,146 @@ public function testFixedBorrowMarketKeepsOrderByOptional(): void $this->assertSame('limit=1&orderBy=apy&orderCurrency=USDT', $request->getUri()->getQuery()); } + public function testPredictionSideMarketSendsEventId(): void + { + $history = []; + $client = $this->makeClient($history); + + $client->alpha->getPredictionSideMarketList('event-123'); + + $body = json_decode((string) $history[0]['request']->getBody(), true, 512, JSON_THROW_ON_ERROR); + $this->assertSame(['eventId' => 'event-123'], $body); + } + + public function testPredictionGroupStageUsesDocumentedContract(): void + { + $method = new \ReflectionMethod(\Bybit\RestApi\AlphaService::class, 'getPredictionGroupStageDetail'); + $params = $method->getParameters(); + + $this->assertSame(['eventType', 'options'], array_map(static fn (\ReflectionParameter $p): string => $p->getName(), $params)); + $this->assertSame('int', (string) $params[0]->getType()); + + $history = []; + $client = $this->makeClient($history); + $client->alpha->getPredictionGroupStageDetail(1, ['groupName' => 'A']); + + $body = json_decode((string) $history[0]['request']->getBody(), true, 512, JSON_THROW_ON_ERROR); + $this->assertSame(['groupName' => 'A', 'eventType' => 1], $body); + } + + public function testPredictionMatchListUsesIntegerEventType(): void + { + $method = new \ReflectionMethod(\Bybit\RestApi\AlphaService::class, 'getPredictionMatchList'); + $this->assertSame('int', (string) $method->getParameters()[0]->getType()); + } + + public function testPredictionTimelineStagesRequiresEventType(): void + { + $method = new \ReflectionMethod(\Bybit\RestApi\AlphaService::class, 'getPredictionTimelineStages'); + $params = $method->getParameters(); + + $this->assertSame(['eventType', 'options'], array_map(static fn (\ReflectionParameter $p): string => $p->getName(), $params)); + $this->assertSame('int', (string) $params[0]->getType()); + + $history = []; + $client = $this->makeClient($history); + $client->alpha->getPredictionTimelineStages(1); + + $this->assertSame('eventType=1', $history[0]['request']->getUri()->getQuery()); + } + + public function testPredictionPriceHistoryRequiresTokenIdAndInterval(): void + { + $method = new \ReflectionMethod(\Bybit\RestApi\AlphaService::class, 'getPredictionPriceHistory'); + $params = $method->getParameters(); + + $this->assertSame(['tokenId', 'interval', 'options'], array_map(static fn (\ReflectionParameter $p): string => $p->getName(), $params)); + + $history = []; + $client = $this->makeClient($history); + $client->alpha->getPredictionPriceHistory('token-123', '1h'); + + $body = json_decode((string) $history[0]['request']->getBody(), true, 512, JSON_THROW_ON_ERROR); + $this->assertSame(['tokenId' => 'token-123', 'interval' => '1h'], $body); + } + + public function testAlphaTradeOrderListRequiresPagination(): void + { + $method = new \ReflectionMethod(\Bybit\RestApi\AlphaService::class, 'getOrderList'); + $params = $method->getParameters(); + + $this->assertSame(['limit', 'pageIndex', 'options'], array_map(static fn (\ReflectionParameter $p): string => $p->getName(), $params)); + $this->assertSame('int', (string) $params[0]->getType()); + $this->assertSame('int', (string) $params[1]->getType()); + + $history = []; + $client = $this->makeClient($history); + $client->alpha->getOrderList(20, 1); + + $body = json_decode((string) $history[0]['request']->getBody(), true, 512, JSON_THROW_ON_ERROR); + $this->assertSame(['limit' => 20, 'pageIndex' => 1], $body); + } + + public function testPredictionEnumParametersUseIntegerTypes(): void + { + foreach ([ + 'executePredictionBuy' => ['orderType'], + 'executePredictionSell' => ['orderType'], + 'getPredictionOrderEstimate' => ['side', 'orderType'], + ] as $methodName => $integerParams) { + $method = new \ReflectionMethod(\Bybit\RestApi\AlphaService::class, $methodName); + $params = []; + foreach ($method->getParameters() as $param) { + $params[$param->getName()] = (string) $param->getType(); + } + foreach ($integerParams as $paramName) { + $this->assertSame('int', $params[$paramName], "{$methodName}::\${$paramName} must be int"); + } + } + } + + public function testInstitutionalLoanProductInfoIsPublic(): void + { + $history = []; + $client = $this->makeClient($history, false); + + try { + $client->lending->insLoanProductInfos(); + } catch (\Bybit\Exception\ConfigurationException $e) { + $this->fail('Public product info endpoint unexpectedly required credentials: ' . $e->getMessage()); + } + + $request = $history[0]['request']; + $this->assertFalse($request->hasHeader('X-BAPI-API-KEY')); + $this->assertFalse($request->hasHeader('X-BAPI-SIGN')); + } + + public function testSmokeProviderCoversEveryClientService(): void + { + $covered = []; + foreach (RestApiSmokeTest::serviceMethodProvider() as $case) { + $covered[$case[0]] = true; + } + + $expected = []; + $client = new \ReflectionClass(Client::class); + foreach ($client->getProperties(\ReflectionProperty::IS_PUBLIC) as $property) { + $type = $property->getType(); + if ($type instanceof \ReflectionNamedType && is_subclass_of($type->getName(), \Bybit\RestApi\BaseService::class)) { + $expected[$type->getName()] = true; + } + } + + $missing = array_diff_key($expected, $covered); + $this->assertSame([], array_keys($missing), 'Smoke provider is missing Client services'); + } + + public function testStocksServiceIsNotPublished(): void + { + $this->assertFalse(property_exists(Client::class, 'stocks')); + $this->assertFalse(class_exists(\Bybit\RestApi\StocksService::class)); + } + /** @dataProvider removedAssetMethodProvider */ public function testUnsupportedOrAbandonedAssetMethodIsNotPublished(string $method): void { @@ -64,7 +204,7 @@ public function testUnsupportedOrAbandonedAssetMethodIsNotPublished(string $meth } /** @param array> $history */ - private function makeClient(array &$history): Client + private function makeClient(array &$history, bool $authenticated = true): Client { $mock = new MockHandler([ new Response(200, ['Content-Type' => 'application/json'], '{"retCode":0,"retMsg":"OK","result":{},"retExtInfo":{},"time":0}'), @@ -73,8 +213,8 @@ private function makeClient(array &$history): Client $stack->push(Middleware::history($history)); return new Client(new Configuration( - apiKey: 'test-key', - apiSecret: 'test-secret', + apiKey: $authenticated ? 'test-key' : null, + apiSecret: $authenticated ? 'test-secret' : null, httpClient: new GuzzleClient([ 'handler' => $stack, 'base_uri' => 'https://api-testnet.bybit.com', diff --git a/tests/RestApiSmokeTest.php b/tests/RestApiSmokeTest.php index 9d07a5d..bf045b9 100644 --- a/tests/RestApiSmokeTest.php +++ b/tests/RestApiSmokeTest.php @@ -22,7 +22,7 @@ * 2. Send a URL under `/v5/`. * 3. Use a Bybit V5 verb (GET, POST, PUT, or DELETE). * - * This is the ~240-endpoint safety net the initial commit lacked — a wrong + * This is the 400+-endpoint safety net the initial commit lacked — a wrong * HTTP verb, a broken PSR-4 mapping, or a method that forgets to call session * would previously ship green. It doesn't validate the exact path shape (that * would duplicate source); it locks the load-bearing invariant that every @@ -40,16 +40,26 @@ private static function serviceClasses(): array return [ \Bybit\RestApi\AccountService::class, \Bybit\RestApi\AffiliateService::class, + \Bybit\RestApi\AlphaService::class, \Bybit\RestApi\AssetService::class, \Bybit\RestApi\BotService::class, \Bybit\RestApi\BrokerService::class, \Bybit\RestApi\CryptoLoanService::class, \Bybit\RestApi\EarnService::class, + \Bybit\RestApi\EventService::class, + \Bybit\RestApi\FiatService::class, + \Bybit\RestApi\LendingService::class, \Bybit\RestApi\MarketService::class, \Bybit\RestApi\P2pService::class, \Bybit\RestApi\PositionService::class, + \Bybit\RestApi\PreUpgradeService::class, + \Bybit\RestApi\ReferralService::class, \Bybit\RestApi\RfqService::class, \Bybit\RestApi\SpotMarginService::class, + \Bybit\RestApi\SpotXService::class, + \Bybit\RestApi\SpreadTradeService::class, + \Bybit\RestApi\StrategyService::class, + \Bybit\RestApi\TaxService::class, \Bybit\RestApi\TradeService::class, \Bybit\RestApi\UserService::class, ]; @@ -81,7 +91,7 @@ public static function serviceMethodProvider(): iterable */ public function testEveryServiceMethodDispatchesAv5Request(string $serviceClass, string $methodName): void { - // 240+ service methods — one shared 200-OK mock queue per test call. + // 400+ service methods — one shared 200-OK mock queue per test call. $history = []; $client = $this->makeClient(new Response(200, ['Content-Type' => 'application/json'], self::OK_ENVELOPE), $history); From 1dce33b2ffee7c28f696528293f988baa53719d5 Mon Sep 17 00:00:00 2001 From: doris-xiao-bybit Date: Fri, 6 Nov 2026 14:14:15 +0800 Subject: [PATCH 2/3] sdk update --- .github/workflows/ci.yml | 7 +++---- README.md | 10 ++++++++++ 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1e95005..9b587ed 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -82,10 +82,9 @@ jobs: lowest-deps: # Verify the SDK still builds and tests pass against the LOWEST versions - # of every `require` constraint (guzzle ^7.5 → 7.5.0, etc.). The regular - # `build` job resolves highest-compatible and would silently start using - # a Guzzle 7.6+-only API without bumping the constraint, which would break - # users pinned to 7.5. + # of every `require` constraint (guzzle ^7.16.1 → 7.16.1, etc.). The regular + # `build` job resolves highest-compatible versions and would not catch use + # of APIs unavailable in the minimum supported dependency versions. name: PHP 8.1 — prefer-lowest dep resolve + phpunit runs-on: ubuntu-latest steps: diff --git a/README.md b/README.md index d214de3..3833625 100644 --- a/README.md +++ b/README.md @@ -155,12 +155,22 @@ Each API group is a readonly property on `Bybit\Client`: - `$client->asset` — coin balance, funding history - `$client->user` — sub-accounts, API-key management - `$client->affiliate` — sub-affiliate lists +- `$client->alpha` — Alpha trading, prediction markets, liquidity pools - `$client->broker` — broker earnings, distributions - `$client->cryptoLoan` — flexible / fixed crypto loans +- `$client->event` — event-contract orders, positions, trades, settlements +- `$client->fiat` — fiat balances, quotes, and trade history +- `$client->lending` — institutional loans - `$client->rfq` — request-for-quote (block trades) - `$client->spotMargin` — UTA spot margin +- `$client->spotX` — Launchpool, Puzzle, and Token Splash activities +- `$client->spreadTrade` — spread instruments and orders +- `$client->strategy` — algorithmic trading strategies +- `$client->tax` — batch tax reports - `$client->earn` — earn, liquidity mining, RWA, PWM, hold-to-earn - `$client->p2p` — P2P advertise / order / chat +- `$client->preUpgrade` — pre-upgrade account, order, execution, and position history +- `$client->referral` — referral campaigns, commissions, and invitations - `$client->bot` — DCA / grid / futures-combo / futures-grid / martingale ## Error Handling From 15c954386f955d269be1ef3932ebde6477964fac Mon Sep 17 00:00:00 2001 From: "johnny.wang" Date: Fri, 6 Nov 2026 15:02:42 +0700 Subject: [PATCH 3/3] fix: support optional authentication for margin coin data --- CHANGELOG.md | 3 ++ src/RestApi/LendingService.php | 3 +- src/Session.php | 17 +++++++- tests/RestApiContractTest.php | 80 +++++++++++++++++++++++++++++++--- 4 files changed, 95 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 00ba9c6..4d09d46 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,9 @@ ## 0.1.2 — 2026-10-28 +### Fixed +- Allow public margin token conversion queries without credentials while retaining authenticated OTC data and live credential updates. + ### Added - `AlphaService::getLpOrderList(...)` - `AlphaService::getLpPayTokenList(...)` diff --git a/src/RestApi/LendingService.php b/src/RestApi/LendingService.php index ac54c0c..3b31a77 100644 --- a/src/RestApi/LendingService.php +++ b/src/RestApi/LendingService.php @@ -53,6 +53,7 @@ public function insLoanDelayLiqStatus(array $options = []): array /** * Get Margin Token Conversion Details + * Uses public data without credentials and account-specific OTC data when authenticated. * * GET /v5/ins-loan/ensure-tokens-convert * @@ -61,7 +62,7 @@ public function insLoanDelayLiqStatus(array $options = []): array */ public function insLoanEnsureTokensConvert(array $options = []): array { - return $this->session->signRequest('GET', '/v5/ins-loan/ensure-tokens-convert', $options); + return $this->session->optionalAuthRequest('GET', '/v5/ins-loan/ensure-tokens-convert', $options); } /** diff --git a/src/Session.php b/src/Session.php index 2cbe055..14e0eee 100644 --- a/src/Session.php +++ b/src/Session.php @@ -25,8 +25,8 @@ /** * Session owns the Guzzle client + auth-header assembly. Every service class - * receives a Session instance and dispatches through publicRequest() / - * signRequest(). + * receives a Session instance and dispatches through publicRequest(), + * signRequest(), or optionalAuthRequest(). * * Signing invariant: the payload signed and the query string sent on the wire * MUST be byte-identical. We build ONE query_str (sortAndEncode after key @@ -73,6 +73,19 @@ public function signRequest(string $method, string $path, ?array $params = null) return $this->dispatch($method, $path, $params, true); } + /** + * Endpoint supporting public data and authenticated account-specific data. + * Reads the live configuration on every request to support credential updates. + * + * @param array|null $params Query params for GET/DELETE, body for POST/PUT/PATCH. + * @return BybitEnvelope + */ + public function optionalAuthRequest(string $method, string $path, ?array $params = null): array + { + $signed = $this->config->apiKey !== null && $this->config->apiSecret !== null; + return $this->dispatch($method, $path, $params, $signed); + } + /** * @param array|null $params * @return array diff --git a/tests/RestApiContractTest.php b/tests/RestApiContractTest.php index 44f32df..b7f4cfd 100644 --- a/tests/RestApiContractTest.php +++ b/tests/RestApiContractTest.php @@ -4,6 +4,7 @@ namespace Bybit\Tests; +use Bybit\Authentication; use Bybit\Client; use Bybit\Configuration; use GuzzleHttp\Client as GuzzleClient; @@ -171,6 +172,67 @@ public function testInstitutionalLoanProductInfoIsPublic(): void $this->assertFalse($request->hasHeader('X-BAPI-SIGN')); } + public function testMarginCoinConversionInfoIsPublicWithoutCredentials(): void + { + $history = []; + $client = $this->makeClient($history, false); + + $client->lending->insLoanEnsureTokensConvert(['productId' => '81']); + + $this->assertCount(1, $history); + $request = $history[0]['request']; + $this->assertSame('GET', $request->getMethod()); + $this->assertSame('/v5/ins-loan/ensure-tokens-convert', $request->getUri()->getPath()); + $this->assertSame('productId=81', $request->getUri()->getQuery()); + $this->assertFalse($request->hasHeader('X-BAPI-API-KEY')); + $this->assertFalse($request->hasHeader('X-BAPI-SIGN')); + } + + public function testMarginCoinConversionInfoRetainsAuthenticatedOtcAccess(): void + { + $history = []; + $client = $this->makeClient($history); + + $client->lending->insLoanEnsureTokensConvert(['productId' => '81']); + + $this->assertCount(1, $history); + $request = $history[0]['request']; + $this->assertSame('productId=81', $request->getUri()->getQuery()); + $this->assertSame('test-key', $request->getHeaderLine('X-BAPI-API-KEY')); + $this->assertSame( + Authentication::signV5( + 'test-secret', + $request->getHeaderLine('X-BAPI-TIMESTAMP'), + 'test-key', + $request->getHeaderLine('X-BAPI-RECV-WINDOW'), + $request->getUri()->getQuery() + ), + $request->getHeaderLine('X-BAPI-SIGN') + ); + } + + public function testMarginCoinConversionInfoTracksCredentialUpdates(): void + { + $history = []; + $config = $this->makeConfiguration($history, false, 3); + $client = new Client($config); + + $client->lending->insLoanEnsureTokensConvert(); + $config->apiKey = 'rotated-key'; + $config->apiSecret = 'rotated-secret'; + $client->lending->insLoanEnsureTokensConvert(); + $config->apiKey = null; + $config->apiSecret = null; + $client->lending->insLoanEnsureTokensConvert(); + + $this->assertCount(3, $history); + $this->assertFalse($history[0]['request']->hasHeader('X-BAPI-API-KEY')); + $this->assertSame('rotated-key', $history[1]['request']->getHeaderLine('X-BAPI-API-KEY')); + $this->assertNotSame('', $history[1]['request']->getHeaderLine('X-BAPI-SIGN')); + $this->assertFalse($history[2]['request']->hasHeader('X-BAPI-API-KEY')); + $this->assertFalse($history[2]['request']->hasHeader('X-BAPI-SIGN')); + } + public function testSmokeProviderCoversEveryClientService(): void { $covered = []; @@ -206,13 +268,21 @@ public function testUnsupportedOrAbandonedAssetMethodIsNotPublished(string $meth /** @param array> $history */ private function makeClient(array &$history, bool $authenticated = true): Client { - $mock = new MockHandler([ - new Response(200, ['Content-Type' => 'application/json'], '{"retCode":0,"retMsg":"OK","result":{},"retExtInfo":{},"time":0}'), - ]); + return new Client($this->makeConfiguration($history, $authenticated)); + } + + /** @param array> $history */ + private function makeConfiguration(array &$history, bool $authenticated = true, int $responseCount = 1): Configuration + { + $responses = []; + for ($i = 0; $i < $responseCount; $i++) { + $responses[] = new Response(200, ['Content-Type' => 'application/json'], '{"retCode":0,"retMsg":"OK","result":{},"retExtInfo":{},"time":0}'); + } + $mock = new MockHandler($responses); $stack = HandlerStack::create($mock); $stack->push(Middleware::history($history)); - return new Client(new Configuration( + return new Configuration( apiKey: $authenticated ? 'test-key' : null, apiSecret: $authenticated ? 'test-secret' : null, httpClient: new GuzzleClient([ @@ -220,6 +290,6 @@ private function makeClient(array &$history, bool $authenticated = true): Client 'base_uri' => 'https://api-testnet.bybit.com', 'http_errors' => false, ]), - )); + ); } }