Python SDK
The openbacktest package — candles as DataFrames, sessions as objects.
The openbacktest package wraps the REST API in a pythonic client:
candles arrive as pandas DataFrames, sessions are stateful objects with
buy/sell/close, and statistics come back computed by the same engine
as the app.
The client uses the public API for the current release by default. Set
OPENBACKTEST_BASE_URL to target another environment, such as a local server.
Install
The SDK lives in the repository under sdk/python (PyPI publication
planned):
python -m venv .venv
.venv\Scripts\Activate.ps1 # Windows — use source .venv/bin/activate elsewhere
pip install -e "sdk/python[dev]"Quickstart
import os
from openbacktest import OpenBacktest
client = OpenBacktest(
api_key=os.environ["OPENBACKTEST_API_KEY"],
)
print(client.me()) # sanity check: key + Pro entitlement
# Candles as a DataFrame (UTC datetime index, OHLCV columns)
candles = client.get_candles("BTCUSDT", "1h", count=1500)
# Continuous Binance USD-M current-quarter candles
futures = client.get_candles(
"BTCUSDT",
"1h",
count=1500,
feed="binance-usdm-current-quarter",
)
print(candles.tail())
# Project + session
project = client.create_project("SMA cross", "BTCUSDT", "1h")
session = client.create_session(
project.id, "run 1", initial_balance=10_000,
fees={"entryFee": 0.1, "exitFee": 0.1, "type": "percent"},
)
# Trade: open with buy()/sell(), close with close().
session.buy(qty=0.1, price=60_000, time=candles.index[100])
session.close(price=61_000, time=candles.index[110])
stats = session.finish(break_even_threshold=2.5)
print(stats.winrate, stats.pl_net, stats.max_drawdown)To run a blind, reproducible random replay, pass a candidate period plus the
duration and seed. The returned SessionInfo exposes both the exact selected
window and the frozen account timezone:
session = client.create_session(
project.id,
"blind random run",
initial_balance=10_000,
range_start=1704067200000,
range_end=1767225600000,
replay_randomization={"seed": 42, "durationMs": 7 * 86_400_000},
blind_mode=True,
smooth_candles=False,
)
print(session.info.range_start, session.info.range_end)
print(session.info.random_seed, session.info.account_timezone)Session lifecycle
buy(qty, price, time, stop_loss=None, take_profit=None, note=None)/sell(...)open a long/short position — one open position at a time.close(price, time)closes it into a trade record, buffered locally and flushed to the API in batches of up to 500 (flush()to force).finish(break_even_threshold=0)flushes, marks the session finished (idempotent) and returns the stats.stats(break_even_threshold=0)reads or recalculates them with the same account-currency break-even band.- Finished-session stats include
ideal_r_analysis: seven-day Ideal Average/Max RR, per-trade data coverage, and “could have profit/BE” at the strict 1.2R threshold. It staysnot-finalwhile the session is active so post-exit prices cannot leak into replay. - The session then appears in the web app, tagged
api/sdk, with the same charts and statistics as a manual replay.
Errors
All API failures raise typed exceptions from openbacktest.errors:
AuthenticationError (401), ProRequiredError (403), NotFoundError
(404), SessionNotActiveError (409), ValidationError (400),
RateLimitError (429, exposes retry_after seconds — GET requests are
retried automatically up to 3 times), ServerError (5xx).