Skip to main content

A local-first quantitative backtesting and strategy analytics toolkit

Project description

jbqlab

PyPI version CI Python 3.10+ License: MIT

A local-first quantitative backtesting and strategy analytics toolkit.

jbqlab lets you backtest trading strategies on your own price data using a simple CLI or a clean Python SDK - all locally, no cloud account needed.


Table of Contents


Installation

pip install jbqlab

Python 3.10 or later is required. No sign-up, no API keys.


Quick Start

CLI - first backtest in 30 seconds:

# Download or create a CSV with date,close columns, then:
jbqlab validate data.csv
jbqlab backtest data.csv --strategy buy_and_hold
jbqlab backtest data.csv --strategy sma_crossover --param fast=10 --param slow=30

Python SDK - in three lines:

from jbqlab import run_backtest

result = run_backtest("data.csv", strategy="sma_crossover", fast=10, slow=30)
print(result.metrics)
# {'total_return': 0.28, 'cagr': 0.14, 'sharpe': 0.96, 'max_drawdown': 0.21, ...}

Data Format

jbqlab expects a CSV file with at minimum a date column and a close column.

date,close
2020-01-02,3257.85
2020-01-03,3234.85
2020-01-06,3246.28
...
  • date - any parseable date string (YYYY-MM-DD recommended)
  • close - adjusted closing price (numeric)
  • Additional columns (open, high, low, volume) are accepted but not required by most strategies

Validate your file first:

jbqlab validate data.csv --quality

CLI Reference

Run jbqlab --help or jbqlab <command> --help for full option details.

strategies

List all available strategies and their parameters.

jbqlab strategies

info

Show detailed information about a specific strategy, including its parameters and default values.

jbqlab info <strategy_name>

# Examples
jbqlab info sma_crossover
jbqlab info rsi

validate

Check a CSV file for backtesting compatibility.

jbqlab validate data.csv
jbqlab validate data.csv --ohlcv   # also check OHLCV consistency
jbqlab validate data.csv --quality # show data quality report

backtest

Run a backtest. Strategy parameters are passed with --param key=value and can be repeated.

# Default strategy
jbqlab backtest data.csv

# Strategy with parameters
jbqlab backtest data.csv --strategy sma_crossover --param fast=10 --param slow=30
jbqlab backtest data.csv --strategy rsi --param period=14 --param oversold=30
jbqlab backtest data.csv --strategy bollinger_bands --param window=20 --param num_std=2.5
jbqlab backtest data.csv --strategy macd \
  --param fast_period=12 --param slow_period=26 --param signal_period=9
jbqlab backtest data.csv --strategy momentum --param lookback=20

# Transaction costs and capital
jbqlab backtest data.csv --strategy sma_crossover \
  --param fast=10 --param slow=30 \
  --cost 0.001 --slippage 0.0005 --capital 50000

# Save to a custom directory
jbqlab backtest data.csv --strategy buy_and_hold --out my_results/

# Suppress progress output
jbqlab backtest data.csv --strategy buy_and_hold --quiet
Option Default Description
--strategy, -s buy_and_hold Strategy name
--param, -p - key=value parameter (repeatable)
--out, -o results/ Output directory
--cost 0.001 Transaction cost fraction (0.1%)
--slippage 0.0005 Slippage fraction (0.05%)
--capital 100000 Initial capital
--no-plot false Skip equity curve plot
--quiet, -q false Suppress output

optimize

Grid-search for the best strategy parameters.

jbqlab optimize data.csv --strategy sma_crossover --metric sharpe
jbqlab optimize data.csv --strategy rsi --metric calmar
jbqlab optimize data.csv --strategy sma_crossover \
  --fast-min 5 --fast-max 30 --fast-step 5 \
  --slow-min 20 --slow-max 60 --slow-step 10 \
  --metric total_return

Built-in grids: sma_crossover, mean_reversion, rsi, bollinger_bands, momentum. For custom grids use the Python SDK.

report

Generate a full markdown report with equity curve, metrics table, and trade log.

