Python SDK

Runtime objects and service interfaces available to custom BeeQuant strategy code.

1. SDK overview

The BeeQuant Python SDK provides a consistent quantitative-trading API across backtesting, paper trading, and live trading. You can use the SDK when writing Python code in both the custom trading logic node and the custom data processing node. However, exchange clients (ctx.exchange) are available only to custom trading logic and visual trading nodes. Custom data processing nodes cannot access ctx.exchange or ctx.signal, including market-data and trading methods such as get_price, get_klines, and get_funding_rate. They can only transform their input DataFrame.

Backtest market-data limitations: Backtests do not contain actual exchange trades, order-book snapshots, or order-book events. Bar-level execution is simulated from candlestick OHLC data, while tick-level execution uses a synthetic price path interpolated from one-minute OHLC data. Consequently, price queries in a backtest cannot be used to infer real bid/ask prices, order-book depth, fill ordering, partial fills, or the exact order in which stop conditions would have triggered in live trading.
ModulePurpose
beequant.objectData object definitions for accounts, orders, positions, candlesticks, and related entities
beequant.apiAbstract interfaces for trading clients, runtime context, logging, and other services
Preinstalled third-party packages

The backend runtime for custom data processing and custom trading logic nodes includes the following commonly used packages, which can be imported directly:

  • Data processing: pandas, numpy, pyarrow, scipy, python-dateutil, and pytz
  • Technical analysis: ta and TA-Lib
  • Machine learning: scikit-learn, lightgbm, and optuna
  • Deep learning: torch (the GPU image additionally includes a CUDA-enabled build, matplotlib, and seaborn)
  • Other packages: requests, sqlalchemy, redis, pydantic, and pyparsing
⚠ Not preinstalled: statsmodels, xgboost, catboost, and tensorflow. Use scikit-learn, lightgbm, or torch instead.

2. Data objects beequant.object

2.1 Account — Account information

FieldTypeDescription
idstrAccount ID
indexintAccount index
exchangestrExchange name
market_typestrMarket type (spot/um/cm)
initial_capitalfloatInitial capital
total_equityfloatTotal account equity
available_balancefloatAvailable balance
frozen_balancefloatFrozen balance
unrealized_pnlfloatUnrealized PnL
realized_pnlfloatRealized PnL
used_marginfloatMargin in use
margin_ratiofloatMargin ratio
leverageintLeverage
balanceslist[Balance]Balance entries
positionslist[Position]Open positions

2.2 Balance — Balance information

FieldTypeDescription
account_idstrAccount ID
exchangestrExchange
assetstrAsset
amountfloatTotal balance
availablefloatAvailable balance
frozenfloatFrozen balance
entry_pricefloatAverage entry price
updated_atintLast update time in milliseconds

2.3 Position — Position information

FieldTypeDescription
account_idstrAccount ID
exchangestrExchange
symbolstrTrading symbol
position_sidestrPosition side (long/short)
amountfloatPosition quantity
entry_pricefloatAverage entry price
mark_pricefloatMark price
leverageintLeverage
marginfloatMargin
unrealized_pnlfloatUnrealized PnL
realized_pnlfloatRealized PnL
notional_valuefloatNotional value
updated_atintLast update time in milliseconds
PositionSide values: long (long position) / short (short position) / both (hedge mode)

2.4 Order — Order information

FieldTypeDescription
order_idstrOrder ID
symbolstrTrading symbol
sidestrOrder side (buy/sell)
position_sidestrPosition side
order_typestrOrder type (market/limit)
pricefloatOrder price
amountfloatOrder quantity
filled_amountfloatFilled quantity
filled_pricefloatAverage fill price
commissionfloatTrading fee
statusstrOrder status
exit_reasonstrPosition exit reason
created_atintCreation time in milliseconds
OrderStatus: created / filled / partially_filled / canceled / rejected / expired / failed
OrderType: market / limit
MarketType: spot / um (USDT-margined futures) / cm (coin-margined futures)

2.5 Kline — Candlestick data

FieldTypeDescription
timestampintTimestamp in milliseconds
openfloatOpen price
highfloatHigh price
lowfloatLow price
closefloatClose price
volumefloatTrading volume

2.6 Ticker — Market ticker

Backtests do not simulate an order book: last_price is the only meaningful price; bid_price and ask_price equal the latest price; and bid_qty and ask_qty are 0.0.

FieldTypeDescription
exchangestrExchange
symbolstrTrading symbol
market_typestrMarket type (spot/um/cm)
last_pricefloatLatest price
bid_pricefloatBest bid price
bid_qtyfloatQuantity at the best bid
ask_pricefloatBest ask price
ask_qtyfloatQuantity at the best ask
update_timeintLast update time in milliseconds

2.7 SymbolInfo — Symbol information

