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.3.tar.gz (54.9 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.3-py3-none-any.whl (65.8 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: jbqlab-1.0.3.tar.gz
  • Upload date:
  • Size: 54.9 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.3.tar.gz
Algorithm Hash digest
SHA256 26b92def4a52677d89cec1e10f51bda952b646500ad5f25271d50fd353bbe5ad
MD5 5838c38b32d4f395f2d64c8844100651
BLAKE2b-256 a57c8fb76ddf61df2166a96009f6839d86f3992b77c8071dcc5bdcec33a4f3a3

See more details on using hashes here.

File details

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

File metadata

  • Download URL: jbqlab-1.0.3-py3-none-any.whl
  • Upload date:
  • Size: 65.8 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.3-py3-none-any.whl
Algorithm Hash digest
SHA256 a088ef6338f4c6b50e83eb3f380540165e11ad92eb3e6b35ed3c1030131121a7
MD5 4838775a5edeebe746306e9827a7f141
BLAKE2b-256 5ca6d89a2df2caa6ee4c9cdc239dd6ea035e702f6e05a34094b294ab2b0a059c

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