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 the Test (backtest) dialog — without editing the file every time you want to try a new number. Test is described in Running code; multi-run sweeps are covered under Optimization. Params are read during Backtests, not plain Run.
This page covers the two halves of that flow:
- Declaring
paramsin your Python file - Wiring those params to the Test / backtest modal so you can set, save, and optimize them
How it works at a glance
- In your strategy file, you import a special
paramsobject and read attributes off it (e.g.params.PERIOD). - The IDE scans your code to discover those names and lists them in the Test dialog.
- You enter a type and value for each name in the dialog (or define a sweep when you optimize).
- When you click Test, the engine fills
paramswith your values before your script runs, so the values are available the moment your file is imported.
Inputs are populated only for backtests (the Test button). They are not populated for plain Run — use plain Python defaults if you want a runnable script outside backtests. See Strategy lifecycle for when
paramsare visible to callbacks.
Declaring params in your strategy
Add a single import and reference each parameter name as an attribute on params:
from ide.inputs_module import params
PERIOD = params.PERIOD
MAX_OPEN_LONGS = params.MAX_OPEN_LONGS
USE_FILTER = params.USE_FILTER
LABEL = params.LABELA few rules apply:
- The import must be
from ide.inputs_module import paramsexactly (whitespace is OK). The IDE looks for this line specifically. - Each parameter name must be a valid Python identifier (
A–Z,a–z,0–9,_, not starting with a digit). - You can use
params.NAMEanywhere in the file — top‑level, insideon_init, insideon_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.
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. 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:
| Column | What you enter |
|---|---|
| Parameter | The name (read-only — comes from your code). |
| Type | One of int, float, str, bool. |
| Value | The value to use for the run. |
Notes on Type choices:
int— whole numbers (e.g.14).float— decimals (e.g.0.5,1e-3); commas in numbers are stripped.bool— acceptstrue/false,yes/no,y/n,on/off, and1/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 ide.inputs_module import params
PERIOD = params.PERIOD # <- already filled by the time this line executesIf 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 reading it will raise AttributeError. Add the row in the dialog and re‑run — or fall back with getattr(params, "NAME", default).
Your dialog values are remembered between runs, so you don’t need to retype them every time.
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— bothtrueandfalseare 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 (
0–1) — chance two parents produce a mixed child. - Mutation rate (
0–1) — 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.NAMEreferences and that the import line matches exactly. -
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
intfor a value like0.5). -
Booleans aren’t case-sensitive —
True,true,1,yesall evaluate to true. -
Use Optimize for parameter searches, not editor scripts: brute force is exhaustive, genetic is for larger spaces.
-
Inputs are backtest‑only: when you click Run,
paramsis not populated. Guard with defaults if you want the same file to be runnable both ways:from ide.inputs_module import params PERIOD = getattr(params, "PERIOD", 14)