Star 历史趋势
数据来源: GitHub API · 生成自 Stargazers.cn
README.md

QuantJourney Backtester

A Python-native backtesting engine for reproducible portfolio research.

Python PyPI License Platform API Changelog

QuantJourney Backtester turns strategy ideas into auditable research packets: signals become target weights or explicit orders, orders become simulated fills, fills update cash and positions, and NAV is reconstructed from portfolio state.

It is designed for researchers who need more than an equity curve: execution assumptions, costs, slippage, rebalancing rules, crisis behavior, walk-forward validation, optimization diagnostics, metrics, plots, and run metadata from one repeatable run.

Free Quant Research & Learning Resources

  • Quant Interviews — 194 quantitative finance interview questions covering mathematics, statistics, trading systems, and coding. Download both books as free PDFs.
  • QuantJourney Blog — 300+ articles on quantitative finance, systematic strategies, and backtesting. Subscribe for new research and code.
  • Quant Videos — Trading strategies, Python implementations, and code walkthroughs on YouTube.

Installation

pip install quantjourney-bt

Current PyPI release: 0.12.5. The public package supports Python 3.11 and newer.

Why It Exists

Most backtests stop at signal x returns. That is fast, but it hides the questions that matter before a strategy can be trusted:

  • Was there look-ahead?
  • What happened to missing bars?
  • How were weights converted into trades?
  • Did costs and turnover destroy the edge?
  • Did parameters generalize out of sample?
  • Which crisis regimes broke the strategy?
  • Can the run be reproduced and reviewed later?

QuantJourney Backtester makes these assumptions explicit.

Two Research Modes

Weight mode is for portfolio research: factor portfolios, rotation models, long/cash strategies, long/short books, risk overlays, volatility targeting, and scheduled rebalancing.

Order mode is for execution-aware research: market, limit, stop, stop-limit, trailing stop, bracket, and OCO orders with commissions, slippage, volume participation, fills, positions, cash, NAV, and trade blotters.

Fast weight execution solves transaction costs recursively on one post-cost capital path: NAV, implied quantities, trade notionals, booked costs and reported positions reconcile to the same self-financing ledger. Use weight_execution="orders" when discrete fills and cash movements matter. For fills at the open, range-sensitive slippage sees only the previous completed bar and volume capacity is forecast from lagged observations; the engine does not use that day's later high, low, close or full-day volume.

Engine Contract

Data -> Features -> Signals -> Target Weights / Orders -> Fills -> Positions -> NAV -> Metrics -> Report Packet

Each stage is explicit. Data is transformed into features, features drive signals, signals become either target weights or orders, execution assumptions turn those decisions into fills, and portfolio state is used to reconstruct NAV, metrics, plots, and run metadata.

What you want to do -> what to use

I want to...Use
Generate long / flat / short or ranking intent_compute_signals()
Convert intent into target portfolio exposure_compute_weights()
Apply caps, vol targeting, inverse vol, or risk parityrisk_model=...
Trade only on calendar, drift, signal, or turnover triggersRebalancePolicy(...)
Submit market / limit / stop / trailing / bracket / OCO ordersexecution_mode="orders" + _compute_orders(...)
Model spread, impact, and commission assumptionsslippage & commission models
Validate parameters out of samplewalk-forward / Optuna

The repository examples and tests demonstrate these engine semantics locally.

What You Get From One Run

Each local run can produce metrics, plots, equity curves, drawdowns, rolling risk, optimization evidence, walk-forward results, CSV/JSON artifacts, a static HTML dashboard, and run metadata. The hosted platform adds crisis diagnostics, interactive dashboards, execution traces, and PDF tear sheets.

What Stays Local

Your strategy code, signals, portfolio accounting, order simulation, metrics, plots, generated reports, and run artifacts stay local. QuantJourney Cloud is used for market-data preparation and authentication.

What It Is Not

This is not a broker, not a live trading system, not investment advice, and not a guarantee that a strategy will work out of sample. Some examples intentionally simplify assumptions such as borrow cost, financing, liquidity and market impact. Those assumptions are documented so they can be changed, not hidden.

Example Output

Every run produces a review-ready research packet — equity curves, monthly returns heatmaps, drawdowns, risk and rolling statistics, and walk-forward / optimization summaries (see Reports for the exact file list). A few examples:

