OnlineTechnicalIndicators internals
Sub-indicator(s)
An indicator can be composed internally of sub-indicator(s). Input values catched by fit! calls are transmitted to each sub_indicators to be processed to _calculate_new_value function which calculates value of indicator output.
Example: Bollinger Bands (BB) indicator owns 2 internal sub-indicators
central_bandwhich is a simple moving average of prices,std_devwhich is standard deviation of prices.
Composing new indicators
Indicators Chaining with OnlineStatsChains
Indicators can be chained together to create complex compositions - it's like building new indicators with Lego bricks.
Examples of chained indicators:
DEMA: 2 moving averages chained togetherTEMA: 3 moving averages chained togetherT3: 6 moving averages chained togetherTRIX: 3 moving averages chained together with ROC calculation
Using OnlineStatsChains StatDAG (Recommended)
The recommended way to compose indicators is using OnlineStatsChains.StatDAG. This provides a directed acyclic graph (DAG) structure for organizing indicator chains with automatic value propagation through filtered edges.
Basic pattern:
using OnlineStatsChains
# 1. Create a StatDAG
dag = StatDAG()
# 2. Add indicator nodes with symbolic names
add_node!(dag, :ema1, EMA(period=10))
add_node!(dag, :ema2, EMA(period=10))
# 3. Connect nodes with filtered edges (only propagates non-missing values)
connect!(dag, :ema1, :ema2, filter = !ismissing)
# 4. Fit data to the source node - values propagate automatically
fit!(dag, :ema1 => 100.0)
# 5. Read values from any node
value(dag, :ema1) # First EMA value
value(dag, :ema2) # Second EMA value (automatically updated)Benefits of StatDAG:
- Clear structure: Visual organization of the indicator pipeline
- Automatic propagation: Values flow through filtered edges without manual handling
- Named access: Each stage can be inspected by name for debugging
- Flexible composition: Easy to add/remove stages or modify connections
DAGWrapper: Integration with fit! Infrastructure
The DAGWrapper struct provides a compatibility layer between StatDAG and the OnlineTechnicalIndicators' fit! infrastructure:
mutable struct DAGWrapper
dag::StatDAG # The underlying StatDAG
source_node::Symbol # Entry point for data
stats::Vector{OnlineStat} # For compatibility checks
endWhen fit! is called on a DAGWrapper, it forwards the data to the DAG's source node, which then automatically propagates values through all connected edges:
function fit!(wrapper::DAGWrapper, data)
fit!(wrapper.dag, wrapper.source_node => data)
endThis allows composed indicators to use StatDAG internally while maintaining compatibility with the standard fit! interface.
Example: How DEMA Uses StatDAG
The DEMA (Double Exponential Moving Average) indicator demonstrates the StatDAG pattern:
Structure:
Input → :ma1 (EMA) → :ma2 (EMA) → DEMA calculationImplementation:
# In the DEMA constructor:
dag = StatDAG()
add_node!(dag, :ma1, MAFactory(Float64)(EMA, period=period))
add_node!(dag, :ma2, MAFactory(Float64)(EMA, period=period))
# Filtered edge - only propagate non-missing values
connect!(dag, :ma1, :ma2, filter = !ismissing)
# Wrap for compatibility with fit! infrastructure
sub_indicators = DAGWrapper(dag, :ma1, [dag.nodes[:ma1].stat])How it works:
- When
fit!(dema, data)is called, data flows tosub_indicators(the DAGWrapper) - DAGWrapper forwards to
dag[:ma1] - The filtered edge automatically propagates to
dag[:ma2](if value is non-missing) - In
_calculate_new_value, values are read from both nodes:
function _calculate_new_value(ind::DEMA)
val2 = value(ind.dag, :ma2)
if !ismissing(val2)
# DEMA formula: 2 * MA1 - MA2
return 2.0 * value(ind.dag, :ma1) - val2
else
return missing # Chain not fully warmed up
end
endKey insight: The filtered edge (filter = !ismissing) eliminates the need for nested conditionals - propagation only happens when values are available.
For migrating from the old add_input_indicator! API, see the Migration Guide.
Filtering and Transforming Input (Legacy)
The input_filter and input_modifier mechanism described below is a legacy feature that has been superseded by StatDAG filtered edges for built-in indicators. It remains available only for backward compatibility with custom user-defined indicators.
For new indicator compositions, use OnlineStatsChains.StatDAG with filtered edges instead. See the Migration Guide for details.
The legacy mechanism allows filtering and transforming input of an indicator using functions (typically anonymous functions). Input can be filtered/transformed before being passed to sub-indicators or processed by _calculate_new_value.
This mechanism still exists in the codebase for backward compatibility with custom indicators that may have implemented input_filter and input_modifier fields, but is no longer used by any built-in indicators.
Moving average factory
SMA,EMA, ... are moving average.
Most complex indicators uses in their original form SMA or EMA as default moving average.
In some markets they can perform better by using instead an other kind of moving average.
A moving average factory have been implemented
This kind of indicators have a ma parameter in order to bypass their default moving average uses.