Skip to main content

Open Binancian Futures

Python License

A Python framework for creating, backtesting, and deploying automated trading bots on Binance USDⓈ-M Futures.

Features

  • Live Trading – Monitor multiple symbols and execute trades automatically
  • Backtesting – Run deterministic backtests on Binance Vision archives or injected historical data
  • Webhooks – Real-time notifications via Slack/Discord

Prerequisites

  • Python 3.12+
  • Binance API keys with Enable Futures permission for live trading (Get keys)

Getting Started

1. Install the package

pip install open-binancian-futures

The core install supports live trading, backtesting and Discord notifications. Install extras for the features your strategy uses:

pip install 'open-binancian-futures[ai]'         # AI helpers, TOON and token utilities
pip install 'open-binancian-futures[indicators]' # pandas-ta and TA-Lib
pip install 'open-binancian-futures[slack]'       # Slack notifications
pip install 'open-binancian-futures[ai,indicators,slack]' # previous full dependency set

Existing strategies importing these libraries must install the corresponding extras after upgrading. The example strategy below requires [indicators].

2. Create a .env file (see .env.example)

Variable Required Default Description
API_KEY Yes* - Binance API key (mainnet)
API_SECRET Yes* - Binance API secret (mainnet)
SYMBOLS No BTCUSDT comma-separated list of symbols to trade
INTERVALS No 1d Comma-separated candle intervals (1m, 5m, 1h, ...). First entry is the primary interval
LEVERAGE No 1 Leverage multiplier (1 ~ 125)
SIZE No 0.05 Trade size per order (e.g., 0.05 = 5% of balance)

* For testnet, use API_KEY_TEST and API_SECRET_TEST instead

View All Configuration Options
Variable Type Default Description
IS_TESTNET bool false Use testnet (true/false)
GTD_NLINES number - Candles to hold open orders (GTC if not set)
TIMEZONE string UTC Timezone (e.g., Asia/Seoul)
WEBHOOK_URL string - Slack/Discord webhook for notifications
Backtesting
IS_BACKTEST bool false Enable backtest mode
BALANCE number 100 Initial backtest balance
INDICATOR_INIT_SIZE number 200 Candles for indicator warm-up
BACKTEST_START_DATE string - Inclusive UTC start date for Vision backtests
BACKTEST_END_DATE string - Inclusive UTC end date for Vision backtests
BACKTEST_DATA_DIR path cache Binance Vision ZIP archive cache directory

3. Create your strategy

Extend the Strategy class and implement load(), run(), and run_backtest() functions:

  • load(DataFrame): Loads technical indicators you want to use
  • run(str, str): Executes your trading logic
  • run_backtest(str, str, int): Backtesting logic (optional)
Example Strategy
import asyncio
import pandas_ta as ta

from binance_sdk_derivatives_trading_usds_futures.rest_api.models import (
    NewOrderSideEnum,
    NewOrderTimeInForceEnum,
)
from open_binancian_futures.types import OrderType
from open_binancian_futures.strategy import Strategy
from open_binancian_futures.constants import settings
from open_binancian_futures.utils import fetch
from pandas import DataFrame
from typing import cast, override

class MyStrategy(Strategy):

    @override
    def load(self, df: DataFrame) -> DataFrame:
        """Add technical indicators to the dataframe"""
        # You can use `pandas_ta` to add technical indicators
        df["RSI_14"] = ta.rsi(df["Close"], length=14)
        return df

    @override
    async def run(self, symbol: str, interval: str) -> None:
        """Execute your trading logic"""
        latest = self.indicators[symbol][interval].iloc[-1] # Access to the latest candle
        entry_price = latest["Close"]

        if latest["RSI_14"] < 30:
            async with cast(asyncio.Lock, self.lock):
                if entry_quantity := self.exchange_info.to_entry_quantity(
                    symbol=symbol,
                    entry_price=entry_price,
                    balance=self.balance,
                ):
                    fetch(
                        self.client.rest_api.new_order,
                        symbol=symbol,
                        side=NewOrderSideEnum.BUY,
                        type=OrderType.LIMIT.value,
                        price=float(entry_price),
                        quantity=float(entry_quantity),
                        time_in_force=NewOrderTimeInForceEnum.GTC,
                    )

    @override
    async def run_backtest(self, symbol: str, interval: str, index: int) -> None:
        """Backtesting logic (optional)"""
        ...

4. Deterministic backtesting

The package backtester accepts a DataFrame, a CSV/Parquet path, or a custom HistoricalDataSource. The input must contain Open_time, Open, High, Low, and Close; add Symbol when more than one symbol is present. Numeric Open_time values follow Binance's epoch-millisecond convention.

from open_binancian_futures import (
    BacktestConfig,
    Backtesting,
    DataFrameDataSource,
    MarketExecutionPolicy,
    OrderType,
    PositionSide,
)

runner = Backtesting(
    strategy=my_strategy,
    data_source=DataFrameDataSource(candles, interval="1h"),
    config=BacktestConfig(
        initial_balance=100.0,
        leverage=1,
        warmup_bars=0,
        interval="1h",
        market_execution=MarketExecutionPolicy.NEXT_OPEN,
    ),
)
result = runner.run()