Cumulative returns vs benchmark

Cumulative returns vs benchmark

Monthly returns heatmap

Monthly returns heatmap

Crisis analysis across historical stress periods (hosted platform report pack)

Crisis analysis

Walk-forward out-of-sample equity (hosted platform report pack)

Walk-forward out-of-sample equity

The first two charts come from the open-source report pack in this repository. Charts marked hosted platform report pack — crisis analysis, trade blotters, execution traces, PDF factsheets, and interactive dashboards — are generated by the hosted QuantJourney platform on top of the same engine results. More examples at backtester.quantjourney.cloud.

Install

pip install quantjourney-bt

With uv:

uv pip install quantjourney-bt

Optional extras: pip install "quantjourney-bt[wf]" or uv pip install "quantjourney-bt[data,wf]" adds Optuna for the walk-forward optimization examples (WF05); [data] adds the yfinance benchmark fallback.

For local development:

python3 -m venv .venv
source .venv/bin/activate
python -m pip install -U pip
python -m pip install -e ".[dev,data]"
pytest

Do not install dependencies into the Homebrew/system Python. Use a virtual environment; otherwise macOS/Homebrew may raise an externally-managed-environment error and the launcher may miss packages such as quantjourney_ti.

Reproducible Demo Without API Key

Run the first strategy against deterministic bundled sample data:

./strategy.sh example_weights_01_sma_daily --sample-data --output /tmp/qj-sample

The sample dataset is intentionally small and reproducible. It is useful for install checks, report generation, and reading the engine flow without creating an account. For real market data, set QuantJourney API credentials and run the same strategy without --sample-data.

qj-bt Data Catalog

Open the optional keyboard-driven browser in an interactive terminal:

qj-bt data

Use deterministic section commands in scripts, CI, or an agent workflow:

qj-bt data overview
qj-bt data sources
qj-bt data granularities
qj-bt data datasets
qj-bt data asset-classes
qj-bt data universes
qj-bt data example-symbols
qj-bt data sources --json

qj-bt data uses the public metadata endpoints without reading or transmitting an API key. When no section is supplied, it opens the interactive browser only when stdin and stdout are attached to a terminal; otherwise it emits the overview table. The example-symbol index is illustrative and is not an exhaustive market-data availability catalog.

Repository Layout

backtester/               Runtime package imported as backtester
strategies/               Runnable strategy examples
strategy.sh               macOS/Linux strategy launcher
strategy.bat              Windows strategy launcher
strategy.py               Shared cross-platform launcher logic
benchmarks/               Benchmark-suite notes
skills/                   Strategy-authoring skill materials
tests/                    Import, packaging, and report smoke checks
docs/                     Roadmap and supporting documentation
CHANGELOG.md              Release history

The public runtime includes the shared execution simulator, contract-aware portfolio ledger, portfolio-of-strategies book, and pre-trade risk controls. Hosted data, orchestration, and extended report packs remain outside this repository; see Public Scope.

The tests/ directory is intentionally kept. It is not required at runtime, but it gives the package a quick install/import/report safety check before release.

Documentation

  • Windows setup - native Windows installation and strategy.bat usage without WSL.
  • Roadmap - direction of travel by theme, without delivery dates or ordering commitments.
  • Strategy catalog - runnable examples with source and result links.
  • Contributing - how to add example strategies, fixes, and docs (fork, branch, pull request).
  • Performance refactor in 0.12.4 - benchmark results, implementation details, and parity checks for the faster engine paths.
  • Release process - clean-tag publishing and exact artifact boundary checks.

AI Co-Pilot Skills

The skills/ directory holds guidance packs for AI-assisted research. When you work with an AI coding assistant, point it at the relevant SKILL.md so it follows the engine's conventions instead of guessing:

SkillUse it to
qj-strategy-ideasTurn an idea into a runnable strategy — weights vs orders, the nearest example, the two-method pattern.
qj-strategy-authorWrite a clean, focused example strategy.
qj-strategy-reviewerReview a strategy for look-ahead, exposure, cost realism, and mode fit.
qj-report-analystRead a report and its plots and judge whether the result is trustworthy.
qj-config-helperConfigure the engine — parameters, rebalance policy, risk overlays, granularity.

