Skip to content

Bybit SDK

Complete reference for ctx.bybit — programmatic trading on Bybit from worker code.

Bybit V5 API

This SDK wraps the Bybit V5 unified API. Live, demo, and testnet environments all supported.

Setup

  1. Add a Bybit trading block to your workspace canvas.
  2. Open the inspector → API Keys → pick a key (or add a new one in Settings → API Keys).
  3. Connect the block to your Worker block via an edge.
  4. In the worker's inspector, the ctx.bybit adapter is now available.
python
def tick(ctx):
    ticker = ctx.bybit.get_tickers("BTCUSDT")
    ctx.log.info(f"BTC: {ticker['list'][0]['lastPrice']}")

If no Bybit block is connected, calling any method raises:

RuntimeError: No trading block connected. Connect a Bybit block to this worker.

Categories & Modes

Bybit V5 splits markets into four categories. The default is taken from your block's inspector but can be overridden per call:

CategoryDescription
linearUSDT/USDC perpetuals & futures (default)
inverseCoin-margined perpetuals (BTCUSD, ETHUSD)
spotSpot trading
optionOptions (BTC, ETH, SOL)

Account modes (api_mode):

ModeEndpointNotes
liveapi.bybit.comReal funds
demoapi-demo.bybit.comPaper-trading with real market data
testnetapi-testnet.bybit.comSynthetic test environment

Mode is stored on the API key — switch in Settings → API Keys → Bybit.

Market Data

get_tickers

Latest ticker (last price, bid, ask, 24h volume).

python
ctx.bybit.get_tickers(symbol: str = "BTCUSDT", base_coin: str = None) -> dict
ParamTypeDescription
symbolstrTrading pair, e.g. "BTCUSDT"
base_coinstrFor options only: filters by base ("BTC", "ETH", "SOL")

Returns: {"list": [{"symbol", "lastPrice", "bid1Price", "ask1Price", "volume24h", ...}]}

python
t = ctx.bybit.get_tickers("BTCUSDT")
last = float(t["list"][0]["lastPrice"])

WebSocket cache

On PRO/MAX plans this returns cached ticker data at 0ms latency from the live WS stream — no REST call.

get_klines

OHLCV candlestick data.

python
ctx.bybit.get_klines(
    symbol: str,
    interval: str = "60",
    limit: int = 200,
    start: int = None,
    end: int = None,
    category: str = None,
) -> dict
ParamTypeDescription
intervalstr"1", "3", "5", "15", "30", "60", "120", "240", "360", "720", "D", "W", "M" (minutes / Day / Week / Month)
limitintMax 1000
start, endintUnix ms timestamps

Returns: {"list": [[start, open, high, low, close, volume, turnover], ...]}

python
candles = ctx.bybit.get_klines("BTCUSDT", interval="60", limit=24)
closes = [float(c[4]) for c in candles["list"]]
sma_24h = sum(closes) / len(closes)

get_mark_price_klines

Mark-price candles (for derivatives — used for liquidation calculations).

python
ctx.bybit.get_mark_price_klines(
    symbol: str,
    interval: str = "60",
    limit: int = 200,
    category: str = None,
) -> dict

Same shape as get_klines. Only available for linear / inverse categories.

get_index_price_klines

Index-price candles (basket of spot prices the perpetual tracks).

python
ctx.bybit.get_index_price_klines(symbol, interval, limit, category) -> dict

get_orderbook

Current order book depth.

python
ctx.bybit.get_orderbook(symbol: str, limit: int = 50, category: str = None) -> dict
ParamLimit
linear / inverse1, 25, 50, 100, 200, 500
spot1, 50, 200
option25

Returns: {"s": "BTCUSDT", "b": [[price, size], ...], "a": [[price, size], ...], "ts": 1234567890, "u": 12345}

python
ob = ctx.bybit.get_orderbook("BTCUSDT", limit=50)
best_bid = float(ob["b"][0][0])
best_ask = float(ob["a"][0][0])
spread_bps = (best_ask - best_bid) / best_bid * 10000

get_recent_trades

Most recent public trades.

python
ctx.bybit.get_recent_trades(symbol: str, limit: int = 60, category: str = None) -> dict

get_funding_history

Historical funding rates for perpetuals.

python
ctx.bybit.get_funding_history(
    symbol: str,
    limit: int = 200,
    start_time: int = None,
    end_time: int = None,
    category: str = None,
) -> dict

get_open_interest

Open-interest history (aggregate position size on the perp).