FieldTypeDescription
exchangestrExchange
symbolstrTrading symbol
base_assetstrBase asset
quote_assetstrQuote asset
min_qtyfloatMinimum order quantity
step_sizefloatOrder quantity increment
tick_sizefloatMinimum price increment
max_leveragefloatMaximum leverage

3. API interfaces beequant.api

3.1 UserContext — Runtime context

The main entry point for strategy code. It provides unified access to trading, logging, signals, and file storage, and supports dynamic attributes for retaining user-defined state across bars.

AttributeTypeDescription
ctx.exchangeExchangeExchange client manager. Use ctx.exchange[0] to get the first client. Available only in custom trading logic and visual trading nodes; unavailable in custom data processing nodes
ctx.logLogLogging service
ctx.signalSignalSignal access. Available only in custom trading logic and visual trading nodes; unavailable in custom data processing nodes
ctx.fileFileFile persistence service (models / parameters)
ctx.<any_name>AnyDynamic attribute for retaining user-defined state across bars, for example ctx.entry_price = {}
python
def init(ctx: UserContext):
    ctx.max_position = 0.1  # Dynamic attribute retained across bars
    ctx.entry_price = {}


def handle_data(ctx: UserContext, datas):
    client = ctx.exchange[0]
    ctx.log.info("Processing bar")

3.2 Client — Trading client

Provides a consistent interface for queries, market data, positions, and order placement across backtesting, paper trading, and live trading. Access it through ctx.exchange[0].

Metadata and utility methods

MethodReturn valueDescription
get_exchange()strReturns the exchange name, such as binance, okx, or bybit
get_market()strReturns the market type: spot, um, or cm
get_exchange_market()tuple[str, str]Returns (exchange, market)
set_symbol_list(symbols)-Sets the symbols monitored by the strategy
get_symbol_list() / symbol_listlist[str]Returns the current symbol list
get_price(symbol)floatReturns the current price from ticker.last_price
get_tickers(symbols)list[Ticker]Returns tickers for multiple symbols
get_total_equity(quote_asset)floatReturns total account equity, denominated in USDT by default
get_leverage(symbol)intReturns the current leverage
set_default_leverage(leverage)-Sets the default leverage
get_cumulative_realized_pnl()Optional[float]Returns the strategy's cumulative realized PnL

Account queries

MethodReturn valueDescription
get_account()AccountReturns account information
get_balance(symbol)BalanceReturns the balance for a specific asset
get_balances()list[Balance]Returns all balances
get_position(symbol, position_side)PositionReturns a specific position
get_positions()list[Position]Returns all positions

Order queries

MethodReturn valueDescription
get_pending_orders(symbol=None)list[Order]Returns open orders; omit symbol to query all symbols
get_history_orders(symbol, limit=100)list[Order]Returns historical orders

Market data

MethodReturn valueDescription
get_kline(symbol, interval=None)Optional[Kline]Returns the current candlestick. Backtests prevent look-ahead; see the backtest market-data limitations above for cross-mode details
get_klines(symbol, interval, limit=100)list[Kline]Returns completed historical candlesticks with timestamp, open, high, low, close, and volume fields
get_ticker(symbol)TickerReturns the current ticker; backtests return a simulated price and do not provide a real order book

Funding rates and fees

Real data is available only for UM/CM futures clients. Spot markets and unsupported environments return None or [].

MethodReturn valueDescription
get_funding_rate(symbol)Optional[dict]Returns the current or most recently available funding-rate information
get_funding_fees(symbol, start_ms, end_ms)list[dict]Returns funding-fee records for the given interval; use symbol="" to query all symbols in the account

get_funding_rate returns a dict containing symbol, fundingRate, nextFundingRate, nextFundingTimeMs, markPrice, indexPrice, and intervalHours.

python
client = ctx.exchange[0]  # Must be a UM/CM futures account

info = client.get_funding_rate("BTC_USDT")
if info is not None:
    rate = info.get("fundingRate", 0.0)        # Current rate; 0.0001 = 0.01%
    next_ms = info.get("nextFundingTimeMs", 0) # Next settlement time in milliseconds
    hours = info.get("intervalHours", 8)       # Settlement interval in hours

High-level trading methods ⭐

MethodReturn valueDescription
place(symbol, side, qty, limit_price, cost, position_side)Optional[str]Places a general-purpose order and returns its order_id
target(symbol, qty, limit_price, cost, auto_partial)Optional[str]Adjusts a one-way position to the target quantity
target_percent(symbol, target_percent, limit_price, threshold, auto_partial)Optional[str]Adjusts to a target portfolio exposure; this is the most commonly used method
close_all(symbol)list[str]Closes all positions for the symbol and returns the order IDs
cancel_all(symbol=None)-Cancels all open orders
set_exit_reason(order_id, reason)boolRecords the reason for closing a position, primarily for backtest analysis