jbqlab report data.csv --strategy sma_crossover --param fast=10 --param slow=30
jbqlab report data.csv --strategy buy_and_hold --title "My Portfolio Report" --out report/

benchmark

Run all 12 strategies on the same dataset and produce a ranked comparison table.

jbqlab benchmark data.csv
jbqlab benchmark data.csv --out benchmark_results/ --no-plots

montecarlo

Bootstrap Monte Carlo simulation on a strategy's return distribution.

jbqlab montecarlo data.csv --strategy buy_and_hold
jbqlab montecarlo data.csv --strategy sma_crossover \
  --param fast=10 --param slow=30 \
  --simulations 20000 --horizon 252 --seed 42

portfolio

Detailed portfolio and risk statistics (Sharpe, Sortino, VaR, CVaR, win rate, etc.).

jbqlab portfolio data.csv --strategy buy_and_hold
jbqlab portfolio data.csv --strategy rsi --param period=14

Python SDK

from jbqlab import run_backtest, grid_search
from jbqlab.benchmark import run_benchmark, print_benchmark_summary
from jbqlab.montecarlo import monte_carlo_simulation
from jbqlab.portfolio import calculate_portfolio_stats
from jbqlab.plotting import plot_equity_curve
from jbqlab.reporting import save_results, generate_report

run_backtest

from jbqlab import run_backtest
import pandas as pd

# From a file path (str or Path)
result = run_backtest(
    "data.csv",
    strategy="sma_crossover",
    fast=10,
    slow=30,
    transaction_cost=0.001,   # 0.1% per trade
    slippage=0.0005,          # 0.05% per trade
    initial_capital=100_000,
)

# From a DataFrame
df = pd.read_csv("data.csv")
result = run_backtest(df, strategy="buy_and_hold")

# Access results
print(result.metrics)
# {'total_return': 0.285, 'cagr': 0.14, 'volatility': 0.31,
#  'sharpe': 0.557, 'sortino': 0.575, 'max_drawdown': 0.28, 'calmar': 0.50}

print(result.equity_curve.head())
# 2020-01-02    100000.00
# 2020-01-03    100014.23
# ...

print(result.positions.head())
# columns: date, close, signal, position, returns, equity

grid_search

from jbqlab import grid_search

result = grid_search(
    "data.csv",
    strategy="sma_crossover",
    param_grid={
        "fast":  [5, 10, 15, 20],
        "slow":  [20, 30, 40, 50],
    },
    optimize_metric="sharpe",  # or: total_return, calmar, sortino
    verbose=True,
)

print(result.best_params)
# {'fast': 10.0, 'slow': 20.0}

print(result.summary_df.head())
#    fast  slow  total_return   cagr  sharpe  max_drawdown
# 0  5.0  20.0         0.245  0.118   0.246         0.266
# ...

Benchmark

from jbqlab.benchmark import run_benchmark, print_benchmark_summary, save_benchmark

results = run_benchmark("data.csv")
print_benchmark_summary(results)     # Prints ranked table to stdout
save_benchmark(results, "output/")   # Saves CSV + equity curve plots

Monte Carlo Simulation

from jbqlab import run_backtest
from jbqlab.montecarlo import monte_carlo_simulation

result = run_backtest("data.csv", strategy="buy_and_hold")
returns = result.equity_curve.pct_change().dropna()

mc = monte_carlo_simulation(
    returns=returns,
    n_simulations=10_000,
    time_horizon=252,   # trading days
    random_seed=42,
)

print(mc.summary())
print(f"Probability of loss: {mc.prob_loss:.1%}")
print(f"5th percentile return: {mc.percentile_5:.2%}")

Portfolio Statistics

from jbqlab import run_backtest
from jbqlab.portfolio import calculate_portfolio_stats

result = run_backtest("data.csv", strategy="sma_crossover", fast=10, slow=30)
stats = calculate_portfolio_stats(result.equity_curve)

print(f"Sharpe:       {stats.sharpe_ratio:.2f}")
print(f"Max drawdown: {stats.max_drawdown:.2%}")
print(f"VaR (95%):    {stats.var_95:.2%}")
print(f"Win rate:     {stats.win_rate:.2%}")

