Documentation

Backtests

Use the Test button (Running code) in the QuantCraft IDE to open Run backtest. There you set symbols, price data, optional fundamentals, the simulation window, starting balance and fill costs, and (if your script uses them) input parameters for a single run. The engine invokes your strategy lifecycle callbacks. Results appear in Test results; OHLCV explains bar shapes.

At the top of the modal body you can Load or Save to reuse a run preset (.qcs). Everything else is grouped into up to three tabs so you can work through the form before you start the backtest.

Run backtest modal tabs

TabWhat you set
ScriptShown only when the script declares params.NAME inputs. Parameter values, plus Optimize (brute-force grid or genetic search). See Input parameters and Optimization.
Symbol & dataPrice feed (Alpaca or QuantCraft B2), symbols, asset type, primary timeframe, additional timeframes for rt.get_bar, optional min bars (Alpaca), Include fundamentals, and Include Fama-French factors (Premium / free-data when available).
SimulationStart / end date, warmup bars, starting balance, commission and slippage models. See Account model.

Clock / primary symbol: There is no primary-symbol control in the modal. The bar clock uses a SYMBOL constant in your script (if that ticker is in the loaded list), otherwise the first loaded symbol. See Strategy lifecycle.

Timer / on_timer: The Run backtest modal does not set a timer interval. on_timer is for forward / bulk / chart-forward runs that expose a timer control — not IDE backtests.


Price source (Alpaca vs. B2)

On the Symbol & data tab, choose the price feed:

  • Alpaca — intraday and daily-style Alpaca timeframes are available (requires Alpaca connectivity / credentials as configured in the app).
  • QuantCraft B2 — only daily (d), weekly (w), and monthly (m) OHLCV timeframes are available. You must be signed in to QuantCraft so a session token can be sent for B2 OHLCV (and for fundamentals when enabled).

The choice is saved in run presets (.qcs) as ohlcvSource ("alpaca" or "b2").


Bar timeframe and asset class (Alpaca only)

When the price source is Alpaca, you can set:

FieldPurpose
Bar timeframeCandle resolution for the run — e.g. 1 Day, 1 Hour, 4 Hour, 1 Week, and several minute bars (1 / 5 / 15 / 30 min).
Asset classUS equity or Crypto — drives which symbol list you search and how Alpaca fetches data.
Min bars (optional)If set, after the date range is applied the engine keeps only the N most recent bars. Leave empty to use the full range implied by your start and end dates.

When the price source is B2, you only choose B2 timeframe: Daily, Weekly, or Monthly (no intraday on B2).


Additional timeframes (optional)

Use Additional timeframes on Symbol & data to load extra bar sizes alongside your primary timeframe. In strategy code, read them with rt.get_bar(Timeframe.X, shift) — see OHLCV and bar data and Strategy lifecycle.

  • Multi-select any extra timeframes your strategy needs (e.g. daily when your primary bar is 5-minute).
  • The primary timeframe is also available via rt.get_bar without listing it under Additional timeframes.
  • Returns None if that timeframe has no buffer for the run or data is unavailable.
  • Settings can be saved in run presets (.qcs) under secondaryTimeframes.

Symbols

On Symbol & data, choose one or more tickers for the run:

  • With Alpaca, the list comes from your Alpaca asset universe (equity vs. crypto follows Asset class). You can search and multi-select.
  • With B2, the list comes from the same catalog as fundamentals paths on the server.

Rules:

  • At least one symbol is required.
  • Symbols are normalized to uppercase for the run.
  • Valid characters: letters, digits, . and - (typical for exchange suffixes like BRK.B or RHM.XETRA).

The first symbol in your selection order is the default clock symbol unless your strategy sets a top-level SYMBOL = "..." that matches a loaded ticker. The modal has no separate primary-symbol control.


Fundamentals (optional)

On Symbol & data, check Include fundamentals when your strategy reads the fundamentals argument in on_bar / on_tick (backtest), or in on_timer on a forward run, or uses fundamentals-aware logic.

The checkbox is available for Premium users (or when free-data access is enabled) and when fundamentals features are turned on for your build. When fundamentals are on:

  • You must be signed in (QuantCraft token is sent to load B2 fundamentals files).
  • Pick one or more fundamentals bundles from the multi-select (paths like fundamentals/AAPL.json.gz). The dialog shows the normalized path under each selection.

Important: OHLCV symbols and fundamentals symbols are independent. You can backtest RNMBY on Alpaca while loading RHM.XETRA fundamentals — the UI reminds you that in that case you must pass the correct ticker into fundamentals.current(..., symbol="RHM.XETRA") (or equivalent) in code.

When multiple fundamentals bundles are selected, the engine builds a per-path map. The primary fundamentals bundle used for bar-aligned snapshots defaults to the first OHLCV symbol in your symbol list unless the engine applies another rule; use explicit symbol= on fundamentals.current / get_data_with_offset when you need a specific bundle.


Fama-French factors (optional)