target_percent() explained

Automatically calculates the target position quantity from total account equity and the current price. This is the recommended way to manage position size.

python
client.target_percent(
    symbol="BTC_USDT",
    target_percent=0.1,  # Target position value as a share of total equity
    limit_price=None,    # None places a market order
    threshold=0.05,      # Skip rebalancing when the deviation is below 5%
    auto_partial=True,   # Reduce the order automatically if funds are insufficient
)
Formula:
Target position value = total account equity × target_percent
Target position quantity = target position value ÷ current price
target_percentSpot behaviorFutures behavior
0Close the positionClose all positions
0.5Position value = 50% of total equityLong; notional value = 50% of total equity
1.0Fully investedLong; notional value = 100% of total equity
-0.5Unsupported (must be ≥ 0)Short; notional value = 50% of total equity
2.0Not recommended2× leveraged long exposure
python
# Assume total equity is 10,000 USDT and BTC is priced at 50,000 USDT.
# target_percent = 0.8 -> target quantity = 10,000 * 0.8 / 50,000 = 0.16 BTC

client.target_percent("BTC_USDT", 0.8)   # No position -> open a 0.16 BTC long
client.target_percent("BTC_USDT", 0.8)   # 0.1 BTC long -> add 0.06 BTC
client.target_percent("BTC_USDT", 0.8)   # 0.2 BTC long -> reduce by 0.04 BTC
client.target_percent("BTC_USDT", -0.8)  # 0.1 BTC long -> close the long, then open a short
client.target_percent("BTC_USDT", 0)     # Close the position

Basic trading methods

python
# Spot
client.buy(symbol, qty=None, price=None, cost=None)
client.sell(symbol, qty=None, price=None, cost=None)

# One-way futures positions
client.open_long(symbol, qty=None, price=None, cost=None)
client.close_long(symbol, qty=None, price=None, cost=None)
client.open_short(symbol, qty=None, price=None, cost=None)
client.close_short(symbol, qty=None, price=None, cost=None)

# Other methods
client.set_leverage(symbol, leverage=None)
client.cancel_order(symbol, order_id)
qty always means a quantity of the base currency, while cost always means an amount denominated in USDT. Provide one or the other, not both.

3.3 Exchange — Client manager

Manages multiple client instances and supports lookup by name or index.

MethodDescription
ctx.exchange[0]Returns a client by index; this is the most common form
ctx.exchange.get_by_name('binance')Returns a client by exchange name
ctx.exchange.get_all_clients()Returns all registered clients

3.4 Signal — Signal access

Provides access to trading signals generated by the strategy. The system retrieves data from ctx.signal.get() in advance and passes it to the datas parameter of handle_data.

python
# datas is supplied automatically, so you normally do not call ctx.signal.get() yourself.
def handle_data(ctx: UserContext, datas):
    signal_df = datas  # DataFrame for one time step, including symbol/timestamp/prediction

# Historical features are calculated by upstream processing nodes.
# historyPeriods must cover the required lookback window.

3.5 Log — Logging service

MethodDescription
ctx.log.info(msg, source='', extra='')Business events such as opening, closing, or rebalancing positions
ctx.log.detail(msg, source='')Per-bar details such as selection rankings and target positions; suitable for frequent output
ctx.log.warn(msg, source='')Risk and validation warnings
ctx.log.error(msg, source='')Error messages
ctx.log.debug(msg, source='')Local debugging; not recommended in production
ctx.log.dataframe(df, title='Data preview', source='')Writes a DataFrame preview that the web interface renders as a table
Strategy code should always use ctx.log.*. Do not call print() directly.

3.6 File — File persistence

Persists model files (machine learning) and parameter files (strategy state recovery) across runs. Every method is addressed by file name; saving under an existing name overwrites it (and does not consume an extra file slot). Internal file IDs are never exposed.

Local paths: the strategy process can only read and write the task work directory. /tmp, the home directory and arbitrary absolute paths are rejected. Always use ctx.file.work_path(name) when you need a path on disk.

The work directory is ephemeral: work_path(name) points at the task container's local disk, which is destroyed when the task ends.torch.save() and booster.save_model() only cover the "write locally" step —you must then call ctx.file.save_model(name) to upload before the file is actually persisted. Loading works the same way: call ctx.file.load_model(name) to fetch the remote file locally, then hand the path to the library.

