Skip to main content

Official Python client for the Backtest360 API

Project description

backtest360

PyPI version Python versions License: MIT tests

Official Python client for the Backtest360 API.

Run backtests, automate, integrate with your research or trading workflows. The client handles authentication, serialization, and error mapping so you can call a single method instead of building and parsing the raw HTTP requests yourself.

import matplotlib.pyplot as plt
import yfinance as yf
from backtest360 import Client, Strategy

df = yf.download("BTC-USD", period="1y", interval="1d",
                 auto_adjust=False, multi_level_index=False, progress=False)
df.columns = df.columns.str.lower()

result = Client(api_key="b360_...").backtest(Strategy.rsi_threshold_long(), df)
result.summary()
result.strategy_equity.plot(title="Equity curve")
plt.show()

Save this snippet as quickstart.py, drop in your API key, and run it with python quickstart.py (install the extras if needed: pip install matplotlib yfinance).


Install

pip install backtest360

Requires Python 3.9+. The only runtime dependencies are httpx and pandas.

Need to install Python first? (Windows / macOS / Linux / WSL)

Windows (native)

  1. Install Python from python.org/downloads (check "Add to PATH"), or via winget:
    winget install Python.Python.3.12
    
  2. Open PowerShell and verify:
    python --version
    
  3. Install the client and yfinance for the quickstart:
    pip install backtest360 yfinance
    
  4. Run a script:
    python quickstart.py
    

Windows via WSL (recommended for quant work)

  1. Install WSL:
    wsl --install
    
    Restart, then open the Ubuntu terminal.
  2. Install Python:
    sudo apt update && sudo apt install python3 python3-pip -y
    
  3. Install the client:
    pip3 install backtest360 yfinance
    
  4. Run a script:
    python3 quickstart.py
    

macOS

# via Homebrew (recommended)
brew install python

# or download from python.org/downloads

Then:

pip3 install backtest360 yfinance
python3 quickstart.py

Linux

sudo apt install python3 python3-pip -y   # Debian/Ubuntu
pip3 install backtest360 yfinance
python3 quickstart.py

Get an API key

Sign up at backtest360.com and copy your key. Store it in the BACKTEST360_API_KEY environment variable or pass it directly:

client = Client(api_key="b360_...")
# or: export BACKTEST360_API_KEY=b360_...
client = Client()

The engine URL can be overridden with the optional BACKTEST360_ENGINE_URL environment variable, read when the Client is constructed. An explicit base_url= argument takes precedence over the environment variable, which in turn takes precedence over the default:

export BACKTEST360_ENGINE_URL=https://api.backtest360.com

Features

  • Synchronous client — straightforward to use in scripts, notebooks, and pipelines
  • Hand-written wrapper over the public REST API — no generated code, no schema sync
  • Built-in strategy templates (Strategy.rsi_threshold_long(), Strategy.ma_crossover(), …)
  • Grouped-knob classes: Execution, Costs, Risk, Sizing, MarketHours, Settings — set only what you need
  • Pre-computed signals path: client.backtest_signals(series, df) for model-generated signals
  • Pandas-native — pass a DataFrame, get pandas Series back (result.strategy_equity, result.returns)
  • Built-in sample data served by the engine — examples run without external data feeds (client.sample_data("BTC"))
  • Chart-annotation markers and data-quality report on every result (result.markers, result.data_quality)
  • Engine introspection: client.version() for version compatibility checks, client.me() for your key's scopes/limits/usage
  • Strategy templates: client.list_templates() to discover ready-to-run predesigned strategies
  • Raw-API escape hatch for full control (client.backtest_raw({...}))
  • Strict type hints + py.typed — first-class IDE and mypy support
  • MIT licensed

Common patterns

Custom strategy

from backtest360 import Client, Strategy, Execution, Costs, Risk, Sizing, Settings
import yfinance as yf

df = yf.download("SPY", start="2020-01-01", end="2024-01-01", interval="1d",
                 auto_adjust=False, multi_level_index=False, progress=False)
df.columns = df.columns.str.lower()

strat = Strategy(
    name="rsi_mean_reversion",
    long_entry="(rsi_14 > 30) & (rsi_14 < 50)",
    long_exit="rsi_14 >= 50",
    indicators=[Strategy.indicator("rsi", ref="rsi_14", period=14)],
)

result = Client(api_key="b360_...").backtest(
    strat, df,
    execution=Execution(entry="open", exit="close", signal_frequency="daily"),
    costs=Costs(slippage_bps=2.5, fee_pct=0.001),
    risk=Risk(stop="atr", value=2.5, atr_period=14, max_drawdown=0.25),
    sizing=Sizing(weight=1.0, vol_target=0.15, leverage_limit=2.0),
    settings=Settings(risk_free_rate=0.04),
)

result.summary()
print("Max Drawdown:", result.stats.get("max_drawdown", "n/a"))
for t in result.trades[:5]:
    print(t["entry_date"], t["direction"], t["return_net"])

Indicator library (names, params, output columns): https://api.backtest360.com/docs

Strategy templates: see the Strategy.<name>() classmethods (e.g. Strategy.rsi_threshold_long()).

Built-in sample data

No data feed handy? The engine serves a small set of ready-made daily OHLCV datasets, so you can run a backtest with no external dependency:

from backtest360 import Client, Strategy