python
ctx.bybit.get_open_interest(
    symbol: str,
    interval_time: str = "1h",  # "5min" | "15min" | "30min" | "1h" | "4h" | "1d"
    limit: int = 200,
    start_time: int = None,
    end_time: int = None,
    category: str = None,
) -> dict

get_long_short_ratio

Long/short ratio across the platform (sentiment indicator).

python
ctx.bybit.get_long_short_ratio(
    symbol: str,
    period: str = "1h",  # "5min" | "15min" | "30min" | "1h" | "4h" | "1d"
    limit: int = 50,
    category: str = None,
) -> dict

get_instruments

All tradable instruments for a category (and optionally a base coin for options).

python
ctx.bybit.get_instruments(base_coin: str = "BTC", category: str = "option") -> dict

get_delivery_price

Delivery / exercise prices for futures and options.

python
ctx.bybit.get_delivery_price(base_coin: str = "BTC", category: str = "option") -> dict

Account & Wallet

get_balance

Wallet balance across coins.

python
ctx.bybit.get_balance(coin: str = None) -> dict
ParamDescription
coinFilter to a single coin (e.g. "USDT"). Omit to return all.

Returns: {"list": [{"totalEquity", "totalAvailableBalance", "coin": [{"coin", "walletBalance", "availableToWithdraw", ...}]}]}

python
bal = ctx.bybit.get_balance("USDT")
usdt = bal["list"][0]["coin"][0]
ctx.log.info(f"Free USDT: {usdt['availableToWithdraw']}")

WebSocket cache

PRO/MAX: cached from the private WS stream at 0ms — no REST.

get_account_info

Account type (UTA / Classic), unified margin mode, master/sub.

python
ctx.bybit.get_account_info() -> dict

get_fee_rate

Maker / taker fees for your tier.

python
ctx.bybit.get_fee_rate(symbol: str = None, category: str = None) -> dict

get_transaction_log

Account transaction log (deposits, withdrawals, fees, funding, realized PnL).

python
ctx.bybit.get_transaction_log(
    account_type: str = "UNIFIED",
    category: str = None,
    currency: str = None,
    type: str = None,         # TRADE | SETTLEMENT | DELIVERY | LIQUIDATION | TRANSFER_IN | …
    start_time: int = None,
    end_time: int = None,
    limit: int = 50,
) -> dict

Positions

get_positions

All open positions, optionally filtered by symbol.

python
ctx.bybit.get_positions(symbol: str = None) -> dict

Returns: {"list": [{"symbol", "side", "size", "entryPrice", "leverage", "unrealisedPnl", "markPrice", "liqPrice", ...}]}

python
positions = ctx.bybit.get_positions()
for p in positions["list"]:
    if float(p["size"]) > 0:
        ctx.log.info(f"{p['symbol']} {p['side']}: PnL {p['unrealisedPnl']}")

get_closed_pnl

Closed-position PnL history.

python
ctx.bybit.get_closed_pnl(symbol: str = None, limit: int = 50, category: str = None) -> dict

set_leverage

Set leverage on a symbol (separate buy / sell legs for hedge mode).

python
ctx.bybit.set_leverage(symbol: str, buy_leverage, sell_leverage=None) -> dict
python
ctx.bybit.set_leverage("BTCUSDT", 10)        # one-way: 10x both sides
ctx.bybit.set_leverage("BTCUSDT", 5, 3)      # hedge: 5x long, 3x short

switch_margin_mode

Switch isolated ↔ cross margin for a symbol.

python
ctx.bybit.switch_margin_mode(
    symbol: str,
    trade_mode: int,    # 0 = cross, 1 = isolated
    buy_leverage: str = "10",
    sell_leverage: str = None,
) -> dict

set_position_mode

Switch one-way ↔ hedge mode at the account or symbol level.

python
ctx.bybit.set_position_mode(
    mode: int,          # 0 = one-way, 3 = hedge (both buy & sell)
    symbol: str = None, # None = applies to whole category
    coin: str = None,   # for inverse: by margin coin
    category: str = None,
) -> dict

set_risk_limit

Set the per-position risk limit (controls max position size and forced-liquidation tier).

python
ctx.bybit.set_risk_limit(
    symbol: str,
    risk_id: int,           # Bybit's pre-defined tier ID; see `get_risk_limit`
    position_idx: int = 0,  # 0 = one-way / hedge buy, 1 = hedge buy, 2 = hedge sell
    category: str = None,
) -> dict

set_trading_stop

Apply Take Profit / Stop Loss / trailing stop to an open position.

