Custom Series
[[custom_series]] lets you create a custom numeric series from a formula.
In this block, the formula is limited to symbols available at indicator stage. Runtime backtest, portfolio, order, and trade variables are not available.
Use this block to isolate an intermediate calculation and reuse it across conditions or as input to other indicators.
How the formula interprets series
Inside a custom_series, a series is not interpreted on the native timeframe of the block that produced it, but on the timeframe of the block that reads it.
In other words, the formula always evaluates in the frame of reference of the custom_series itself. If it uses a series coming from another timeframe, that series is first realigned onto the block axis before it is used. Both the current value and its history are therefore read in that same frame.
Take a simple case. If your main strategy runs on 240, an indicator daily_signal is calculated on D, and a custom_series reads that indicator without defining its own timeframe, then the formula runs on the 240 axis. In that context, daily_signal[1] means the value seen one 240 bar earlier on the projected series. It does not mean the previous daily bar.
This rule matters as soon as you combine multiple timeframes in the same formula. It ensures that a series and its history remain consistent from the point of view of the block consuming them.
Block declaration
A strategy can contain multiple [[custom_series]] blocks. Each block outputs one numeric series identified by its id.
formula follows the general expression rules (operators, functions, reserved constants, historical indexing). See Expressions and functions.
In [[custom_series]], the formula can use standard price series, outputs from indicators already defined in the strategy, and the variables they expose.
Examples
Minimal setup
This block reproduces Williams Variable Accumulation/Distribution. The formula measures the gap between close and open, normalizes it by the candle range, then weights it by volume.
[[custom_series]]
id = "wvad"
formula = "high != low ? (close - open) / (high - low) * volume : 0"True Range
This block computes the True Range of a candle. The formula takes the maximum between the current range (high - low) and the absolute gaps between the current candle extremes and the previous close.
[[custom_series]]
id = "true_range"
formula = "max(high - low, abs(high - close[1]), abs(low - close[1]))"Dedicated timeframe
This block forces the computation onto a daily timeframe.
If timeframe is omitted, the block runs on the grid main timeframe defined in [backtest].
[[custom_series]]
id = "daily_body"
formula = "close - open"
timeframe = "D"See the Exchanges, Symbols and Timeframes page for alignment rules between this timeframe and the main timeframe.
Using custom_series as the source of another indicator
A custom series can be reused as source in other indicator blocks.
[[custom_series]]
id = "price_delta"
formula = "close - close[1]"
[[moving_average]]
id = "delta_ma"
type = "ema"
source = "price_delta"
length = 20Variables exposed by indicators
A custom_series formula can also use the variables exposed by indicators already defined in the strategy, for example fast.length, fast.type, fast.symbol, or fast.timeframe.
This example adapts the formula according to the moving-average types currently being evaluated during grid search.
[[moving_average]]
id = "fast"
type = ["sma", "ema"]
length.start = 10
length.stop = 30
[[moving_average]]
id = "slow"
type = ["sma", "ema"]
length = 50
[[custom_series]]
id = "ma_signal"
formula = "fast.type == 'ema' and slow.type == 'ema' ? fast / slow : (fast - slow) / slow * 100"Parameters
| Parameter | Description |
|---|---|
idString Required | Unique name of the produced series. This identifier becomes the variable name you use in expressions. |
formulaExpression Required | Expression that defines the computed series. Supported inputs: standard prices, ids of indicators already defined, variables exposed by those indicators ( fast.length, fast.type, fast.symbol, fast.timeframe, etc.), numeric constants, and expression functions.Accepted TOML types: string, integer, floating-point number. Runtime backtest, portfolio, order, and trade variables are not available in this block. Reserved constants pi, euler, phi, and rphi should not be reused as business identifiers. |
timeframeString or Array Optional | Timeframe used to compute the series. If omitted, computation uses the grid main timeframe defined in [backtest].For accepted formats and alignment rules, see Exchanges, Symbols and Timeframes. |
symbolString or Array Forbidden | symbol is not allowed on [[custom_series]].For multi-market logic, define upstream indicator sources with their own symbols, then combine those indicators in formula. |
Available variables
The custom_series block exposes one numeric series plus context metadata (symbol, timeframe).
These variables are exposed after the series has been computed and can be used downstream. They are not available inside the block formula itself.
Assume this configuration:
[[custom_series]]
id = "candle_body"
formula = "close - open"Then:
| Variable | Description |
|---|---|
candle_body or candle_body[0]Decimal | Current value of the computed series. |
candle_body[n]Decimal | Value of the series n bars ago. |
candle_body.symbolString | Market symbol effectively used by this block. |
candle_body.timeframeString | Timeframe effectively used by this block. |
Notes
- Numeric variables support arithmetic, comparisons, and logical operators.
- Text variables are intended for equality/inequality checks only.
- A formula cannot reference its own
id(self-reference is forbidden).
Common errors
| Message (summary) | Typical cause | Fix |
|---|---|---|
Invalid formula | Invalid expression syntax, missing parenthesis, or malformed expression token. | Simplify the formula, verify variable names, then rebuild it progressively. |
The expression cannot reference its own id | Self-reference (for example id = "x" with formula = "x + 1"). | Use another input series; do not reference the current block id in its own formula. |
Key 'symbol' is not allowed on custom_series blocks | symbol is present in [[custom_series]]. | Remove symbol from the block and handle multi-market logic through upstream indicators. |
Unknown source id | A referenced indicator id does not exist (typo, case mismatch, missing block), or the formula uses a variable that is not exposed by an indicator already defined in the strategy. | Check spelling/case, ensure the source indicator block exists, and only use standard price series, outputs from indicators already defined, or the variables they expose. |
Cyclic dependency | Circular indicator dependency graph. | Refactor block dependencies to remove the cycle. |