Skip to content
Level 3 · AFL DeveloperLessonPart 10 · page 4 of 830 min
30Minutes
16AFL functions
11Sources
StandardRequires
AFL functions taught here16

Parameters: Param, ParamToggle, ParamList and ParamColor

An indicator you have to edit in order to change is a script. An indicator whose settings live in a dialog is a tool. The difference is the Param* family, and getting it right takes about twenty minutes of learning that will save you years of opening the Formula Editor to change a number from 20 to 21.

Press Ctrl+R over any chart pane and the Parameters dialog opens, showing every Param* call in that pane’s formula. Move a slider and the formula re-runs immediately.

Every one of these is copied from the official function pages. The return types are the part people get wrong.

Function Signature Returns
Param Param( name, defaultval, min, max, step, sincr = 0 ) NUMBER
ParamStr ParamStr( name, default ) STRING
ParamColor ParamColor( name, defaultcolor ) NUMBER
ParamStyle ParamStyle( name, defaultstyle = styleLine, mask = maskDefault ) NUMBER
ParamField ParamField( name, field = 3 ) ARRAY
ParamToggle ParamToggle( name, values, defaultval = 0 ) NUMBER
ParamList ParamList( Name, Values, defaultval = 0 ) STRING
ParamDate ParamDate( Name, "default date", format = 0 ) NUMBER or STRING
ParamTime ParamTime( Name, "default time", format = 0 ) NUMBER or STRING
ParamTrigger ParamTrigger( Name, "Button text" ) NUMBER

Two rules apply to all of them. Parameter names and values must not contain non-printable characters — codes below ASCII 32. And the default, min, max and step arguments must be constant numbers: they are cached and are not re-read on later evaluations, so feeding them a variable gives silently stale slider bounds.

Fragment — not a complete formula

MaPeriod = Param( "Periods", 50, 2, 400, 1, 10 );

Name, default, minimum, maximum, step, and then the sixth argument almost nobody uses: sincr, the section increment. When the same drag-and-drop section is dropped into a pane more than once, each new copy’s default is bumped by this amount. AmiBroker’s own moving average ships with a default of 15 and an increment of 10, so dropping it twice gives you a 15-period average and a 25-period one rather than two identical lines.

The dialog cannot exceed the max you coded. If you want Bollinger periods above 100 you have to raise the number in the formula; there is no user-facing override.

Fragment — not a complete formula

ShowBands = ParamToggle( "Bands", "Hide|Show", 1 );
if( ShowBands ) { /* draw them */ }

The values argument is required and holds the two display labels separated by a pipe, with the first label meaning false and the second meaning true. The function returns a NUMBER — 0 or 1. The labels are decoration.

The single most common ParamToggle mistake is comparing the result against text: if( ShowBands == "Show" ) is always false. Treat it as the Boolean it is.

Fragment — not a complete formula

AverageName = ParamList( "Average", "Simple|Exponential|Weighted", 0 );

Here the return really is a STRING — the label the user chose, not its index. Meanwhile the third argument is an index: the zero-based position of the default item. Getting those two backwards is the classic ParamList bug, and it fails quietly, because comparing a string against a number simply never matches.

The delimiter is documented as “| or comma separated”, so both work. The corollary is that a choice label cannot itself contain a comma or a pipe.

Fragment — not a complete formula

LineTint = ParamColor( "Line colour", colorCycle );

colorCycle is a special default accepted only by ParamColor. It makes each newly dropped copy of a section pick the next colour in a fixed rotation — the colour equivalent of Param’s sincr. Do not pass it to Plot(); that is not documented behaviour.

Fragment — not a complete formula

LineStyle = ParamStyle( "Style", styleLine | styleThick, maskDefault );

The mask argument decides which style flags appear in the drop-down. maskDefault offers thick, dashed, hidden and own scale; maskPrice adds candle and bar; maskHistogram offers histogram and area; maskAll offers everything. If a style you expect is missing from the list, the mask is why.

Two arguments only: name and default string. There is no validation, so a mistyped ticker handed to Foreign() or PlotForeign() simply produces nothing rather than an error.

Fragment — not a complete formula

Source = ParamField( "Price field", 3 );
MyAverage = MA( Source, 20 );

ParamField is the only member of the family that returns an ARRAY — the chosen data series itself. The field argument selects the default: 0 Open, 1 High, 2 Low, 3 Close (the default), 4 the average of high, low and close, 5 Volume, 6 Open Interest, and 7 upwards the indicators already inserted into the pane, in insertion order.

The value −1 is the interesting one. It means “the first indicator inserted into this pane, or Close if there is none”, and it is what makes drag-and-drop chaining work — dropping a moving average onto an RSI pane gives you an average of the RSI. Hard-coding 3 breaks that behaviour for anyone who uses your formula the way AmiBroker intends.

