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/CHANGELOG.md b/CHANGELOG.md
index 9b10c57..4d09d46 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,4 +1,105 @@
# Changelog
+
+## 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(...)`
+- `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/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
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..3b31a77
--- /dev/null
+++ b/src/RestApi/LendingService.php
@@ -0,0 +1,139 @@
+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
+ * Uses public data without credentials and account-specific OTC data when authenticated.
+ *
+ * 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->optionalAuthRequest('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/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 6e65d06..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;
@@ -57,6 +58,207 @@ 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 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 = [];
+ 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,22 +266,30 @@ 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}'),
- ]);
+ 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(
- apiKey: 'test-key',
- apiSecret: 'test-secret',
+ return new Configuration(
+ apiKey: $authenticated ? 'test-key' : null,
+ apiSecret: $authenticated ? 'test-secret' : null,
httpClient: new GuzzleClient([
'handler' => $stack,
'base_uri' => 'https://api-testnet.bybit.com',
'http_errors' => false,
]),
- ));
+ );
}
}
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);