On Symbol & data, tick Include Fama-French factors (global) when your strategy reads global monthly factor returns via fama_french.qc. See Fama-French factors for the full API.

When factors are on:

  • You need Premium (or free-data access when enabled) and must be signed in.
  • The checkbox is on by default when the data gate allows it. Uncheck to skip factor data for that run.
  • OHLCV symbols, fundamentals bundles, and Fama-French factors are independent — enable any combination you need.
  • There is no factors= callback argument — import quantcraft.fama_french and read fama_french.qc inside callbacks (on_init, on_bar, on_tick, …).

Simulation — dates, balance, and fill costs

All of the following live on the Simulation tab:

FieldPurpose
Start dateRequired. First UTC calendar day included in the execution window (YYYY-MM-DD).
End dateRequired. Last UTC calendar day included. Must be on or after the start date.
Warmup bars (indicators)Extra bars loaded before the start date (same timeframe as your bars) so moving averages and similar indicators have history. Callbacks still run only between start and end dates. Default is 45; enter 0 to disable extra warmup.
Starting balanceRequired. Initial cash for the simulated PaperAccount.
Commission / slippageHow fills are adjusted for trading costs — see below and Account model.

The Run backtest modal does not configure a timer interval. on_timer is only available on forward runs (chart forward test, bulk forward / Quant Cloud) when timerIntervalMs is set. See Strategy lifecycle.

Optional default stop-loss / take-profit / risk sizing can still appear in .qcs presets when present, but the Run backtest modal does not currently expose SL/TP / risk inputs. Configure those in code or via presets if your helpers support them — see Account model and Run presets (.qcs).

Commission and slippage

SettingPurpose
Commission modelPer share (default), per trade, or zero
Commission costCost per share or flat fee per order ($) — default per-share cost is often 0 until you set a non-zero value
Minimum trade costFloor per order when using per-share commission ($)
Slippage modelVolume share (default), fixed spread, or zero
Volume limit / Price impactVolume-share slippage parameters (volume_limit also caps fill qty)
SpreadTotal spread per share for fixed-spread slippage ($)

Simulation settings can be saved in run presets (.qcs).


Script parameters (single run)

If your strategy imports from quantcraft.inputs import params (legacy from ide.inputs_module import params or from quantcraft.inputs_module import params still works) and references params.NAME, the dialog shows a Script tab with one row per discovered name: Parameter, Type (int / float / str / bool), and Value.

Fill every row before you start — values are required for each declared parameter. They are sent on the wire as strings and coerced by the engine before your file loads, so params.PERIOD (for example) is already the correct Python type when your module executes.

On the same tab you can enable Optimize for grid or genetic search — see Optimization. Leave Optimize unchecked for a normal single backtest.


What happens when you start the run

The app validates the form (dates, symbols, balance, fundamentals if enabled, and script parameter types). On success it starts one backtest with the assembled configuration; progress and logs appear in the Output panel, and structured results open in Test Results.


Quick reference

TopicWhere it’s set
Alpaca vs. B2 pricesSymbol & data → price feed (ohlcvSource in .qcs).
TimeframePrimary timeframe (Alpaca) or B2 timeframe (d / w / m only).
Additional timeframesAdditional timeframes multi-select — for rt.get_bar(Timeframe.X, shift).
Asset classUS equity / Crypto (Alpaca only).
Truncate to last N barsMin bars (Alpaca only, optional).
What to tradeSymbols (multi-select on Symbol & data).
Clock symbolScript SYMBOL if loaded; else first symbol (no modal control).
Financial statementsInclude fundamentals + fundamentals multi-select; requires sign-in.
Global factor returnsInclude Fama-French factors (global) — see Fama-French factors.
Calendar windowStart date / End date on Simulation (required).
Indicator history before startWarmup bars on Simulation.
Starting cashStarting balance on Simulation.
Commission / slippageSimulation tab — see Account model.
on_timerNot in Run backtest — forward runs with timerIntervalMs (Strategy lifecycle).
on_tickBacktest: four synthetic OHLC ticks per bar (no real tick history). Forward runs: every broker price update — see Strategy lifecycle.
Tunables in codeScript tab (params.*), single values per run (or Optimize).

Tips

  • If Alpaca symbols never load, open Trade once or confirm Alpaca connectivity; for B2, confirm you’re signed in and the symbol catalog loaded.
  • Warmup only extends loaded history — it does not add trading days outside your date range.
  • Do not expect on_timer in the IDE backtest — there is no timer control on that modal. Use on_bar / on_tick instead. Timers apply on forward runs when timerIntervalMs is configured.
  • on_tick in backtest uses synthetic OHLC from each bar (four calls per bar) — not real tick data. Test live tick logic on forward runs (Strategy lifecycle).
  • Match fundamentals bundles to the tickers you actually read in code when OHLCV and fundamentals tickers differ.
  • Use Min bars sparingly — it is easy to accidentally shorten a run more than you intended.