Skip to main content

Indicator Settings

TradeScript settings modal with configurable chart and indicator controls
Settings resolve from indicator defaults through application defaults, saved state, and runtime changes; the precedence list below shows which value wins.

Five sources can set the same indicator input or style: indicator defaults, application defaults, the options passed when the instance is added, runtime updates, and per-bar colors. Only one wins a contested field, and only some of them survive a reload.

Which value wins

The sources below are ordered from lowest to highest priority. A later source overrides the same key from any earlier source.

  1. Indicator or catalog defaults — defaults declared by the indicator, including input.*, plot.*, and built-in catalog defaults.
  2. Application defaults for future indicatorssetBuiltInIndicatorDefaults or setIndicatorDefaults.
  3. Options supplied while adding an indicator — inputs and styles passed to addIndicator or addBuiltInIndicator.
  4. Changes to an existing indicatorupdateIndicator, updateBuiltInIndicatorProperties, or an indicator handle's updateProperties.
  5. Per-bar colors declared by the indicatorplot.colors and plot.barcolor; these paint over static styles for their individual bars.

Worked example — every layer sets EMA length or line width:

const ui = chart.customization()

// Application defaults for every EMA added after this call
ui.setBuiltInIndicatorDefaults('EMA', {
inputs: { length: 21 },
styles: { line: { color: '#38bdf8', width: 2 } },
})

// Add options win over the defaults
const id = chart.addBuiltInIndicator('EMA', {
inputs: { length: 50 }, // wins over the default 21
styles: { line: { width: 4 } }, // wins over the default 2; color stays #38bdf8
})

// An instance update wins over everything set at add time
chart.updateIndicator(id, { inputs: { length: 100 } }) // final length: 100

Defaults apply only to indicators created after the call. Existing instances keep their current state until you update them directly.

Persistence — settings survive reload

Instance state (inputs, styles, visibility, pane placement, axisLabelVisible) lives on the indicator instance and serializes into ChartState.indicators via getState() / setState(), alongside drawings and alerts. A user's Settings-dialog edits are instance state, so they survive reload whenever the host persists and restores chart state.

Verify the round-trip:

chart.updateIndicator(id, { inputs: { length: 50 } }) // simulate a user edit
const saved = chart.getState()

// ... new session: recreate the widget, then restore ...
chart.setState(saved)
chart.getIndicators().find((i) => i.id === id)?.inputs // → includes { length: 50 }

Application defaults for future indicators are chart customization state, not instance state — re-apply them at startup or persist them with your customization handling.


Initial defaults

Authoring inputs (indicator side)

input.int('Length', 14, {
id: 'length',
min: 1,
max: 500,
group: 'Params',
tooltip: 'Lookback bars',
})
  • Integer — input.int
  • Float — input.number
  • Boolean — input.bool
  • Series source — input.source
  • Color — input.color
  • Enum — input.select
  • Text — input.text
  • Symbol — input.symbol

Always set id. Optional group / tooltip feed Settings chrome. Author plot options (plot.line(..., { color, width, style })) become the chart's default visual settings.

Application defaults for future instances

LayerHow
Author defaultsplot.line(..., { color, width, style })
Future built-in indicator defaultschart.customization().setBuiltInIndicatorDefaults(id, { inputs, styles, paneId, paneHeight, visible, priceScale })
Future custom indicator defaultschart.customization().setIndicatorDefaults(name, { inputs, styles, paneId, paneHeight, visible, priceScale })
Global overrideschart.customization().applyStyleOverrides({ indicators: … })

Use setBuiltInIndicatorDefaults(id, defaults) for future built-in indicators. Use inspectBuiltInIndicatorDefaults(id, defaults) when a Settings UI needs feedback before submitting defaults. Unknown input ids, invalid values, unknown style ids, invalid pane heights, invalid price-scale placements, and non-boolean visibility values are reported as diagnostics. Custom indicator names can define their own inputs and styles through setIndicatorDefaults(...).

For built-in indicators, use the Built-in Indicator Reference for exact inputs.* and styles.* paths.


Runtime changes

The definition you patch

When you call addIndicator / updateIndicator:

export interface IndicatorDefinition {
id?: string
name: string
paneId?: string
paneHeight?: number
priceScale?: 'as-series' | 'new-left' | 'new-right' | 'no-scale'
visible?: boolean
axisLabelVisible?: boolean // plot values on the price axis
inputs?: Record<string, unknown> // by input id / key
styles?: Record<string, unknown>
securities?: Record<string, SecuritySeries>
}

Inputs

Keys match authoring id:

// Indicator:
input.int('Length', 14, { id: 'length' })

// Host:
chart.addIndicator({ name, inputs: { length: 21 } })
chart.updateIndicator(id, { inputs: { length: 50 } })

Use an object keyed by the input ids you declared. This keeps settings readable and stable when you add or reorder inputs.

Styles on existing instances

Instance kindHow
Existing built-in instanceupdateBuiltInIndicatorProperties(id, { styles }) or getIndicatorHandle(id)?.updateProperties({ styles })
Existing custom instanceupdateIndicator(id, { styles }) when your UI exposes them
Per-bar colorsplot.colors / plot.barcolor in the indicator

updateBuiltInIndicatorProperties(instanceId, patch) and updateProperties(patch) validate catalog-backed inputs and styles before mutating the live indicator. Use inspectBuiltInIndicatorProperties(id, patch) when a settings UI needs diagnostics before submitting an existing built-in property patch.

Price-axis labels

Every indicator can show its latest plot values as labels on the price axis. The chart-wide default lives in chart styles (indicator.lastValueMark.show, exposed in chart settings as Show indicator values on price axis); axisLabelVisible pins one indicator either way.

chart.updateIndicator(id, { axisLabelVisible: false }) // this indicator only, labels off
chart.getIndicatorHandle(id)?.updateProperties({ axisLabelVisible: true })
ValueBehavior
undefinedFollows the chart-wide default
trueLabels on for this indicator, whatever the default is
falseLabels off for this indicator, whatever the default is

The chart settings dialog lists one switch per indicator under Price Axis → Indicator axis labels, and the indicator Settings dialog carries the same switch under Visibility. Both update the same instance setting, so a pinned preference survives later chart-settings changes.

Saved state

Settings dialog (UI)

For each indicator instance, Settings typically shows:

Tab / areaSource of fields
InputsAuthored input.* declarations
StyleAuthored plot.* declarations and instance style overrides
VisibilityInstance visible, plot visible, axisLabelVisible

TradeScript owns the Settings schema. Your integration updates instance values through chart.updateIndicator; those values round-trip through getState() and setState().

Use clearIndicatorDefaults(name) to remove future defaults for one indicator, or clearIndicatorDefaults() to clear the full default map. Clearing defaults does not touch existing instances — they keep their saved values.


Result keys (calc map)

Plots and markers should set key when hosts or tests read values:

plot.line(fast, { key: 'fast', title: 'Fast EMA' })
marker(up, { dir: 'up', key: 'golden', label: 'Golden' })
plot.value(score, { key: 'score' }) // hidden series

Without key, TradeScript assigns one automatically. Set a key whenever your application needs to read or style a specific result.

Indicator errors in Settings

If error('message') stops a calculation, surface that message in Settings, the legend, or a toast.