For example: when writing a new strategy, open skills/qj-strategy-ideas/SKILL.md and follow the pattern; when reviewing one, use skills/qj-strategy-reviewer/SKILL.md; to make sense of the output, use skills/qj-report-analyst/SKILL.md.

Quick Start

For a full catalog of all 50 example strategies — each with a one-line description, a link to its source, and a link to its results page — see strategies/README.md or the summary below.

List available strategies:

./strategy.sh --list

On Windows use strategy.bat --list in Command Prompt or .\strategy.bat --list in PowerShell. See WINDOWS.md for the complete native Windows workflow.

Check one strategy import without credentials or a data call:

./strategy.sh example_weights_01_sma_daily --check

Run a deterministic demo without API credentials:

./strategy.sh example_weights_01_sma_daily --sample-data --output /tmp/qj-sample

Run repository checks:

pytest -q

Run a real backtest after setting credentials:

export QJ_API_KEY="..."
./strategy.sh example_weights_01_sma_daily --output /tmp/qj-reports

If market-data preparation rejects the strategy configuration, the launcher stops before execution and shows a yellow Configuration needs attention panel with the affected field and a suggested fix. Normal runs omit the raw response and traceback; set QJ_LOG_LEVEL=DEBUG when technical request details are needed.

Run all strategies sequentially through the same launcher:

export QJ_API_KEY="..."
./strategy.sh --all --output ./reports

The batch continues after individual failures and writes per-strategy logs plus a tab-separated summary under reports/_batch/<timestamp>/. Use ./strategy.sh --all --check to import-check the full catalog without data calls.

API key auth is preferred for CLI runs. Email/password auth also works; if the auth service returns an active-session conflict, the launcher retries with replace_existing_session=true by default. Set QJ_REPLACE_EXISTING_SESSION=0 if you do not want a CLI run to replace an existing web session.

Hosted Backtester runs require the account entitlement product:backtester and a restricted API key carrying both product:backtester and feature:backtester. If either grant is missing, the launcher stops before execution and points to Account and API keys without printing a Python traceback.

Strategy Catalog

The repository ships 50 runnable example strategies — 25 weight-based, 20 order-based, and 5 walk-forward / optimization. Each has source and results-page links in the full catalog; a summary follows.

Weight-based (25) — target-weight portfolios, market-neutral long/short, and risk overlays:

#StrategyIdeaCodeResults
W01Daily SMA TrendHold each sector ETF while SMA(50) > SMA(200); daily rebalancesourceview
W02Monthly ETF Trend + DriftSMA(50/200) trend on ETFs; month-end + 5% drift bandsourceview
W03Weekly RSI ReversionEnter RSI(14) < 35, exit RSI > 60; weekly (Fri)sourceview
W04Quarterly Dual MomentumRank ETFs by 12-month return, hold top 2 if positive; quarter-endsourceview
W05Monthly Inverse VolatilitySize each ETF by inverse 63-day volatility; month-endsourceview
W06Signal-Change Defensive RotationSPY > SMA(200) -> risk-on ETFs, else defensive; on signal changesourceview
W07Intraday RSI 15mEqual-weight basket when RSI oversold; 15-minute barssourceview
W08Intraday EMA Scalp 1mEMA(9/21) trend/cash; 1-minute barssourceview
W09Intraday SMA Trend 1hSMA(10/30) trend/cash; hourly barssourceview
W10Monthly + Circuit BreakerMonthly ETF trend; flatten on a 15% drawdown + cooldownsourceview
W11Quarterly TE + Cost GateMomentum with tracking-error trigger and turnover budgetsourceview
W12Daily Partial DriftMomentum tilt; trade only names past a 10% drift bandsourceview
W13Pairs Trading (Ratio Z-Score)Market-neutral KO/PEP on a log-ratio z-scoresourceview
W14Pairs Trading (Hedge Ratio)Market-neutral EWA/EWC on a rolling OLS hedge-ratio spreadsourceview
W15Cross-Sectional Momentum (L/S)Long top-3 / short bottom-3 by 12-month return; monthlysourceview
W16Cross-Sectional Reversal (L/S)Long losers / short winners by 1-month return; weeklysourceview
W17Vol-Targeted TrendSMA trend basket scaled to a 10% volatility targetsourceview
W18Vol-Targeted MomentumMomentum basket scaled to a 15% volatility targetsourceview
W19Risk Parity (Multi-Asset ERC)Equal risk contribution across a multi-asset basketsourceview
W20Risk Parity + Position CapSector ERC chained with a 25% per-position capsourceview
W21Bollinger Band ReversionBuy below the lower band, exit at the midlinesourceview
W22MACD TrendLong while MACD is above its signal linesourceview
W23FX Time-Series MomentumSix-month trend across USD-quoted spot pairs; inverse-vol weightssourceview
W24FX Cross-Sectional MomentumLong strongest / short weakest XXX/USD pair; monthlysourceview
W25Continuous Futures Trend ProxyDiversified long/short trend on provider continuous seriessourceview