python
ctx.bybit.set_trading_stop(
    symbol: str,
    take_profit: str = None,
    stop_loss: str = None,
    trailing_stop: str = None,
    tp_trigger_by: str = None,    # "LastPrice" | "MarkPrice" | "IndexPrice"
    sl_trigger_by: str = None,
    active_price: str = None,     # activation price for trailing stop
    tp_size: str = None,          # partial TP size (default = full)
    sl_size: str = None,
    position_idx: int = 0,
    category: str = None,
) -> dict
python
# Set TP at 3% above entry, SL at 1% below
pos = ctx.bybit.get_positions("BTCUSDT")["list"][0]
entry = float(pos["entryPrice"])
ctx.bybit.set_trading_stop(
    symbol="BTCUSDT",
    take_profit=str(entry * 1.03),
    stop_loss=str(entry * 0.99),
)

Orders

place_order

Place a single order.

python
ctx.bybit.place_order(
    symbol: str,
    side: str,                  # "Buy" | "Sell"
    qty: str,                   # quantity as string
    order_type: str = "Market", # "Market" | "Limit"
    price: str = None,          # required for Limit
    category: str = None,
) -> dict

Returns: {"orderId": "...", "orderLinkId": "..."}

python
# Market buy 0.001 BTC
r = ctx.bybit.place_order("BTCUSDT", "Buy", "0.001", "Market")

# Limit sell 0.5 ETH at $3000
r = ctx.bybit.place_order(
    symbol="ETHUSDT", side="Sell", qty="0.5",
    order_type="Limit", price="3000",
)

Trade logging

Every successful order is recorded in your TradeLog table — visible in Journal block and ctx.bybit.get_executions().

amend_order

Modify an unfilled or partially-filled order (qty, price, TP, SL).

python
ctx.bybit.amend_order(
    symbol: str,
    order_id: str,
    qty: str = None,
    price: str = None,
    take_profit: str = None,
    stop_loss: str = None,
    category: str = None,
) -> dict

cancel_order

Cancel a single order by ID.

python
ctx.bybit.cancel_order(symbol: str, order_id: str, category: str = None) -> dict

cancel_all_orders

Cancel all open orders, optionally filtered.

python
ctx.bybit.cancel_all_orders(
    symbol: str = None,
    category: str = None,
    base_coin: str = None,
    settle_coin: str = None,
) -> dict

get_orders

Active (unfilled) orders.

python
ctx.bybit.get_orders(symbol: str = None) -> dict

WebSocket cache

PRO/MAX: cached from private WS at 0ms.

get_order_history

Filled / cancelled / rejected orders.

python
ctx.bybit.get_order_history(
    symbol: str = None,
    order_id: str = None,
    limit: int = 50,
    category: str = None,
) -> dict

get_executions

Trade fills with fees (the actual transactions, not just orders).

python
ctx.bybit.get_executions(
    symbol: str = None,
    order_id: str = None,
    limit: int = 50,
    category: str = None,
) -> dict

batch_place_orders

Place up to 20 orders in one call (atomic acceptance, individual fills).

python
ctx.bybit.batch_place_orders(orders: list, category: str = None) -> dict
python
ctx.bybit.batch_place_orders([
    {"symbol": "BTCUSDT", "side": "Buy",  "orderType": "Limit", "qty": "0.001", "price": "60000"},
    {"symbol": "BTCUSDT", "side": "Buy",  "orderType": "Limit", "qty": "0.001", "price": "59000"},
    {"symbol": "BTCUSDT", "side": "Buy",  "orderType": "Limit", "qty": "0.001", "price": "58000"},
])

batch_cancel_orders

Cancel up to 20 orders in one call.

python
ctx.bybit.batch_cancel_orders(orders: list, category: str = None) -> dict
python
open = ctx.bybit.get_orders("BTCUSDT")["list"]
ctx.bybit.batch_cancel_orders([{"symbol": o["symbol"], "orderId": o["orderId"]} for o in open])

Account Operations

internal_transfer

Transfer between sub-accounts and account types.

python
ctx.bybit.internal_transfer(
    coin: str,
    amount: str,
    from_account_type: str = "UNIFIED",  # UNIFIED | FUND | SPOT | CONTRACT | OPTION
    to_account_type: str = "FUND",
    transfer_id: str = None,             # auto UUID if omitted
) -> dict

Common Patterns

Demo / testnet during development

Set the API-key mode in Settings → API Keys → Bybit to demo or testnet. All worker calls automatically route to the right environment. Switch back to live when you're ready.

Error handling

All methods that hit a remote API can raise BybitAPIError (extends ExchangeAPIError). For network failures, httpx.HTTPStatusError. Wrap calls if needed:

python
def tick(ctx):
    try:
        positions = ctx.bybit.get_positions()
    except Exception as e:
        ctx.log.error(f"Bybit unreachable: {e}")
        return

