Bitunix API Perpetual Futures Trading with LumiBot

How to Use Bitunix

Bitunix integration in Lumibot supports only perpetual futures trading. Spot trading is not supported.

Bitunix support at a glance

Capability

Status

Requirement

USDT perpetual futures

Supported

Fund the Futures wallet with USDT

Spot trading

Not supported

Use another broker integration

Hedge-mode positions

Required

The account must confirm HEDGE mode

Historical futures bars

Supported

Use a native interval and available exchange history

Account Funding and Cash Calculation:

  • You must transfer funds to the Futures section of your Bitunix account. Money in the spot wallet will not be available for trading.

  • For accurate calculation of available cash, it is strongly recommended to deposit USDT into your Bitunix Futures account. If you deposit crypto (e.g., BTC), it will not register as available cash for order sizing, though it can still be used as margin by Bitunix.

Environment Variables

Set the following environment variables in your .env file or system environment:

BITUNIX_API_KEY=your_bitunix_api_key
BITUNIX_API_SECRET=your_bitunix_api_secret

Position Refresh Failures

Position reads require a complete successful response. A transport error, rejected request, or malformed position raises LumibotBrokerAPIError and leaves tracked positions unchanged. A failed read does not mean the account is flat and is not cached as a successful refresh; a later read can retry. An explicitly successful empty snapshot removes all stale non-cash positions. Concurrent polling and strategy reads preserve the latest successfully applied request: an older response cannot remove, resurrect, or overwrite its positions. Failed reads remain retryable and do not discard another successful response. Positions added locally during a pending read retain their fields and ownership until the next fresh snapshot. Polling reports the failure and retries on its next cycle. Strategy code using fresh get_position() or get_positions() reads should allow the error to stop that decision, rather than treating it as permission to open a position.

The tracker supports one active position per symbol. Multiple nonzero rows for the same symbol, including simultaneous long and short HEDGE positions, raise the same error and preserve tracked state. They cannot be represented as independent positions by this adapter. Zero-quantity rows are ignored.

Setting Leverage for Bitunix Orders

Specify leverage in the CRYPTO_FUTURE Asset constructor or set its leverage attribute before creating an order. The constructor preserves the requested leverage; its default is 1. LumiBot requests that leverage from Bitunix before submitting an opening order. Reduce-only orders, including full and fractional close_position calls, preserve the existing exchange leverage without requesting a leverage change. This also applies after a restart when the local leverage cache is empty. If the exchange rejects an opening leverage change, LumiBot logs a warning; the Asset value does not confirm the exchange’s actual leverage.

Example: Setting Leverage on a Bitunix Futures Order

from lumibot.entities import Asset, Order

asset = Asset("HBARUSDT", Asset.AssetType.CRYPTO_FUTURE, leverage=10)
order = self.create_order(
    asset=asset,
    quantity=100,
    side=Order.OrderSide.BUY,
    order_type=Order.OrderType.LIMIT,
    limit_price=0.18
)
submitted_order = self.submit_order(order)
if submitted_order:
    self.log_message(f"Placed order: ID={submitted_order.identifier}, Status={submitted_order.status}")

Order Precision and Position Mode

LumiBot loads and caches Bitunix trading-pair rules for each symbol during the broker session. Quantities round down to basePrecision decimal places; limit, take-profit, and stop-loss prices round down to quotePrecision. All quantity and price fields are sent as decimal strings. For example, with BTCUSDT rules of basePrecision=4 and minTradeVolume=0.0001, a requested quantity of 0.008868641 becomes "0.0088". The tracked order quantity uses this executable size. Rounding down can leave a small residual position after a partial close.

Quantities below minTradeVolume after rounding return an order with ERROR status without placing an exchange order. Missing or invalid pair rules also block submission; failed lookups are retried on the next order.

The adapter requires confirmed HEDGE mode before submitting. If mode initialization fails or reports ONE_WAY, the order receives a clear error and is not sent. Check the account mode and outstanding positions/orders before retrying: Bitunix can reject mode changes while positions or orders exist. Opens send tradeSide="OPEN". Reduce-only closes send tradeSide="CLOSE" with the matching exchange position ID and hedge side. An absent or ambiguous matching position blocks the close.

See the Bitunix place-order contract and trading-pair rules.

Historical Bars

Bitunix serves native crypto-futures intervals including 1m, 15m, 1h, 2h, 4h, and 1d. LumiBot requests a native interval when it matches the strategy timeframe instead of downloading one-minute bars and resampling them locally.

The Bitunix futures API limits each kline response to 200 candles. LumiBot automatically paginates timestamp-bounded windows when length is greater than 200. If the symbol does not have enough exchange history to satisfy the request, get_historical_prices raises a clear error with the returned and requested counts instead of silently returning a short frame.

Example Usage

Below are practical examples using the Bitunix broker in Lumibot, based on the bitunix_futures_example.py strategy.

Placing a Limit Order for a Futures Contract

from lumibot.entities import Asset, Order