print(result.summary.format())
print(result.summary.trades)
print(result.equity_curve)

Backtesting.run() returns the BacktestRunResult; existing callers that only use the side effects can continue to ignore the return value.

CsvDataSource(path, symbol="ETHUSDT", interval="1h") and ParquetDataSource(...) provide the file-backed equivalents. Injected data does not create a Binance client or make a network request. The default Backtesting() path requires BACKTEST_START_DATE and BACKTEST_END_DATE and loads candles from Binance Vision public archives without creating an authenticated Binance client. Backtest strategies should use the framework order helpers; live REST operations require an explicitly supplied client. When BacktestConfig.interval is omitted, a direct DataFrame/CSV/Parquet source uses its declared interval; otherwise the configured interval takes precedence. Every symbol must expose that selected interval; inconsistent symbol-specific interval keys are rejected instead of being relabeled.

BinanceVisionDataSource resolves monthly USDⓈ-M kline ZIP files first and falls back to daily files when a monthly archive is unavailable. Archives are cached locally and are never silently replaced by REST candle data. The date-only end_date/--end-date includes the entire UTC calendar day. The INDICATOR_INIT_SIZE setting is loaded as warm-up context before the requested start date, so the requested dates describe the evaluated period rather than being consumed by indicator initialization. The old BinanceHistoricalDataSource remains available only as an explicit compatibility source for callers migrating from the previous engine. When an execution interval is explicitly configured, the source must provide that interval; the runner raises instead of evaluating another interval under the wrong label.

The default engine evaluates completed candles in UTC chronological order. Existing orders are eligible on the current candle, while newly created LIMIT, STOP, TAKE_PROFIT, and TAKE_PROFIT_MARKET orders wait until the next candle. A newly created MARKET order fills at the next available evaluation candle open by default (MarketExecutionPolicy.NEXT_OPEN). MarketExecutionPolicy.CLOSE explicitly enables same-close market fills. Limit and STOP_MARKET gaps fill at the candle open; a STOP_LIMIT gaps remain pending until their limit can execute, while the triggered limit remains active across later candles. Intrabar triggers fill at the configured price, and Stop Loss wins over Take Profit when both are reached. Multiple crossed partial exits are processed in that same deterministic priority order. Costs, slippage, and funding are zero by default. OHLC data cannot reveal the order of prices within a candle, so these priority and gap rules are modeling assumptions, not tick-level fills. Open positions are realized at each symbol's final evaluated close with Trade.exit_reason == "end_of_backtest". Last-bar next-open market orders remain unfilled and are canceled with their reserved margin released. Partial exit orders close only their requested quantity. A custom CostModel is applied to both entry and exit fills.

The returned BacktestRunResult exposes by_symbol, summary, equity_curve, and final_balance. Metrics use each symbol's actual evaluated-bar count, classify zero PNL as break-even, and keep the loss sign negative in expectancy calculations.

For strategy code that should work without Binance SDK enums, use the domain adapter:

await self.submit_order(
    self.order_intent(
        "ETHUSDT", PositionSide.BUY, OrderType.LIMIT,
        price=99.0, quantity=1.0,
    )
)

OrderIntent supports managed live TRAILING_STOP_MARKET orders with activation_price and callback_rate. With a managed gateway, replace synchronous set_trailing_stop(...) calls with await submit_order(...); see managed helper migration. The backtest gateway does not implement these extended trailing-stop and close-position intents. Managed market orders use an explicit reference price or the runtime’s latest indicator close for sizing.

Existing run_backtest(symbol, interval, index) implementations and direct OrderList.open_order(...) calls remain supported. The latter are discovered by the runner after each callback; new non-market orders still follow the same-candle deferral rule. Strategy.open_order(...) remains available and routes through the managed gateway when one is configured.

Migration: completed data and next-open execution

The market default changed from CLOSE to NEXT_OPEN. A signal at a close of 100 followed by an open of 110 now enters at 110. To reproduce the former market-price assumption, pass BacktestConfig(market_execution=MarketExecutionPolicy.CLOSE). This setting does not restore the former callback-before-fill ordering.

Existing orders expire and fill for all symbols before close callbacks start. Close-time cancellation cannot undo a fill earlier in that candle. Callbacks run in sorted symbol order, giving reproducible shared-balance priority. Entry-fill hooks run after this accounting phase, see only data completed before that candle, and their new orders wait for a later candle.

Every strategy data view is a fresh copy containing only completed candles across all symbols and intervals. The engine uses Close_time when supplied; otherwise it infers completion from the interval, including calendar months for 1M. Constructors receive only the warm-up prefix. Custom load() is recomputed on each bounded view; it must handle empty frames and should be free of order submissions and other side effects. This correctness-first approach can cost more time than computing indicators once over all data. Keep timestamps and rows intact when adding indicator columns.

Replace full-history preprocessing or indexing beyond the current bar with calculations over the supplied prefix:

def load(self, df):
    return df.assign(mean_close=df["Close"].rolling(20).mean())

