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.
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 |
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:
BrokerA 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
Noneif 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
Noneif no position exists.- Return type:
Optional[Order]