Fragment — not a complete formula

Rebuild = ParamTrigger( "Maintenance", "Rebuild cache" );
if( Rebuild )
{
// Runs exactly once, on the refresh caused by the button press.
}

ParamTrigger normally returns 0. When the button is pressed it refreshes the chart and returns 1 for that single execution only; every later refresh returns 0 again. That makes it a one-shot action, not a switch. Anything that has to persist beyond that one execution has to be written somewhere persistent, which in AFL means a static variable — covered in Part 11.

Guard it carefully. A chart pane is re-evaluated for many reasons: a new tick, a zoom, a symbol change. The trigger returning 1 is tied to the press, but the side effect you perform is not automatically safe to repeat.

Both take their default as a string and return a number by default, which is the first trap. ParamDate format 0 returns a DateNum such as 990503; format 2, added in AmiBroker 6.20, returns a DateTime you can compare against the built-in DateTime() array. ParamTime has no format 2 — assuming symmetry with ParamDate is a real mistake — and its format 0 returns a TimeNum, so 09:30 becomes 93000.

Fragment — not a complete formula

_SECTION_BEGIN( "Configurable MA" );
// every Param* call in here belongs to this section
_SECTION_END();

AmiBroker identifies a parameter by section name plus parameter name. That is what lets you drop two moving averages into one pane and have two independent “Periods” sliders: the second section is auto-named MA1, so the two parameters have different full names.

The section name must be a literal string in double quotes. _SECTION_BEGIN( "MA" + i ) is invalid, which rules out generating sections in a loop.

Two helpers exist for naming plots from within a section. _DEFAULT_NAME() returns the section name followed by the values of its numeric parameters — for a section named MA1 containing a price field and a 15-period setting, it evaluates to "MA1(Close,15)". _PARAM_VALUES() returns just the bracketed list, so you can supply your own prefix. Both are evaluated when the formula runs, so a title built from them tracks the sliders automatically.

This is the behaviour that costs people the most time, and it has a simple mechanical cause.

Parameter values are stored per Chart ID — the read-only field you can see on the Axes & Grid tab of the Parameters dialog — in a file called broker.params. And GetChartID() is officially documented as returning 0 in Automatic Analysis.

Where a parameter value comes from

  1. Param() callname + section
  2. Chart IDthe pane, or 0 in Analysis
  3. broker.paramsstored value for that pair
  4. Value returnedor the coded default if none
Two panes running the same formula have different Chart IDs, so they hold different values.

Three consequences follow:

  1. The values you set on a chart pane have no effect on a Scan, Exploration, Backtest or Optimization. The Analysis window has its own Parameters control, and you must set them there as well. This is the second item on AmiBroker’s own checklist for “why do my Analysis results differ from my chart?”.
  2. Because every Analysis run shares Chart ID 0, two different formulas run from Analysis windows that happen to use the same parameter name share the same stored value. Distinctive names, or sections, prevent that.
  3. Two chart panes running the same formula are genuinely independent. That is a feature — it is how you compare a 20-period and a 200-period version side by side — but it also means “I changed it and nothing happened” usually means you changed it on the other pane.

They look similar and do opposite things.

Fragment — not a complete formula

// Adjustable from a dialog. Constant during an optimisation run.
MaPeriod = Param( "Periods", 50, 2, 400, 1 );
// Swept by the optimiser. No dialog control at all.
MaPeriod = Optimize( "Periods", 50, 2, 400, 1 );

During an Optimization, Param() keeps returning whatever the Analysis window’s parameter set holds — it does not vary. Only Optimize() sweeps. A formula built entirely on Param() and then “optimised” produces N identical rows, which is a memorable way to discover the difference.

Having every control available is not the same as using them well. A few principles that hold up in practice:

Expose what you would actually change; hide what you would not. Each slider is a decision the user now has to make. A tool with four meaningful settings is more usable than one with fourteen, and far more usable than one with fourteen where three of them interact.

Make the defaults the ones you would use. A formula that draws nothing useful until three parameters are adjusted will be deleted before anybody adjusts them.

Choose ranges that mean something. A period slider running 2–400 with a step of 1 offers 399 choices, most of which nobody wants. Setting the minimum to something the maths supports — 2 for an average, 1 for ATR — prevents the user producing a nonsense chart and blaming you.

Pick the right control type. A finite set of named alternatives is a ParamList, not a Param running 1–6 that the user has to decode. An on/off is a ParamToggle, not a Param running 0–1.

Do not let a parameter silently change what a number means. If one setting switches an output between points and percent, the title must say which is on screen. A parameter that changes the meaning of a displayed value without changing its label is how people misread their own tools.

A small study that exercises every control type in one section: a price field, a period, a band width, an averaging method chosen from a list, an on/off for the bands, a colour, a style, and a free-text symbol to overlay. The point is not the study — it is seeing all eight controls appear in one Parameters dialog and knowing which type each returns.