W23-W25 are price-return research proxies. They do not apply FX lots or futures multipliers to PnL and do not model financing, margin, or controlled futures rolls.

Order-based (20) — explicit orders through the fill engine (slippage, commissions, blotter):

#StrategyOrder typeIdeaCodeResults
O01Market SMA CrossoverMarketBuy SMA(20) crossing above SMA(50), sell on reversesourceview
O02Market RSI ReversionMarketBuy RSI(14) < 35, sell RSI > 60sourceview
O03Limit RSI Dip BuyerLimitPassive buy-limit below the close on weak RSIsourceview
O04Limit Trend PullbackLimitIn an uptrend, wait for a 1% pullback to entersourceview
O05Stop Breakout EntryStopBuy-stop above the recent 20-day highsourceview
O06Protective Stop LossMarket + StopTrend entry with a 5% protective stopsourceview
O07Stop-Limit BreakoutStop-LimitEnter breakouts but cap the maximum fill pricesourceview
O08Stop-Limit ProtectionMarket + Stop-LimitTrend entry, downside protected by a stop-limit sellsourceview
O09Trailing Stop TrendTrailing StopTrend entry, 4% trailing stop manages the exitsourceview
O10RSI + Trailing StopTrailing StopOversold RSI entry, 5% trailing stop for risksourceview
O11Trailing Stop-LimitTrailing Stop-LimitTrailing stop that converts to a limit on triggersourceview
O12Bracket TrendBracketTrend entry with a +6% / -3% bracketsourceview
O13Bracket RSI ReversionBracketRSI dip with a +4% / -2% bracketsourceview
O14OCO Dip or BreakoutOCOCompeting buy-limit (dip) and buy-stop (breakout)sourceview
O15Intraday 5m Bracket ReversionBracketOversold-RSI dips with a tight +0.6% / -0.4% bracket; 5-min barssourceview
O16Intraday 30m Stop BreakoutStopBuy-stop above the 12-bar high, fixed holding period; 30-min barssourceview
O17Monthly Rotation (orders)MarketEvent-driven monthly momentum rotation, executed with orderssourceview
O18Signal-Change Rotation (orders)MarketTrade only on SMA trend-signal flips (no calendar)sourceview
O19FX Momentum with Standard LotsMarketContract-aware whole-lot momentum on USD-quoted spot pairssourceview
O20Futures Donchian ContractsMarketWhole-contract ATR sizing on provider continuous futuressourceview

O19-O20 consume provider contract specifications. Multipliers and lot sizes are applied. Cross-currency conversion, FX swaps, dated-futures selection, and controlled roll execution remain out of scope; unsupported cross-currency FX accounting is rejected rather than approximated.

Walk-forward & optimization (5) — prove a strategy generalizes:

#ExampleIdeaCodeResults
WF01Rolling Walk-ForwardSliding fixed-length train/test windows with a pre-OOS purgesourceview
WF02Expanding Walk-ForwardEver-growing training window vs sliding test windowsourceview
WF03Anchored + Pre-OOS PurgingFixed and percentage-based exclusions before each test windowsourceview
WF04Grid SearchExhaustive SMA fast/slow tuning scored by real backtestssourceview
WF05Optuna TPE + Walk-ForwardBayesian parameter search, then out-of-sample validationsourceview

WF01-WF03 default to slice_diagnostics: train/test metrics are computed from one full-period NAV so examples run quickly and remain easy to inspect. To run a fuller per-fold strategy re-run/refit, enable:

