Skip to main content
Pre-release

This release is a pre-release and may not be stable for production use.

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

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.

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.

Release files for open-binancian-futures 26.3.0rc2

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.3.0rc2
File Size Uploaded
open_binancian_futures-26.3.0rc2.tar.gz 99.9 kB Details

Built distribution (wheel)

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

Total release size: 214.9 kB

Release files / open_binancian_futures-26.3.0rc2.tar.gz

Download URL open_binancian_futures-26.3.0rc2.tar.gz
Size 99.9 kB
Tags Source
SHA-256 checksum
How to use checksums
d6dee0884616ad6145070a07343d236cfe19c643ceb87588fd747014cfd9b2b3
BLAKE2b-256 checksum
How to use checksums
738ac12ef9f09b59be156eebc66a35ad473efb593bda5356c309f9f98b4844fc
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 Sep 26, 2026.

Transparency log

Release files / open_binancian_futures-26.3.0rc2-py3-none-any.whl

Download URL open_binancian_futures-26.3.0rc2-py3-none-any.whl
Size 115.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
66cab1e225a8c903af8448486eb173cbe6bf5485ce90c8ee4d4c2785e5318944
BLAKE2b-256 checksum
How to use checksums
5d4b7b537873f2b5f9cb635e0cc3b1fe38fb1e658add1ab6021f7999cdd42166
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 Sep 26, 2026.

Transparency log
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