Complete runnable AFL

parameter-set-demo.afl
/*
* Every parameter control in one section - worked example for Part 10.
*
* Assumptions
* - Chart pane formula. Press Ctrl+R over the pane to open the Parameters
* dialog; every control below appears there, grouped under the section
* name given to _SECTION_BEGIN.
* - The bands are a dispersion measure, not a forecast. They say how far
* price has recently wandered from its own average, nothing more.
* - StDev's third argument exists from AmiBroker 6.20 onwards.
*/
_SECTION_BEGIN( "Parameter showcase" );
// ParamField returns an ARRAY - the only member of the family that does.
// Field 3 is Close; field -1 chains onto whatever was plotted into the pane
// first, which is how dropping an average onto an RSI pane averages the RSI.
Source = ParamField( "Price field", 3 );
// Param( name, default, min, max, step, sincr )
// The sixth argument bumps the default each time the section is dropped into
// the same pane again, so two copies do not land on the same period.
Periods = Param( "Periods", 20, 2, 300, 1, 10 );
// ParamList returns the chosen label as a STRING. The third argument is the
// zero-based position of the default item, not the default text.
AverageName = ParamList( "Average", "Simple|Exponential|Weighted", 0 );
// ParamToggle returns a NUMBER, 0 or 1. The two labels are display text only -
// never compare the result against "Show".
ShowBands = ParamToggle( "Bands", "Hide|Show", 1 );
BandWidth = Param( "Band width (standard deviations)", 2, 0.5, 4, 0.1 );
// ParamColor and ParamStyle feed Plot()'s colour and style arguments directly.
// colorCycle is accepted only as a ParamColor default.
LineTint = ParamColor( "Line colour", colorCycle );
LineStyle = ParamStyle( "Line style", styleLine | styleThick, maskDefault );
// ParamStr returns a STRING with no validation, so a mistyped ticker simply
// draws nothing.
Benchmark = ParamStr( "Overlay symbol (blank for none)", "" );
if( AverageName == "Exponential" ) Centre = EMA( Source, Periods );
else if( AverageName == "Weighted" ) Centre = WMA( Source, Periods );
else Centre = MA( Source, Periods );
Plot( Close, "Price", colorDefault, styleCandle | styleNoTitle );
// _DEFAULT_NAME() builds "section name (field, periods, ...)" from the numeric
// parameters in this section, so a duplicated section labels itself correctly.
Plot( Centre, _DEFAULT_NAME(), LineTint, LineStyle );
if( ShowBands )
{
// False asks for the sample standard deviation; the documented default,
// True, is the population form that matches Excel's STDEV.P.
Spread = BandWidth * StDev( Source, Periods, False );
BandTint = ColorBlend( LineTint, GetChartBkColor(), 0.4 );
Plot( Centre + Spread, "Upper", BandTint, styleLine | styleDashed );
Plot( Centre - Spread, "Lower", BandTint, styleLine | styleDashed );
}
if( Benchmark != "" )
PlotForeign( Benchmark, Benchmark, colorGrey40,
styleLine | styleOwnScale | styleNoLabel );
_N( Title = StrFormat( "%s %s average, %g periods value %g",
Name(), AverageName, Periods, SelectedValue( Centre ) ) );
_SECTION_END();

Download parameter-set-demo.afl71 lines

Every parameter is declared at the top, before any calculation, which is the convention worth adopting: a reader can see the whole configurable surface of a formula in one screen.

Source comes from ParamField, so it is an array and can be fed straight into EMA, WMA or MA. AverageName comes from ParamList, so it is text and is compared with == against the labels declared in the same call — a discipline worth keeping, since a typo in one of them silently sends every case to the fallback branch.

ShowBands is a number and therefore usable in if(). The bands themselves are the average plus and minus a multiple of the standard deviation, with False passed as StDev’s third argument to request the sample form rather than the documented default, which is the population form matching Excel’s STDEV.P.

The plot name is _DEFAULT_NAME(), so the title shows the section name and the current numeric parameter values without any string building.

The overlay at the end shows why ParamStr needs care: an empty default means “no overlay”, and a mistyped symbol produces nothing at all rather than an error message.

  • ParamField( name, field ) — returns the chosen price series as an array; -1 chains onto the first indicator already in the pane.
  • _DEFAULT_NAME() — section name plus current numeric parameter values, as a string.
  • StDev( array, periods, Population )True, the default, is the population form.
  • PlotForeign( ticker, name, color, style ) — overlays another symbol without calling Foreign() first. Note its default style includes styleOwnScale.