async def run_backtest(self, symbol, interval, index):
    visible = self.indicators[symbol][interval]
    current = visible.iloc[index]  # index == len(visible) - 1
    hourly = self.indicators[symbol]["1h"]
    if hourly.empty:  # no completed hourly candle yet
        return
    # Make decisions from current and hourly.iloc[-1].

Plain run_backtest(symbol, index) callbacks remain supported. Strategy or indicator exceptions fail the run; the CLI exits with a nonzero status.

5. Running

open-binancian-futures my_strategy.py

You can override environment variables from the command line:

open-binancian-futures --backtest \
  --symbols ETHUSDT --intervals 1h,4h \
  --start-date 2024-01-01 --end-date 2024-03-31 \
  --data-dir .cache/binance-vision \
  my_strategy.py

--backtest and --live remain the mode switches. In a Vision backtest, the first value in --intervals is the execution interval and the remaining values are loaded as indicator context. Live trading uses the supervised managed runtime described below.

Opt-in backtest indicator reuse

This optimization requires pandas 2.2.3 or newer.

By default load() is called for every prepared strategy view, preserving strategies that depend on account state or side effects. If load() is a pure function of its input and indicator settings, override:

def backtest_indicator_cache_key(self):
    return (self.period, self.multiplier)

Return an immutable hashable key containing every setting that affects load(); return None to disable reuse. Include a revision in the key when other required calculation state changes. Do not opt in for account-dependent or side-effecting loads. Inputs are compared by content, index and dtype, so an equal row count or last timestamp alone never establishes reuse. One raw input and computed output per symbol/interval are retained, and caches reset for each runner/run. Each callback receives an independent DataFrame copy so mutations cannot poison cached numeric indicator columns. Opted-in outputs must not contain mutable nested Python objects, which pandas deep copies do not recursively isolate.

Completed-candle boundaries, callback/fill ordering and hook-time visibility remain unchanged. No indicators are computed on future rows. Tables are formatted only when INFO logging is enabled. Run python benchmarks/backtest_indicator_cache.py for a fixed four-symbol, 120-bar, three-repeat comparison with load counts, elapsed time, traced memory peaks and exact ledger/equity/final-balance equality checks.

License

MIT License - see LICENSE for details.

Disclaimer

USE AT YOUR OWN RISK.

The author and contributors are not responsible for any financial losses or damages arising from the use of this software. Cryptocurrency trading involves significant risk. Always test thoroughly and trade responsibly.

Managed live recovery

Live trading now starts through a supervised runtime with a durable SQLite order journal. Keep .obf-runtime/orders.sqlite3 across restarts, or set OBF_RUNTIME_PATH / LiveTrading(journal_path=...) to a stable local path. Startup adopts existing target-symbol orders and positions; hedge mode is rejected before changes. Normal shutdown preserves exchange orders and positions.

Unknown placement outcomes hold the affected symbol and are queried by the original client order ID instead of resent. Connection recovery restores account state and missing closed candles before strategy decisions resume. Strategy errors require a fresh runtime and cannot be cleared by reconnecting.

See live operations, scope and testnet checklist and adapter injection / managed helper migration.

Backtest order support

Backtests support market, limit, stop and take-profit orders with explicit quantities or entry sizing, and GTC/GTD expiry. Unsupported intents raise ValueError before registering an order or reserving margin: close_position, trailing stops, liquidation, IOC/FOK and trailing-stop fields. For backtest exits, submit reduce_only=True with an explicit quantity. Live close_position and trailing-stop support remains available through the managed gateway.

Metadata

Release files for open-binancian-futures 26.10.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for open-binancian-futures 26.10.2
File Size Uploaded Provenance Actions
open_binancian_futures-26.10.2.tar.gz 138.5 kB With provenance Details for open_binancian_futures-26.10.2.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for open-binancian-futures 26.10.2
File Interpreter ABI Platform Actions
open_binancian_futures-26.10.2-py3-none-any.whl Python 3 none any Details for open_binancian_futures-26.10.2-py3-none-any.whl

Total release size: 300.3 kB

Release files / open_binancian_futures-26.10.2.tar.gz

Download URL open_binancian_futures-26.10.2.tar.gz
Size 138.5 kB
Tags Source
SHA-256 checksum
How to use checksums
ca9d6dbe7e690da15c75985b92a98e02589cd833a23964b20d914786913ee7a3
BLAKE2b-256 checksum
How to use checksums
5744a4fcbda602de9bf06a0ff375610f9d1d7fc94ff7382472d15ad5d827a00c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 6, 2026.

Transparency log

Release files / open_binancian_futures-26.10.2-py3-none-any.whl

Download URL open_binancian_futures-26.10.2-py3-none-any.whl
Size 161.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
47cd77df3fd9be495015e0f8015e23e43b5d9ed1c5eef7a12dba66377f9780fc
BLAKE2b-256 checksum
How to use checksums
4ce16a9510b9fbaf01b185806137b7afbddb11f3f8a4c22662b53e68c6248f39
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 6, 2026.

Transparency log

Security for open-binancian-futures 26.10.2

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for open_binancian_futures-26.10.2.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 6, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page