QJ_WF_MODE=per_fold_refit ./strategy.sh example_wf_01_rolling_walkforward

The logs and walk-forward summary report the active mode. Per-fold refit is slower because each fold runs the strategy again through the data/preparation pipeline. Factories receive ISO date strings, and the runner fails closed if the returned NAV escapes the requested fold bounds. Learned preprocessing must still be fitted on training data only.

extra_pre_oos_purge_pct extends the exclusion immediately before OOS; the legacy embargo_pct alias does not implement classical post-test embargo. Optimizer runs report DSR with raw/effective trial counts plus a rolling top-K rank-failure diagnostic. The latter is not canonical CSCV PBO.

WF04-WF05 are optimization workflows and should be read as selection diagnostics rather than a simple winner-takes-all backtest.

Long/short examples (W13–W16) are market-neutral; short borrow/financing is not modeled (a documented research approximation).

Data Granularity

Backtester(..., granularity="1d") remains the default. For yfinance-backed /bt/prepare data you can request historical intraday bars with values such as 1m, 5m, 15m, 30m, or 1h; numeric aliases like granularity=5 are normalized to 5m.

strategy = MyStrategy(
    api_key="...",
    instruments=["AAPL", "MSFT"],
    backtest_period={"start": "2026-06-01", "end": "2026-06-05"},
    source="yfinance",
    granularity="5m",
)

Intraday availability depends on yfinance history coverage for the requested symbols and dates.

Strategy Skeleton

import asyncio
import os
import pandas as pd

from backtester import Backtester


class MyStrategy(Backtester):
    def _compute_signals(self) -> pd.DataFrame:
        close = self.instruments_data.get_feature("adj_close")
        fast = close.rolling(20).mean()
        slow = close.rolling(60).mean()
        return ((fast > slow) & fast.notna() & slow.notna()).astype(float)

    def _compute_weights(self) -> pd.DataFrame:
        signals = self.instruments_data.get_feature(
            "strategies", self.strategy_name, "signals"
        )
        active = signals.sum(axis=1).replace(0, pd.NA)
        return signals.div(active, axis=0).fillna(0.0)

    def _compute_positions(self) -> None:
        pass


async def main() -> None:
    strategy = MyStrategy(
        api_key=os.environ["QJ_API_KEY"],
        strategy_name="sma_research",
        instruments=["AAPL", "MSFT", "NVDA"],
        backtest_period={"start": "2024-01-01", "end": "2025-01-01"},
        source="yfinance",
        granularity="1d",
        initial_capital=100_000,
    )
    await strategy.run_strategy()
    strategy.print_summary()


if __name__ == "__main__":
    asyncio.run(main())

Reports

By default a strategy run writes outputs under reports/<strategy_name>/ or the directory passed to --output:

  • summary.txt
  • summary.json
  • metrics.csv
  • equity_curve.csv
  • equity_curve.png
  • dashboard.html
  • selected PNG charts under plots/
  • run_metadata.json

Use --no-reports when you only want calculation and run metadata:

./strategy.sh example_weights_01_sma_daily --no-reports --output /tmp/qj-reports

Assumptions & Limitations

  • Example strategies are research templates, not production trading systems.
  • Long/short examples do not model borrow fees, stock-loan availability, financing, or margin interest by default.
  • Commissions, slippage, volume participation, and market impact are model assumptions. Treat them as part of the research contract.
  • The deterministic sample dataset is illustrative. It is not historical market data and should not be used to judge strategy quality.
  • Historical intraday availability depends on the upstream provider and the requested symbols, dates, and granularity.
  • Walk-forward and optimization diagnostics help expose overfit risk, but a good in-sample or single out-of-sample result is not proof of robustness. Check whether a run used slice_diagnostics or per_fold_refit.

The runtime package is imported as backtester.

License

Apache License 2.0.

关于 About

QuantJourney Backtester
backtest-enginebacktesterbacktester-pythonbacktestingbacktesting-toolshedge-fundoptunastock-marketstocksstrategieswalk-forwardwalk-forward-backtest

语言 Languages

Python99.8%
Shell0.1%
Batchfile0.0%

提交活跃度 Commit Activity

代码提交热力图
过去 52 周的开发活跃度
65
Total Commits
峰值: 23次/周
Less
More

核心贡献者 Contributors