Cloud-Run proxy (PRO+ plans)

Workers on PRO and above route Bybit calls through a Google Cloud Run proxy with rotating exit IPs. This avoids rate-limit concentration when many users share the same server IP. Transparent — no code changes.

WebSocket caching

PRO+ plans subscribe to Bybit's public + private WS streams in the background. Methods get_tickers, get_orderbook, get_balance, get_positions, get_orders automatically prefer the cache when fresh — 0 ms latency, 0 REST calls.

Recipes

Simple DCA (dollar-cost averaging)

python
def setup(ctx):
    ctx.state.set("last_buy_ts", 0)
    ctx.state.set("buy_amount_usdt", 50)

def tick(ctx):
    import time
    now = int(time.time())
    last = ctx.state.get("last_buy_ts", 0)

    if now - last < 3600:  # once an hour
        return

    px = float(ctx.bybit.get_tickers("BTCUSDT")["list"][0]["lastPrice"])
    qty = round(ctx.state.get("buy_amount_usdt", 50) / px, 4)

    r = ctx.bybit.place_order("BTCUSDT", "Buy", str(qty), "Market")
    ctx.state.set("last_buy_ts", now)
    ctx.log.info(f"DCA buy: {qty} BTC at {px}{r.get('orderId')}")

Fixed-grid market making

python
def setup(ctx):
    grid = []
    px = float(ctx.bybit.get_tickers("BTCUSDT")["list"][0]["lastPrice"])
    step = px * 0.005  # 0.5% grid spacing
    for i in range(1, 6):
        grid.append({"symbol": "BTCUSDT", "side": "Buy",  "orderType": "Limit",
                     "qty": "0.001", "price": str(round(px - i * step))})
        grid.append({"symbol": "BTCUSDT", "side": "Sell", "orderType": "Limit",
                     "qty": "0.001", "price": str(round(px + i * step))})
    ctx.bybit.batch_place_orders(grid)
    ctx.state.set("grid_active", True)

def tick(ctx):
    # Re-fill on any executed legs every minute
    open_orders = ctx.bybit.get_orders("BTCUSDT")["list"]
    if len(open_orders) >= 10:
        return  # all 10 orders still alive
    # … reissue logic …

Trailing stop on existing position

python
def tick(ctx):
    positions = ctx.bybit.get_positions("BTCUSDT")["list"]
    pos = next((p for p in positions if float(p["size"]) > 0), None)
    if not pos:
        return

    # Activate a 1% trailing stop the moment we're 2% in profit
    entry = float(pos["entryPrice"])
    mark = float(pos["markPrice"])
    if mark > entry * 1.02:
        ctx.bybit.set_trading_stop(
            symbol="BTCUSDT",
            trailing_stop=str(round(entry * 0.01)),
            active_price=str(round(entry * 1.02)),
        )
        ctx.log.info("Trailing stop activated")

Reference

Bybit V5 endpointSDK method
GET /v5/market/tickersget_tickers
GET /v5/market/klineget_klines
GET /v5/market/mark-price-klineget_mark_price_klines
GET /v5/market/index-price-klineget_index_price_klines
GET /v5/market/orderbookget_orderbook
GET /v5/market/recent-tradeget_recent_trades
GET /v5/market/funding/historyget_funding_history
GET /v5/market/open-interestget_open_interest
GET /v5/market/account-ratioget_long_short_ratio
GET /v5/market/instruments-infoget_instruments
GET /v5/market/delivery-priceget_delivery_price
GET /v5/account/wallet-balanceget_balance
GET /v5/account/infoget_account_info
GET /v5/account/fee-rateget_fee_rate
GET /v5/account/transaction-logget_transaction_log
GET /v5/position/listget_positions
GET /v5/position/closed-pnlget_closed_pnl
POST /v5/position/set-leverageset_leverage
POST /v5/position/switch-isolatedswitch_margin_mode
POST /v5/position/switch-modeset_position_mode
POST /v5/position/set-risk-limitset_risk_limit
POST /v5/position/trading-stopset_trading_stop
POST /v5/order/createplace_order
POST /v5/order/amendamend_order
POST /v5/order/cancelcancel_order
POST /v5/order/cancel-allcancel_all_orders
GET /v5/order/realtimeget_orders
GET /v5/order/historyget_order_history
GET /v5/execution/listget_executions
POST /v5/order/create-batchbatch_place_orders
POST /v5/order/cancel-batchbatch_cancel_orders
POST /v5/asset/transfer/inter-transferinternal_transfer

AiSpinner Documentation