asset = Asset("HBARUSDT", Asset.AssetType.CRYPTO_FUTURE)
asset.leverage = 5  # Example: set leverage to 5x
order = self.create_order(
    asset=asset,
    quantity=100,
    side=Order.OrderSide.BUY,
    order_type=Order.OrderType.LIMIT,
    limit_price=0.18
)
submitted_order = self.submit_order(order)
if submitted_order:
    self.log_message(f"Placed order: ID={submitted_order.identifier}, Status={submitted_order.status}")

Closing a Position

# Wait for a few seconds if needed
import time
time.sleep(10)
self.close_position(asset)

close_position uses reduce-only semantics. Partial closes are supported by passing fraction between 0 and 1, for example self.close_position(asset, fraction=0.5).

Cancelling Open Orders

orders = self.get_orders()
for order in orders:
    if order.asset.symbol == "HBARUSDT" and order.asset.asset_type == Asset.AssetType.CRYPTO_FUTURE and order.status in [
        Order.OrderStatus.NEW, Order.OrderStatus.SUBMITTED, Order.OrderStatus.OPEN, Order.OrderStatus.PARTIALLY_FILLED
    ]:
        self.cancel_order(order)
        self.log_message(f"Order {order.identifier} cancellation submitted.")

Checking Available Cash

cash = self.get_cash()
self.log_message(f"Current cash {cash}")

Note

For best results, ensure all funds in your Bitunix Futures account are in USDT. Crypto balances may not be counted as available cash for order sizing.

Documentation

class lumibot.brokers.bitunix.Bitunix(config, max_workers: int = 1, chunk_size: int = 100, connect_stream: bool = True, poll_interval: float | None = None, data_source=None)

Bases: Broker

A broker class that connects to the Bitunix exchange for crypto futures trading.

This broker uses Bitunix’s perpetual futures REST API to submit, track, and close crypto futures positions (e.g., BTCUSDT perpetual).

Key Features: - Only supports crypto futures (TRADING_MODE must be “FUTURES”). - Closes futures positions with reduce-only market orders. - All positions and orders are managed using Bitunix’s API conventions. - Not suitable for spot trading or non-futures assets.

Notes: - The close_position method submits a reduce-only HEDGE close for the matching position. - All asset symbols should be the full Bitunix symbol (e.g., “BTCUSDT”). - Leverage and margin settings are managed per-symbol as needed.

ASSET_TYPE_MAP = {'crypto': ['crypto'], 'crypto_future': ['future'], 'forex': [], 'future': ['future'], 'option': [], 'stock': []}
DEFAULT_POLL_INTERVAL = 5
LUMIBOT_DEFAULT_QUOTE_ASSET = None
POLL_EVENT = 'poll'
cancel_order(order: Order)

Cancels a FUTURES order.

close_position(strategy_name: str, asset: Asset, fraction: float = 1.0)

Close all or part of an existing position using a reduce‑only market order (tradeSide=”CLOSE”).

Parameters:
  • strategy_name (str) – Name of the strategy that owns the position.

  • asset (Asset) – The asset whose position should be closed.

  • fraction (float, optional) – Fraction of the position to close (0 < fraction ≤ 1). Defaults to 1 (full close).

Returns:

The submitted order, or None if no position exists.

Return type:

Optional[Order]

do_polling()

Polls Bitunix for order status updates and dispatches events.

get_historical_account_value(start_date=None, end_date=None, frequency=None) dict

Not implemented: Bitunix does not support historical account value retrieval.

get_quote_asset()
get_time_to_close()

Return the remaining time for the market to close in seconds

get_time_to_open()

Return the remaining time for the market to open in seconds

get_timestamp()
is_market_open()

Determines if the market is open.

Parameters:

None

Returns:

True if market is open, false if the market is closed.

Return type:

boolean

Examples

>>> self.is_market_open()
True
sell_all(strategy_name, cancel_open_orders: bool = True, strategy=None, is_multileg: bool = False)

Override sell_all to use flash_close_position for futures.

ws_url

Private websocket endpoint for authenticated Bitunix futures streams.

Bitunix.get_time_to_close()

Return the remaining time for the market to close in seconds

Bitunix.get_time_to_open()

Return the remaining time for the market to open in seconds

Bitunix.get_timestamp()
Bitunix.is_market_open()

Determines if the market is open.

Parameters:

None

Returns:

True if market is open, false if the market is closed.

Return type:

boolean

Examples

>>> self.is_market_open()
True
Bitunix.close_position(strategy_name: str, asset: Asset, fraction: float = 1.0)

Close all or part of an existing position using a reduce‑only market order (tradeSide=”CLOSE”).

Parameters:
  • strategy_name (str) – Name of the strategy that owns the position.

  • asset (Asset) – The asset whose position should be closed.

  • fraction (float, optional) – Fraction of the position to close (0 < fraction ≤ 1). Defaults to 1 (full close).

Returns:

The submitted order, or None if no position exists.

Return type:

Optional[Order]