Benchmark A asks six accounting engines to replay one invariant-checked portfolio path. Benchmark B gives
them only adjusted data and the same research contract, then requires each engine to compute indicators,
decisions, execution and NAV independently. Agreement and divergence now answer two different questions.
1 · contractShared research input
One OHLCV hash, calendar, warmup, timing and initial capital.
2 · benchmark AConformance replay
One canonical target matrix tests accounting agreement.
3 · benchmark BNative strategies
Each engine computes signals, state, weights and rebalances.
4 · evidenceAttributed differences
Path error, first divergence, indicator semantics and rounding.
We compare QJ with free, open-source and commercial backtesting tools used for Python research, event-driven
simulation, cloud trading workflows and no-code portfolio testing.
#
Tool
Access
Model
Strongest at
Research trade-off
1
QJ Backtester
Open-source / Python
Python-first portfolio research engine
Signal, factor, allocation and order-aware validation with generated reports
Portfolio evidence, diagnostics and inspectable research packets
2
vectorbt
Open-source
Vectorized Python research library
Fast array research, parameter sweeps and signal experiments
Excellent speed; execution semantics and reports are workflow-dependent
3
pmorissette/bt
Open-source
Portfolio backtesting library
Clean allocation experiments and rebalancing workflows
Compact for simple portfolios; less focused on execution and generated evidence
4
Backtrader
Open-source
Python event-driven engine
Order-based strategies, broker-style simulation, stops and limits
Strong event model; portfolio research code grows with ranking and sizing logic
5
Zipline Reloaded
Open-source
Python event-driven research engine
Scheduled algorithms, daily equities and pipeline-style research
Clear research model; setup, bundles and data history calls add overhead
6
QuantConnect / LEAN
Cloud + open-source engine
Cloud platform plus C#/Python engine
Data, broker integrations, optimization and live deployment workflow
Powerful when deployment matters; heavier for small local portfolio research tests
7
NautilusTrader
Open-source core; separate Pro/Cloud services
Event-driven trading engine
Research-to-live parity, multi-asset execution, venue adapters and order lifecycle realism
Strong execution stack; heavier than needed for simple daily portfolio evidence
8
QuantRocket
Commercial platform
Self-hosted data, research and trading platform
Market data, Jupyter workflow, Zipline/Moonshot/Pipeline support and broker integration
Platform infrastructure first; less focused on lightweight standalone research packets
9
Portfolio123
Commercial / no-code
Stock ranking and portfolio simulation platform
Equity screens, ranking systems, buy/sell rules and point-in-time portfolio simulations
Accessible and data-rich; less inspectable than Python source-controlled research
10
TradingView
Commercial / chart-native
Charting platform with strategy testing
Visual chart research, Pine Script strategies, alerts and trader-facing workflows
Excellent for chart-native tests; less suited to auditable multi-engine portfolio validation
11
Composer
Commercial / no-code
No-code strategy builder and automated brokerage workflow
AI-assisted strategy creation, backtests, conditional logic and automated rebalancing
Very accessible; less open and programmable than local Python research
12
Qlib
Open-source
AI-oriented quantitative research platform
ML model research, alpha modeling, data pipelines and experiment workflows
Model-research first; portfolio accounting and report packets are not the main surface
13
FinRL
Open-source
Deep reinforcement learning trading framework
RL environments, agents, tutorials and portfolio allocation experiments
RL-focused research stack; not a general-purpose portfolio evidence engine
14
PyBroker
Open-source
Python algorithmic trading and ML backtesting library
ML-assisted strategy testing, ranking, walk-forward style experiments and Python workflows
Good for strategy research; less focused on generated institutional review packets
Which backtester fits your workflow?
The same engine can be excellent in one workflow and awkward in another. This matrix summarizes fit by
research task, using capability labels instead of binary checkmarks.
Workflow
QJ Backtester
vectorbt
bt
Backtrader
Zipline
LEAN
Fast signal researchIndicators, signal sweeps and daily portfolio experiments.
Strong
Native
Strong
Custom
Custom
Heavy
Portfolio weights / allocationTarget weights, rebalance schedules and allocation diagnostics.
Native
Strong
Native
Custom
Custom
Native
Order lifecycle realismStops, limits, fills, cash and positions; full broker-style lifecycle state varies by engine.
Native
Strong
Limited
Native
Strong
Native
Walk-forward validationOOS folds, training windows and overfit evidence.
Native
Built-in splits
Custom
Custom
Custom
Custom
Crisis / regime diagnosticsStress periods, market regimes and behavior under drawdown.
Native
Custom
Limited
Custom
Custom
Custom
Generated research reportsShareable reports with metrics, plots and engine-specific metadata.
Native
Custom
Limited
Custom
Custom
Native
Local Python workflowSmall local loop: edit strategy, run, inspect artifacts.
Native
Native
Native
Native
Heavy
Heavy
Live trading / broker pathMoving from research into live venue or brokerage integration.
Limited
Limited
Limited
Strong
Limited
Native
Native first-class workflow.Strong good fit with normal setup.Built-in splits chronological split utilities; end-to-end fold execution remains workflow-dependent.Custom possible through user code.Heavy powerful but larger stack.Limited not the main surface.
Compare Strategy Results
We run two complementary benchmarks. They answer different questions, so identical results mean something
different in each one. The measured engines are QJ Backtester, VectorBT,
pmorissette/bt, Zipline, Backtrader and
QuantConnect LEAN.
Benchmark
What is shared
What each engine does
What identical results mean
A · Conformance replay
One canonical decision and execution matrix, validated before every run.
Replays the same targets through its own accounting path.
Accounting agrees; identity is the pass criterion.
B · Native strategies
Only adjusted OHLCV data and the explicit research contract.
Computes indicators, signals, state, weights and rebalances itself.
Identity is not required; differences reveal real engine semantics.
Most public comparisons rewrite a strategy in every API and then mistake semantic drift for an engine
difference. Benchmark A removes that drift entirely. Benchmark B measures it deliberately and reports the first
divergent decision date with an attribution.
Benchmark A — conformance replay
One invariant-checked target matrix is mapped into six accounting engines. The goal is exact path agreement,
not independent signal generation. If the outputs differ beyond tolerance, the conformance test fails.
Benchmark strategies
We test different strategy types because each one exposes a different engine assumption: signal timing, rebalance calendars, ranking, volatility sizing or cash switching.
#
Strategy
What it tests
1
SMA crossover without costs
Indicator alignment, daily signal application, close-to-close assumptions
Absolute and relative momentum, asset-vs-cash switching, simultaneous allocation
Canonical equity paths with engine checkpoints
Every engine reproduces the same full NAV path. A neutral line shows that path; colored, staggered markers sample
actual observations from each engine so all six remain visible instead of the last rendered line hiding the other five.
The marker dates are staggered only for legibility; values are not offset or shifted. The complete daily path—not
merely the displayed checkpoints—is validated for QJ Backtester, VectorBT, pmorissette/bt, Zipline, Backtrader and LEAN.
Conformance replay final NAV
Validated July 11, 2026: $100,000 initial capital, 2015 warmup, 2016-01-04 to 2024-12-31 evaluation, adjusted OHLCV, close(t) decisions, close(t+1) execution, 0.1% cash buffer and zero benchmark costs. Every engine receives the same validated portfolio decisions; QJ is highlighted for easier scanning.
Strategy
QJ Backtester
VectorBT
pmorissette/bt
Zipline
Backtrader
QC LEAN
1. SMA 50/200
$1,596,086
$1,596,086
$1,596,086
$1,596,086
$1,596,086
$1,596,086
2. RSI Reversion
$307,971
$307,971
$307,971
$307,971
$307,971
$307,971
3. Monthly EW Rebal
$1,673,524
$1,673,524
$1,673,524
$1,673,524
$1,673,524
$1,673,524
4. Momentum+Vol
$657,808
$657,808
$657,808
$657,808
$657,808
$657,808
5. Dual Momentum
$3,706,895
$3,706,895
$3,706,895
$3,706,895
$3,706,895
$3,706,895
What conformance replay establishes
Conformance result: All 30 engine-strategy pairs pass the strict protocol: matching protocol hash, calendar, NAV path and final result within tolerance.
Path agreement: Daily-return correlation is 1.000 across every pair. The largest observed relative NAV difference is 2.05 × 10⁻¹⁰, caused by floating-point and linearly scaled whole-share adapters.
What was normalized: Adjusted OHLCV, warmup, decision weights, execution weights, close(t+1) lag, cash buffer, position cap, zero costs, initial capital and metric definitions are shared.
What QJ proves here: QJ native weight accounting reproduces the same portfolio path as five independent engines while keeping explicit weights, cash, holdings and report-ready state.
Where QJ is stronger: The benchmark only tests conformance. QJ adds one Python research surface for weight and order modes, generated evidence packets, walk-forward tooling and multi-asset examples; those product capabilities are not credited in the NAV table.
What this does not prove: This compact five-stock fixture is an engine-semantics test, not an alpha contest, capacity study or claim that these strategies are investment-ready.
Compute time is reported in the native benchmark below, where every engine computes the strategy itself.
Replaying a prevalidated decision matrix measures adapter plumbing rather than engine speed, so the
conformance section makes no timing claims.
Benchmark B · native strategy implementations
Each engine computes the strategy itself
Only adjusted OHLCV data and the research contract are shared. Every engine computes its own indicators,
signals, state, weights, rebalance decisions and portfolio path. Identical output is not required here:
differences expose the engines’ real semantics.
Validated July 21, 2026. Three consecutive complete runs changed 0 of 150 metric cells and the maximum
final-NAV delta between runs was $0.00. The shared contract uses AAPL, MSFT, NVDA, GOOGL and AMZN; adjusted
OHLCV; a 2015 warmup; 2016-01-04 through 2024-12-31 evaluation (2,264 sessions); $100,000 initial capital;
close(t) decisions; close(t+1) execution; a 0.1% cash buffer; and zero costs.
Each engine's checkpoints sample its own independently computed NAV path; marker dates are staggered only for
legibility and values are never shifted. On RSI mean reversion the VectorBT markers visibly trace a different
path — its documented rolling-RSI semantics — while the whole-share engines sit within rounding distance of the
fractional line.
Final NAV
Strategy
QJ
VectorBT
pm/bt
Zipline
Backtrader
LEAN
SMA 50/200
$1,596,086
$1,596,086
$1,596,086
$1,578,890
$1,595,709
$1,577,961
RSI Reversion
$307,971
$592,949 †
$307,971
$308,352
$307,658
$308,255
Monthly EW
$1,673,524
$1,673,524
$1,673,524
$1,668,082
$1,673,349
$1,666,680
Momentum + Vol
$657,808
$657,808
$657,808
$653,919
$657,422
$653,709
Dual Momentum
$3,706,895
$3,706,895
$3,706,895
$3,706,200
$3,706,560
$3,705,550
CAGR
Strategy
QJ
VectorBT
pm/bt
Zipline
Backtrader
LEAN
SMA 50/200
36.13%
36.13%
36.13%
35.97%
36.13%
35.96%
RSI Reversion
13.34%
21.92% †
13.34%
13.36%
13.33%
13.36%
Monthly EW
36.85%
36.85%
36.85%
36.81%
36.85%
36.79%
Momentum + Vol
23.34%
23.34%
23.34%
23.26%
23.33%
23.25%
Dual Momentum
49.53%
49.53%
49.53%
49.52%
49.53%
49.52%
Sharpe
Strategy
QJ
VectorBT
pm/bt
Zipline
Backtrader
LEAN
SMA 50/200
1.4147
1.4147
1.4147
1.4097
1.4146
1.4100
RSI Reversion
0.6256
0.9190 †
0.6256
0.6264
0.6252
0.6265
Monthly EW
1.2745
1.2745
1.2745
1.2733
1.2746
1.2734
Momentum + Vol
1.2918
1.2918
1.2918
1.2895
1.2913
1.2900
Dual Momentum
1.3592
1.3592
1.3592
1.3591
1.3591
1.3591
Max drawdown
Strategy
QJ
VectorBT
pm/bt
Zipline
Backtrader
LEAN
SMA 50/200
−28.41%
−28.41%
−28.41%
−28.52%
−28.42%
−28.50%
RSI Reversion
−47.41%
−30.44% †
−47.41%
−47.32%
−47.44%
−47.29%
Monthly EW
−41.65%
−41.65%
−41.65%
−41.79%
−41.64%
−41.76%
Momentum + Vol
−23.05%
−23.05%
−23.05%
−23.30%
−23.06%
−23.27%
Dual Momentum
−38.86%
−38.86%
−38.86%
−38.62%
−38.86%
−38.62%
† VectorBT RSI semantics: by default, its native implementation uses a rolling mean of gains and losses;
the other five engines use Wilder smoothing. We deliberately did not normalize this away—it is the kind of
semantic difference this benchmark is designed to expose.
Decision divergence audit
Target weights from every native implementation are compared with QJ on all comparable dates. The audit records
the first divergence and attributes its cause instead of treating every different NAV as an unexplained engine gap.
Strategy
Engine
Differing decision rows
First divergence
Attribution
All five
Zipline / Backtrader / LEAN / pm-bt
0
—
—
SMA, Monthly, Momentum, Dual
VectorBT
0
—
—
RSI Reversion
VectorBT
1,646 / 2,264
2016-01-07
Rolling RSI vs Wilder RSI
Fractional accounting
Why three engines agree to the last digit
QJ, VectorBT and pm/bt use fractional target-weight accounting with zero costs. Under those conditions the NAV
path is a pure function of weights and close prices:
NAV(t+1) = NAV(t) × (1 + Σ w·r)
Independent engines evaluating the same function on the same decisions must agree. Across the complete
nine-year paths, the largest pairwise difference is $0.000000007 (about 3×10⁻¹⁵ relative): ordinary
double-precision rounding. Bit-identical copied output—not close independent arithmetic—would be the red flag.
Whole-share execution
Why the remaining paths differ
Zipline, Backtrader and LEAN place integer-share orders through their own execution paths. Rounding down leaves
a small, price-dependent cash residue on every rebalance.
Final NAV ends 0.02–1.1% below the fractional result as uninvested cash compounds over nine years.
Max drawdown can be shallower because the same residue drags during rallies and cushions declines.
For Dual Momentum, every engine finds the same 2018-10-01 peak and 2018-12-24 trough. The whole-share book was
about 0.08% behind at the peak and 0.31% ahead at the trough—an attributable path effect, not a different signal.
Native compute time (fair core seconds; lower is better)
Strategy computation and engine accounting only; data fetch, report rendering, exports and process startup are
excluded. QJ reports its calculation core. LEAN reports its internal algorithm timer because container parse time
is unstable between runs. Values are medians of three consecutive complete runs. Timing varies between runs; the
metrics above do not.
Strategy
QJ
VectorBT
pm/bt
Zipline
Backtrader
LEAN
SMA 50/200
0.73 s
0.16 s
1.35 s
6.59 s
1.23 s
1.94 s
RSI Reversion
2.21 s †
1.99 s †
3.28 s
1.88 s
0.88 s
1.20 s
Monthly EW
0.16 s
0.11 s
0.58 s
1.06 s
0.74 s
0.94 s
Momentum + Vol
0.36 s
0.18 s
0.53 s
1.45 s
0.72 s
0.81 s
Dual Momentum
0.23 s
0.16 s
0.44 s
1.20 s
0.71 s
0.78 s
† RSI timing: QJ and VectorBT both spend most of this time in the identical Python state-machine
loop defined by the strategy. Path-dependent entry/exit state cannot be fully vectorized; the underlying accounting
pass runs in milliseconds.
Figure 2. Native benchmark core time by engine; strategy logic plus engine accounting, lower bars are faster.
Vectorized accounting with complete state
QJ’s weight-ledger accounting is fully vectorized while retaining explicit cash, holdings, margin history and an
accounting-identity assertion on every bar. The vectorized path was verified bit-identical: maximum equity
difference $0.000000000000 across all 11,320 daily observations, with the complete 967-test suite green.
Speed on a five-ticker fixture is a workflow signal, not a universal leaderboard. Data access, caching, universe
size and execution model dominate real research time.
What the two benchmarks establish
Conformance (A): all engines reproduce one canonical path within 10⁻¹⁰; accounting agrees.
Independence (B): with only data and contract shared, five engines converge on identical decisions everywhere except VectorBT’s documented RSI semantics. NAV differences are attributed to whole shares or the indicator definition, with the first divergent date reported.
Determinism: three consecutive complete 30-backtest runs produced no changed metric cells and a maximum final-NAV delta of $0.00.
What this does not prove: this is an engine-semantics test on a compact fixture—not an alpha contest, capacity study or claim that these strategies are investment-ready.
Full disclosure
The three fractional adapters share the research contract—data, constants and rebalance-calendar helpers—but each computes signals in its own code and runs its own accounting: the QJ ledger, vbt.Portfolio.from_orders, or btWeighTarget/Rebalance. Their agreement is mathematically forced once independently computed decisions agree.
LEAN runs the official Docker image. Its five native strategies share one algorithm base class with per-strategy logic selected at runtime.
Every native result JSON records the data SHA-256, contract version and engine mode. A single runner regenerates the artifacts and gates publication on 30/30 results, one data hash, one calendar and attributed divergences only.
Conformance adapter methodology: strategy logic runs once and produces the invariant-checked decision and execution artifacts.
The excerpts below come from the strict adapters actually used; they show only how each engine consumes those same
artifacts. No adapter recalculates signals, changes the 25% cap, renormalizes cash or applies a different lag.
One decision matrix. Six adapter surfaces.
QJ consumes canonical decision weights through its native one-bar lag and portfolio accounting path. VectorBT,
pmorissette/bt and Backtrader receive the resulting execution targets; Zipline and LEAN receive equivalent scaled
quantities where their accounting models require them. This is adapter code, not six different strategy definitions.
QJ Backtester
Decision weights through the native lag and rebalance path
SUBMISSION_SHARES[decision_date] = (
execution_shares.loc[execution_date]
)
def handle_data(context, data):
if session_date(data.current_dt) not in SUBMISSION_DATES:
return
for ticker, asset in context.assets.items():
desired = scaled_quantity(ticker)
delta = desired - current_quantity(asset)
if delta:
order(asset, delta)
perf = run_algorithm(
start=pd.Timestamp("2015-12-31"),
end=pd.Timestamp("2024-12-31"),
handle_data=handle_data,
capital_base=100_000 * MICRO_SHARE_SCALE,
bundle="qj_compare",
)
Backtrader
Target-percent orders with close execution
class CanonicalTargetStrategy(bt.Strategy):
params = dict(targets=None, execution_dates=None)
def next(self):
date = self.datas[0].datetime.date(0)
if date not in self.p.execution_dates:
return
row = self.p.targets.loc[pd.Timestamp(date)]
nav = float(self.broker.getvalue())
orders = []
for data in self.datas:
target = float(row[data._name])
current = self.getposition(data).size * data.close[0]
orders.append((target * nav - current, data, target))
orders.sort(key=lambda item: item[0])
for _delta, data, target in orders:
self.order_target_percent(data=data, target=target)
cerebro.broker.set_coc(True)
QuantConnect LEAN
Scaled canonical quantities at the closing auction
class CanonicalWeightsAlgorithm(QCAlgorithm):
def initialize(self):
self.set_start_date(2015, 12, 31)
self.set_end_date(2024, 12, 31)
self.set_cash(100_000 * MICRO_SHARE_SCALE)
self.execution_quantities = load_canonical_quantities()
self.schedule.on(
self.date_rules.every_day(self.calendar_symbol),
self.time_rules.before_market_close(self.calendar_symbol, 20),
self.submit_close_targets,
)
def submit_close_targets(self):
desired = self.execution_quantities.get(self.time.date())
for delta, symbol in sell_before_buy_deltas(desired):
self.market_on_close_order(symbol, delta)
Detailed engine comparisons
Use this chapter for the practical trade-offs between QJ and the individual engines below.
vs vectorbt
QuantJourney vs vectorbt
vectorbt is excellent for fast vectorized experimentation and parameter sweeps across NumPy arrays. It is the right choice when iteration speed is the primary objective. QuantJourney is designed for the next step: moving from fast signal research to portfolio evidence.
Question
vectorbt
QuantJourney
Can I test many signals quickly?
Yes
Yes
Can I work with target portfolio weights?
Yes
Native
Separate signals, weights, orders, fills, cash, positions and NAV?
Available; explicit state separation is workflow-dependent
High-speed parameter experimentation across NumPy/pandas arrays is where vectorbt is unmatched.
Use QuantJourney when
The backtest must become portfolio evidence
When results need to be explainable, auditable and shareable — with accounting behind them.
vs Backtrader
QuantJourney vs Backtrader
Backtrader is a mature Python framework for event-driven strategy simulation. It is useful when the strategy is naturally order-based with explicit entry/exit logic. QuantJourney is built around weight-based systematic research where accounting assumptions, diagnostics and research output matter as much as entry logic.
Question
Backtrader
QuantJourney
Event-driven strategy simulation?
Yes
Yes / growing
Order simulation?
Yes
Yes
Portfolio-weight research as first-class workflow?
Custom
Native
Walk-forward, crisis diagnostics and research packets built in?
Custom
Native
Modern data integration?
Custom
Native
Use Backtrader when
Classic event-driven simulation
Entry/exit logic, stops, limits and broker simulation are the core of the strategy.
Use QuantJourney when
Portfolio-weight research and evidence
Weight-based systematic strategies that need accounting discipline and reportable output.
vs LEAN
QuantJourney vs LEAN
LEAN is a powerful open-source engine for research, optimization and live trading deployment across venues. It is strongest when the workflow needs to move from algorithm design into live brokerage execution. QuantJourney is strongest earlier in the process: portfolio research, local accounting, validation evidence and a shareable research packet.
Question
LEAN
QuantJourney
Backtesting?
Yes
Yes
Live trading deployment?
Native
Optional / not primary
Multi-asset engine?
Native
Yes / depends on data
Portfolio research reports and diagnostics?
Native report generation; extensible
Native
Local private research workflow?
Yes / CLI
Native
Parameter optimization?
Native cloud/CLI optimizer; Optuna via custom wiring
Native (Optuna TPE with walk-forward)
Use LEAN when
Live trading deployment is the goal
Moving from algorithm to live deployment across brokers and venues is where LEAN excels.
Use QuantJourney when
Research evidence and accounting clarity
Portfolio-level validation, diagnostics and research packets before a strategy becomes a production workflow.
Independent validation services
Matching equity curves prove conformance. They do not prove the research.
QuantJourney Validation Services audits the assumptions behind the curve—from data lineage, look-ahead and
survivorship bias through signal timing, rebalancing, execution, costs, parameter selection and out-of-sample
stability. You receive a reproducible evidence pack with the verdict, limitations and next actions, while
sensitive strategy code can remain inside your infrastructure.