Documentation

Input Parameters

Input parameters let you turn values inside your strategy code (for example a lookback length or a maximum number of open longs) into knobs you set from run modals — without editing the file every time you want to try a new number. The same params wiring applies to Run backtest (Backtests), Bulk forward (Quant Cloud), and Chart forward test algo parameters. Test is described in Running code; multi-run sweeps are covered under Optimization. Params are not populated for plain Run.

This page covers the two halves of that flow:

  • Declaring params in your Python file
  • Wiring those params to run modals so you can set, save, and optimize them (see also Run presets (.qcs))

How it works at a glance

  1. In your strategy file, you import a special params object and read attributes off it (e.g. params.PERIOD).
  2. The IDE scans your code to discover those names and lists them in the run modal (Test, bulk forward, or chart forward).
  3. You enter a type and value for each name in the dialog (or define a sweep when you optimize).
  4. When you start the run, the engine fills params with your values before your script runs, so the values are available the moment your file is imported.

Inputs are populated for Run backtest, Bulk forward, and Chart forward test modals. They are not populated for plain Run (/ws/run) — use hasattr defaults if you want the same file to run both ways. See Strategy lifecycle for when params are visible to callbacks.


Declaring params in your strategy

Add a single import and reference each parameter name as an attribute on params:

from quantcraft.inputs import params PERIOD = params.PERIOD if hasattr(params, "PERIOD") else 14 MAX_OPEN_LONGS = params.MAX_OPEN_LONGS if hasattr(params, "MAX_OPEN_LONGS") else 3 USE_FILTER = params.USE_FILTER if hasattr(params, "USE_FILTER") else True LABEL = params.LABEL if hasattr(params, "LABEL") else "default"

A few rules apply:

  • The import must be from quantcraft.inputs import params (whitespace is OK). Legacy from ide.inputs_module import params and from quantcraft.inputs_module import params still work for existing strategies. The IDE looks for a params import from any of these paths.
  • Each parameter name must be a valid Python identifier (A–Z, a–z, 0–9, _, not starting with a digit).
  • Each input must include a literal params.NAME token in source so the IDE can discover it. The client regex-matches params.<identifier>; names referenced only via getattr(params, "NAME", default) are not discovered and will not appear in the Script Parameters form.
  • You can use params.NAME anywhere in the file — top‑level, inside on_init, inside on_bar, etc. Each unique reference becomes one input the dialog will ask you about.
  • There is no schema in the module itself — the names you reference are the schema.

Avoid (form will not list the parameter):

MA_PERIOD = getattr(params, "MA_PERIOD", 24) # no params.MA_PERIOD token PERIOD = 14 # no params reference

Common idioms:

def on_init(): global lookback lookback = int(params.PERIOD) def on_bar(bar_index, bar, fundamentals=None, symbol=None): if bar.bars_back < lookback: return ...

Tip: read the value once into a local/global so you don’t pay attribute lookups on every bar.


Wiring the Test / backtest modal

Open the Test dialog from the editor toolbar (the Test button) and look for the Script Parameters & Optimization (ide.inputs_module) section. This section appears when your file imports params from quantcraft.inputs, quantcraft.inputs_module, or ide.inputs_module. The IDE has already scanned your active file for params.NAME references, so each parameter you used appears as a row.

For each row you set:

ColumnWhat you enter
ParameterThe name (read-only — comes from your code).
TypeOne of int, float, str, bool (aliases integer, number, boolean are also accepted on the wire).
ValueThe value to use for the run.

Notes on Type choices:

  • int / integer — whole numbers (e.g. 14).
  • float / number — decimals (e.g. 0.5, 1e-3); commas in numbers are stripped.
  • bool / boolean — accepts true / false, yes / no, y / n, on / off, and 1 / 0.
  • str — free text, kept as-is (trimmed of surrounding whitespace).

When you click Test, the dialog packages your rows and sends them to the engine. The engine sets the values on params before your on_init() runs, so:

from quantcraft.inputs import params PERIOD = params.PERIOD # <- already filled by the time this line executes

If a parameter name has no row in the dialog (you removed the dialog entry, or your file references a brand‑new name you haven’t set yet), params won’t have that attribute and a bare params.NAME read will raise AttributeError. Add the row in the dialog and re‑run — or use the hasattr + else default pattern shown above (which still includes the params.NAME token for discovery).

Your dialog values are remembered between runs, so you don’t need to retype them every time. Save and reload full parameter sets with Run presets (.qcs).


Optimizing parameters

The same dialog can drive an optimization that runs your strategy many times with different parameter combinations. Tick Optimize script parameters (brute grid or genetic search) and pick a mode:

Brute force

For each parameter row, the dialog adds Step and Max columns where it makes sense:

  • int / float — define a discrete grid: start value → step → max.
  • bool — both true and false are tried.
  • str — kept fixed (string parameters don’t form a grid).

The engine runs every combination of those discrete values and reports each run separately in the Test Results view.

Useful for small grids (a handful of parameters with a few values each). Combinations explode quickly — keep your search space modest.

Genetic

For larger search spaces, switch to Genetic to let an evolutionary search find good combinations without trying every cell:

  • Population size — number of parameter combinations evaluated each generation.
  • Generations — how many generations to run (each is one full population of backtests).
  • Elitism — top individuals copied unchanged into the next generation.
  • Crossover rate (01) — chance two parents produce a mixed child.
  • Mutation rate (01) — chance a gene jumps to another value.
  • Fitness metric — which metric to optimize (Sharpe, Sortino, total return, etc.).
  • Random seed (optional) — reproducibility of the population and operators.

Both modes show live progress in the Output Panel (a progress bar in the header) and a Stop button so you can end a long run.

When optimization finishes, the Test Results view shows the runs sorted by your fitness metric, and you can drill into each one.


Tips

  • Names are discovered from your file: if a row doesn’t appear, double‑check your params.NAME references and that you import params from quantcraft.inputs, quantcraft.inputs_module, or ide.inputs_module.

  • Keep names UPPER_SNAKE_CASE — by convention they read as constants in your code.

  • Provide sensible types in the dialog so coercion does what you expect (e.g. don’t set int for a value like 0.5).

  • Booleans aren’t case-sensitiveTrue, true, 1, yes all evaluate to true.

  • Use Optimize for parameter searches, not editor scripts: brute force is exhaustive, genetic is for larger spaces.

  • Plain Run does not populate params: when you click Run, params is not filled. Use hasattr defaults (with a literal params.NAME token) if you want the same file to work for both Run and Test:

    from quantcraft.inputs import params PERIOD = params.PERIOD if hasattr(params, "PERIOD") else 14
  • Forward runs use the same discovery rules — bulk forward and chart forward modals scan for params.NAME the same way as the backtest dialog.