The GMM component
Table of Contents
1. Summary
A gmm_component is one weighted Gaussian of the price process an
fx_spot_generation_config drives. It is declared in
ores.synthetic.api/domain/gmm_component.hpp, it points at its parent
through fx_spot_config_id, and a parent holds one or more of them.
2. Detail
2.1. What the row holds
component_index, a zero-based ordinal within the parent's mixture.description, a human label such as "primary" or "jump".mean, the mean log-return of this component per update. It is per tick and not annualised.stdev, the standard deviation of this component. It must be zero or greater.weight, the mixture weight.
Why rows rather than a blob. The set is a child table, so the editor writes one row per component and the count of components is data rather than a schema shape. Adding a component is an insert and never a migration.
2.2. The weight normalisation rule
The stored weights are not required to sum to one. They are passed straight
into a std::discrete_distribution<int> when the process is built, and that
distribution normalises them itself. Nothing rewrites the stored rows.
The one rule a stored set must satisfy is that the weights sum to something
greater than zero.
ores::analytics::quant::domain::validate_process_parameters rejects an
all-zero weight set with the message that at least one component must carry a
positive weight. That check is shared by the service factory and the Qt
client, so the same set is rejected in both places.
2.3. Why the components are not in one row
The parent config row holds the datum, the cadence and the process choice.
The mixture is a variable-length list, and the codegen entity shape used
across this schema has no array column. The child table is therefore the
schema's way of holding a list, and it is the same one-config-many-children
shape ir_curve_generation_config uses for its template entries and its
parameter values.
2.4. The fact the code shape does not show
A zero standard deviation is legal and meaningful. It stands for a degenerate
component whose draw is exactly its mean. Both mixture processes test for it
and take the mean directly, because std::normal_distribution asserts on a
zero standard deviation in a debug build and would abort the service.
Nothing constrains mean or stdev to a plausible range in the database.
The mean is a per-tick log-return, so the same number means different things
at different ticks_per_hour values, and a set copied between two configs
with different cadences does not carry the same dynamics.
3. See also
- Market Data Architecture — the structure note that orders this cluster, and where to read this page in it.
- The FX spot generation config, the parent.
- The generator library, which builds the mixture process from these rows.
- The FX spot producer, which reads them at feed construction.
- Geometric Brownian Motion, the single-Gaussian model a mixture generalises.
- Volatility clustering and GARCH models, the discrete-time family that addresses the same fat-tail problem by a recurrence on the variance.