Press Ctrl+R and the dialog shows one section, “Parameter showcase”, containing a price-field chooser, two sliders, a drop-down, a two-state toggle, a colour swatch, a style drop-down and a text field. Changing any of them redraws the chart immediately.

  1. Change the average from Simple to Exponential and watch the line move. Then set the period to 2 and confirm both methods converge on price, which they must.
  2. Drop the same formula into the same pane a second time. The two sections should be named differently and their sliders should be independent.
  3. Open an Analysis window, apply this formula, and open its own Parameters. Note that the values there start from the coded defaults, not from whatever you set on the chart.
  4. Set the overlay symbol to something that does not exist in your database. Nothing should be drawn, and no error should appear — which is exactly why a typo here is hard to spot.
  • A parameter change does nothing. You changed it on a different pane, or in the chart while the formula is running in Analysis.
  • ParamList comparison never matches. The compared text does not exactly match a label in the Values string, including capitalisation and spaces.
  • The style drop-down is missing candles. The mask is maskDefault; use maskPrice or maskAll.
  • Sliders reset unexpectedly. A _SECTION_BEGIN marker was deleted or renamed, so the stored values no longer match the parameter’s full name.
  • The optimiser reports identical results for every step. The formula uses Param() where it needs Optimize().

Add a ParamTrigger button labelled “Reset view” and, inside its if block, call SetChartOptions to restore automatic scaling. Then observe the one-shot behaviour: the block runs on the press and not on the next refresh. That is the whole of ParamTrigger’s contract.

You now know all ten Param* functions, their exact argument orders and — more importantly — their return types, which are what determine whether a value can go into an if, a Plot() colour slot or a MA() call. You know that parameters are keyed by Chart ID, that Analysis runs under Chart ID 0 and therefore keeps its own values, and that Param() and Optimize() are not substitutes for each other.

That is the last piece of machinery. The next four pages build real tools with it.

Check your understanding

Question 1. What does this expression evaluate to when the user has selected "Weighted"?
AverageName = ParamList( "Average", "Simple|Exponential|Weighted", 0 );
Show the answer and why

Answer: The string "Weighted"

ParamList returns the chosen label as a STRING. The third argument is the zero-based index of the default item, which is the part that is a number.

Question 2. Which Param* function returns an ARRAY?
Show the answer and why

Answer: ParamField

ParamField returns the chosen data series itself, which is why it can be passed straight to MA(). Every other member returns a NUMBER or a STRING.

Question 3. You set a period to 30 on your chart, then run the same formula as an Exploration. Which period does the Exploration use?
Show the answer and why

Answer: Whatever the Analysis window’s own parameter set holds, which starts from the coded default

Parameter values are stored per Chart ID, and GetChartID() returns 0 in Automatic Analysis. The Analysis window therefore keeps a completely separate parameter set, which you set through its own Parameters control.

Question 4. ParamOptimize() is a built-in AFL function.
Show the answer and why

Answer: False

Its documentation page returns 404 and it appears in neither official index. The widely circulated version is a user-defined helper posted in a comment on the Optimize page; you must paste it into your own formula.

Question 5. Which of these are legitimate reasons a Parameters slider will not go above 100? Select all that apply.
Show the answer and why

Answer: The max argument in the Param() call is 100, The dialog cannot exceed the coded maximum, so the formula must be edited

The coded max is the ceiling and the dialog cannot exceed it; raising a built-in indicator’s limit means editing the formula. There is no global cap, and step does not impose one.

Sources for this lesson

11 verified · checked 2026-08-31

  1. 01AFL Function Reference — Paramamibroker.com/guide/afl/param.html2026-08-31
  2. 02AFL Function Reference — ParamToggleamibroker.com/guide/afl/paramtoggle.html2026-08-31
  3. 03AFL Function Reference — ParamListamibroker.com/guide/afl/paramlist.html2026-08-31
  4. 04AFL Function Reference — ParamColoramibroker.com/guide/afl/paramcolor.html2026-08-31
  5. 05AFL Function Reference — ParamFieldamibroker.com/guide/afl/paramfield.html2026-08-31
  6. 06AFL Function Reference — ParamStyleamibroker.com/guide/afl/paramstyle.html2026-08-31
  7. 07AFL Function Reference — ParamTriggeramibroker.com/guide/afl/paramtrigger.html2026-08-31
  8. 08AFL Function Reference — GetChartIDamibroker.com/guide/afl/getchartid.html2026-08-31
  9. 09AmiBroker User's Guide — Drag-and-drop indicator buildingamibroker.com/guide/h_dragdrop.html2026-08-31
  10. 10AmiBroker User's Guide — Parameters windowamibroker.com/guide/w_param.html2026-08-31
  11. 11AmiBroker Knowledge Base — Why Analysis results and chart output may differamibroker.com/kb/2015/01/28/why-analysis-results-and-chart-output-may-differ2026-08-31

Every technical claim on this page was checked against the official AmiBroker documentation on the date shown. Where the course disagrees with folklore, the source is how you can tell which one to trust.