Parameters
Parameters
Expose user-tunable inputs — periods, colours, toggles, file paths — that the settings dialog renders, the workspace persists, and the engine uses to tell two indicators apart.
On this page
What a parameter is
A parameter is a public read/write property tagged with [IndicatorParameter] (from
TradeStrike.Pipeline.Indicators). The framework reflects over these to do three things:
- Render an editor. The settings dialog shows one row per attributed property.
- Persist + restore. The value round-trips through the chart template / workspace.
-
Form the content key. The indicator's
ContentKeyis a deterministic hash of its type plus parameter values — soSMA(14)andSMA(50)are distinct instances, and two requests with the same key resolve to the same shared instance (diamond-dependency dedup).
Declaring parameters
declaring parameters[IndicatorParameter(
DisplayName = "Period",
Description = "Number of bars in the lookback window.",
Group = "Parameters",
Order = 0,
MinValue = 1, MaxValue = 5000, Step = 1)]
public int Period { get; set; } = 14;
[IndicatorParameter(DisplayName = "Smoothing", Group = "Parameters", Order = 1)]
public SmoothingMode Smoothing { get; set; } = SmoothingMode.Exponential; // enum -> dropdown
[IndicatorParameter(DisplayName = "Show midline", Group = "Display", Order = 0)]
public bool ShowMidline { get; set; } = true;
DisplayName defaults to the property name; Description becomes the editor
tooltip. MinValue, MaxValue and Step are advisory
— the editor enforces them, but a programmatic assignment honours whatever value the caller
passes. The framework never silently clamps; if you need a hard bound, validate and throw in
OnInit.
Editor types
By default the editor is inferred from the property's CLR type. Override it with the
Editor field (a ParameterEditorKind) when the type alone is ambiguous.
| Property type | Editor |
|---|---|
int / double
|
Numeric spinner (honours Min/Max/Step). |
bool |
Checkbox. |
string |
Text box. |
any enum
|
Dropdown of the enum members. |
ChartColor |
Colour picker. |
string + Editor = ParameterEditorKind.FilePicker
|
Path field + Browse button (use FileFilter for the dialog filter). |
string + Editor = ParameterEditorKind.SymbolPicker
|
Symbol field + Browse into the host's instrument picker (for a benchmark / comparison symbol). |
non-obvious editors[IndicatorParameter(DisplayName = "Blueprint file",
Editor = ParameterEditorKind.FilePicker,
FileFilter = "Blueprint (*.algo)|*.algo|All files (*.*)|*.*")]
public string BlueprintPath { get; set; } = "";
[IndicatorParameter(DisplayName = "Benchmark", Editor = ParameterEditorKind.SymbolPicker)]
public string BenchmarkSymbol { get; set; } = "ES";
Groups and ordering
Group buckets parameters under a header in the dialog (matched by exact string), and
Order sequences rows within a group (lower first; ties fall back to declaration order).
Use a small handful of stable group names — "Parameters", "Display",
"Calculation" — so related controls sit together.
Reading parameters in your code
Read parameter values in OnInit (after base.OnInit), not in the constructor.
The host constructs the indicator, then applies the saved values, then calls OnInit —
so the constructor sees only defaults, while OnInit sees the user's real choices. This is
the place to validate and to size buffers from a period.
validate in OnInitpublic override void OnInit(IIndicatorContext ctx)
{
base.OnInit(ctx);
if (Period < 1)
throw new System.ArgumentOutOfRangeException(nameof(Period), "Period must be >= 1.");
_window = new double[Period]; // allocate state from the resolved parameter
}
When the user edits a math-affecting parameter, the host re-runs OnReset →
OnInit → OnDataLoaded so the whole history recomputes with the new value
— reallocating your buffers in OnInit is what makes that work.
Parameters from a nested object
A large indicator can keep its parameters in a separate, reusable settings POCO instead of scattering
dozens of properties on the indicator. Tag the indicator with
[ParameterContainer(typeof(...))] and implement
IParameterContainerProvider; the platform discovers, edits and persists the container's
tagged properties through the same machinery.
parameter containerpublic sealed class BandSettings
{
[IndicatorParameter(DisplayName = "Width (StdDev)", Group = "Bands")]
public double Width { get; set; } = 2.0;
[IndicatorParameter(DisplayName = "Fill", Group = "Bands")]
public ChartColor Fill { get; set; } = new(33, 150, 243, 40);
}
[ParameterContainer(typeof(BandSettings))]
public sealed class MyBands : IndicatorBase, IParameterContainerProvider
{
public BandSettings Settings { get; } = new();
public object ParameterContainer => Settings; // IParameterContainerProvider
}
Set AllProperties = true on the attribute to surface every persistable public
property of the container as a parameter without tagging each one individually — handy for a
settings object with 100+ fields.
Built-in parameters you inherit
IndicatorBase already declares two parameters every indicator gets for free, grouped under
"Display":
-
ShowPriceMarkers(bool) — a master toggle for this indicator's price-axis labels; off hides every marker regardless of per-plot settings. -
Displacement(int) — shifts the indicator's plots horizontally by N bars (positive = right/future, negative = left/past). It is purely visual: the computed value series is never altered, so alerts and strategies keep reading the true values.