MethodReturn valueDescription
work_path(name)strWritable absolute path inside the task work directory
save_model(name, local_path='')Optional[str]Uploads a model file; returns the file name on success
load_model(name, local_path='')Optional[str]Downloads a model file; returns the local path on success
save_params(name, params)Optional[str]Stores a parameter/state dict as JSON
load_params(name, default=None)Optional[dict]Reads parameters; returns default when absent
save_bytes(name, data)Optional[str]Uploads in-memory bytes directly
load_bytes(name)Optional[bytes]Reads a remote file into memory
list_files()list[FileInfo]Lists every file owned by the current user
exists(name)boolChecks whether a file exists
delete(name)boolDeletes a file to free quota
quota()FileQuotaReturns file count and storage usage

FileInfo: .name / .kind ("model" | "params") / .size / .size_str / .hash / .created_at / .updated_at; FileQuota: .file_count / .max_files / .used_bytes / .max_total_bytes / .max_model_bytes / .max_params_bytes

LimitMaximum
Single model file100 MB
Single parameter file (.json)1 MB
Files per user50
Total storage per user1 GB
File name length100 characters, no path separators

Allowed extensions (the test is whether strategy code can legally read the file back): models .lightgbm (lgb.Booster(model_file=...)), .pt / .pth (torch.load(..., weights_only=True)), .lstm / .transformer (platform AiModel loader); parameters .json.

.pkl / .pickle / .joblib cannot be saved (existing files stay readable and deletable): the static security rules permanently block import pickle, pickle.load and joblib.load, so such a file could never be deserialized. Export scikit-learn parameter arrays to .json, or switch to lightgbm / torch. tensorflow, onnxruntime and safetensors are not preinstalled either, so .h5 / .keras / .onnx / .safetensors are unsupported. Note that open(), pathlib, os and tempfile are blocked as well: writing to local disk must be done by the library itself (torch.save / booster.save_model). That step only fills the ephemeral work directory — you still need ctx.file.save_model(name) to persist it. For parameter files ctx.file.save_params() does both in one call.

python
# Model: persist after training, reuse on the next run
path = ctx.file.load_model("alpha.pt")
if path:
    model.load_state_dict(torch.load(path, weights_only=True))
else:
    train(model)
    torch.save(model.state_dict(), ctx.file.work_path("alpha.pt"))
    ctx.file.save_model("alpha.pt")

# LightGBM
booster.save_model(ctx.file.work_path("alpha.lightgbm"))
ctx.file.save_model("alpha.lightgbm")

# Parameters: strategy state recovery
state = ctx.file.load_params("state.json", default={"grid_level": 0})
state["grid_level"] += 1
ctx.file.save_params("state.json", state)

# Quota: clean up before hitting the file-count limit
q = ctx.file.quota()
if q.file_count >= q.max_files:
    oldest = sorted(ctx.file.list_files(), key=lambda f: f.updated_at)[0]
    ctx.file.delete(oldest.name)

4. Complete strategy example

The following signal-driven position management strategy demonstrates the standard use of all three SDK lifecycle functions. See the custom trading logic node documentation for more templates.

python
from beequant.api.context import UserContext
from beequant.api.client import Client


def init(ctx: UserContext):
    """Initialize the strategy. Called once."""
    ctx.log.info("Strategy initialized", source="Demo")
    ctx.open_threshold = 0.5
    ctx.close_threshold = 0.1
    ctx.max_position = 0.1


def handle_data(ctx: UserContext, datas):
    """Process one signal time step."""
    client: Client = ctx.exchange[0]

    if datas is None or datas.empty:
        return

    for _, row in datas.iterrows():
        symbol = row["symbol"]
        prediction = float(row.get("prediction", 0.0))

        if prediction >= ctx.open_threshold:
            order_id = client.target_percent(
                symbol, ctx.max_position, threshold=0.05, auto_partial=True
            )
            ctx.log.info(
                f"Open/rebalance: {symbol}, target={ctx.max_position}, order_id={order_id}"
            )
        elif abs(prediction) <= ctx.close_threshold:
            order_id = client.target_percent(symbol, 0)
            ctx.log.info(f"Close: {symbol}, order_id={order_id}")
        else:
            ctx.log.detail(f"Hold: {symbol}, prediction={prediction:.4f}")


def handle_tick(ctx: UserContext):
    """Observe prices on each tick. Optional."""
    client: Client = ctx.exchange[0]
    symbol = client.symbol_list[0] if client.symbol_list else "BTCUSDT"
    price = client.get_price(symbol)
    ctx.log.detail(f"Tick: {symbol} price={price}")

5. Symbol naming conventions

Market typeFormatExamples
SpotBASEUSDTBTCUSDT, ETHUSDT
UM (USDT-margined futures)BASE_USDTBTC_USDT, ETH_USDT
CM (coin-margined futures)BASE_USDBTC_USD, ETH_USD
Python field names use snake_case, such as account_id. JSON serialization converts them to camelCase, such as accountID. All data objects provide to_dict() and from_dict() methods.
    BeeQuant - AI Quantitative Trading Platform