client = Client(api_key="b360_...")
print(client.sample_symbols())     # ['SPY', 'QQQ', 'BTC']
df = client.sample_data("BTC")     # DatetimeIndex + lowercase OHLCV — drop-in for backtest()
result = client.backtest(Strategy.rsi_threshold_long(), df)

Pre-computed signals

import pandas as pd
from backtest360 import Client

# Any signal series of {-1, 0, 1} — your ML model, custom indicator, etc.
signals = pd.Series(..., index=df.index)

result = Client(api_key="b360_...").backtest_signals(signals, df)
print(result.stats["sharpe"])

Raw API escape hatch

For users who want exact control with the API docs open:

resp = Client(api_key="...").backtest_raw({
    "run": {"stats_keys": "ids"},
    "legs": [
        {
            "id":          "main",
            "strategy":    {"condition_tree": {...}, "indicators": [...]},
            "data_source": {"ohlcv": {...}},
            "execution":   {"signal_frequency": "daily"},
        },
    ],
})
result = resp["legs"][0]["result"]

Latest signal

Ask the engine for the target position on the most-recent bar — the live-trading hook:

from backtest360 import Client, Strategy

signal = Client(api_key="b360_...").latest_signal(Strategy.rsi_threshold_long(), df)
position = {1: "LONG", 0: "FLAT", -1: "SHORT"}[signal["signal"]]
print(position, signal["long_entry_fired"])

Validate a strategy

Check that a strategy is valid without running a backtest:

from backtest360 import Client, Strategy

v = Client(api_key="b360_...").validate_strategy(Strategy.rsi_threshold_long())
print(v["valid"], v.get("errors", []))

Discover indicators

from backtest360 import Client

client = Client(api_key="b360_...")
print([i["name"] for i in client.list_indicators()])

Discover strategy templates

Browse the predesigned templates available to your key, then fetch one in full and run it:

from backtest360 import Client

client = Client(api_key="b360_...")
for t in client.list_templates():                     # compact catalog
    print(t["id"], "-", t["description"])

strat = client.list_templates(name="rsi_mean_reversion")   # one full definition
df = client.sample_data("SPY")
resp = client.backtest_raw({
    "run": {"stats_keys": "ids"},
    "legs": [{"id": "main", "strategy": strat, "data_source": {"ohlcv": ...}}],
})
result = resp["legs"][0]["result"]

Inspect your API key

See your key's scopes, rate limits, and current usage up front — so you can size requests before hitting a limit:

from backtest360 import Client

info = Client(api_key="b360_...").me()
print(info["scopes"])                       # ['backtest.run', 'meta.read', ...]
print(info["limits"]["rpm"], "req/min")
print(info["usage"]["day"]["remaining"], "requests left today")

Error handling

from backtest360 import Backtest360Error

try:
    result = client.backtest(strategy, df)
except Backtest360Error as e:
    if e.status == 401:
        print("Invalid or expired API key — renew at backtest360.com")
    elif e.status in (429, 503):
        # Rate limited or the engine is at capacity — retry with backoff.
        # e.retry_after carries the Retry-After header (seconds) when set.
        print(f"Busy — retry in {e.retry_after or 5:.0f}s")
    elif e.status == 504:
        print("Run exceeded the compute time limit — reduce the date range "
              "or strategy complexity")
    elif e.status == 422:
        detail = e.body.get("detail") if isinstance(e.body, dict) else e.body
        print("Strategy validation failed:", detail)
    else:
        raise   # unexpected — let it propagate

On error responses, e.request_id carries the response's X-Request-ID — quote it when reporting an issue. You can also pass your own correlation id to any method: client.backtest(strategy, df, request_id="my-run-42").


Versioning

MAJOR.MINOR.PATCH. Pre-1.0 (0.x.y): the API may move between minor versions. Pre-release suffixes: aN (alpha), bN (beta), rcN (release candidate). See CHANGELOG.md for the release history.


Full documentation

Questions / feedback

Questions or feedback? hello@backtest360.com — we read everything. The client is in active development, so help shape it.

Bug reports and feature requests: open an issue on GitHub.

License

MIT — see LICENSE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

backtest360-0.7.0.tar.gz (33.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

backtest360-0.7.0-py3-none-any.whl (27.2 kB view details)

Uploaded Python 3

File details

Details for the file backtest360-0.7.0.tar.gz.

File metadata

  • Download URL: backtest360-0.7.0.tar.gz
  • Upload date:
  • Size: 33.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.15

File hashes

Hashes for backtest360-0.7.0.tar.gz
Algorithm Hash digest
SHA256 10be9719b774363bc2d3682e654e30d5c85113d39674c57ce3b31ad33deb7de3
MD5 abdd9a944312e406ed28fa4237e6ceaa
BLAKE2b-256 c96db0942ff3a2a80213b52ad07c71ff23a96b3e1ae8451531cbd4c233a99fd8

See more details on using hashes here.

File details

Details for the file backtest360-0.7.0-py3-none-any.whl.

File metadata

  • Download URL: backtest360-0.7.0-py3-none-any.whl
  • Upload date:
  • Size: 27.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.15

File hashes

Hashes for backtest360-0.7.0-py3-none-any.whl
Algorithm Hash digest
SHA256 72c9910590f9998b2dcdf97c0019ea95b3125f80d4d58731e369294ae213180d
MD5 83980289cd2589217ffe5763bc6c6978
BLAKE2b-256 ecb497a84be61e8c46d7a159cb9d93609d9103874a4327f131a11acc9a0ba758

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page