Save Results & Reports

from jbqlab.reporting import save_results
from jbqlab.plotting import plot_equity_curve
from jbqlab.report import generate_report

save_results(result, "output/")        # metrics.json, equity_curve.csv, positions.csv
plot_equity_curve(result, "output/equity_curve.png")
generate_report(result, "output/report.md", title="My Backtest")

Available Strategies

Strategy Key Key Parameters
Buy and Hold buy_and_hold -
SMA Crossover sma_crossover fast (10), slow (30)
Mean Reversion mean_reversion window (20), z_entry (-2.0)
RSI rsi period (14), oversold (30), overbought (70)
MACD macd fast_period (12), slow_period (26), signal_period (9)
Bollinger Bands bollinger_bands window (20), num_std (2.0)
Momentum momentum lookback (20), threshold (0.0)
Dual Momentum dual_momentum lookback (12)
Donchian Channel donchian_channel window (20)
Volatility Breakout volatility_breakout window (20), atr_mult (1.5)
Trailing Stop trailing_stop trail_pct (0.05)
Triple SMA triple_sma fast (5), mid (20), slow (60)

Run jbqlab strategies for live parameter docs, or jbqlab info <strategy> for a single strategy.


Output Files

jbqlab backtest (and report) saves the following files to --out (default: results/):

File Description
metrics.json All performance metrics as JSON
equity_curve.csv Date-indexed equity curve
positions.csv Full position/signal log
equity_curve.png Equity curve chart
report.md Markdown report (report command only)

Metrics Reference

Metric Description
total_return Total % return over the period
cagr Compound Annual Growth Rate
volatility Annualised standard deviation of returns
sharpe Sharpe ratio (risk-free rate = 0)
sortino Sortino ratio (downside deviation)
max_drawdown Maximum peak-to-trough drawdown
calmar CAGR / max drawdown

Portfolio Stats (via jbqlab portfolio or calculate_portfolio_stats()): var_95, cvar_95, skewness, kurtosis, win_rate, profit_factor, avg_win, avg_loss, best_day, worst_day


Development

git clone https://github.com/JaiAnshSB26/jbqlab.git
cd jbqlab
pip install -e ".[dev]"

# Run tests
pytest tests/ -q

# Lint
ruff check src/ tests/

# Build a distribution
python -m build

Author: Jai Ansh Bindra
License: MIT
Changelog: CHANGELOG.md

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

jbqlab-1.0.2.tar.gz (54.8 kB view details)

Uploaded Source

Built Distribution

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

jbqlab-1.0.2-py3-none-any.whl (65.7 kB view details)

Uploaded Python 3

File details

Details for the file jbqlab-1.0.2.tar.gz.

File metadata

  • Download URL: jbqlab-1.0.2.tar.gz
  • Upload date:
  • Size: 54.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.4

File hashes

Hashes for jbqlab-1.0.2.tar.gz
Algorithm Hash digest
SHA256 f7ee582264d7ac7d56d93dcfcfc181860cee7b5fe4afb7a0639a305053fe5a55
MD5 01b2eba8e09e5189fe12182cfcf2881b
BLAKE2b-256 2067e8f33c58c12f7265d1ceb8476b5b3767a47ff2a23c4b0ddf8d74c1f96514

See more details on using hashes here.

File details

Details for the file jbqlab-1.0.2-py3-none-any.whl.

File metadata

  • Download URL: jbqlab-1.0.2-py3-none-any.whl
  • Upload date:
  • Size: 65.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.4

File hashes

Hashes for jbqlab-1.0.2-py3-none-any.whl
Algorithm Hash digest
SHA256 2d7f080b217adc0666840d4c8236c2bfa400c2b8d95d8f61d9a4af2142dde089
MD5 a8abae81f77a728e5c421fb09c2bdfc2
BLAKE2b-256 5caf066726ea866521ff9009853a5435ff338e02774f7ec8d16bf2236e14bb14

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