A local-first quantitative backtesting and strategy analytics toolkit
Project description
jbqlab
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
- Quick Start
- Data Format
- CLI Reference
- Python SDK
- Available Strategies
- Output Files
- Metrics Reference
- Development
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
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
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file jbqlab-1.0.1.tar.gz.
File metadata
- Download URL: jbqlab-1.0.1.tar.gz
- Upload date:
- Size: 54.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c9f3b119fe46929139d987f63162c443395de81d9130590816377423708b80c6
|
|
| MD5 |
25be694d771cd045c74397e163e3b08e
|
|
| BLAKE2b-256 |
c2fbec08758c358f8a60418475a5dde4524ef5149d8bdb5873d1744b8a1600e7
|
File details
Details for the file jbqlab-1.0.1-py3-none-any.whl.
File metadata
- Download URL: jbqlab-1.0.1-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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7dabf5b6eb7185a2520bca07c1fecdf8a539a42c0639cb71bb2244ceb587bb90
|
|
| MD5 |
191ad19841993b28ac69ee2a5896cdf1
|
|
| BLAKE2b-256 |
0382efd556be079d564ca16ca2ee12a2fbd37341b137e6d91aef15d793dfe63b
|