Why 4 Fields?
In trading systems, a missing value is not the same as zero. A price ofNaN could mean:
- The symbol doesn’t exist on this exchange (
exists=False) - The data is corrupted or invalid (
valid=False) - The data hasn’t been updated this tick (
updated=False) - The price is genuinely zero — extremely unlikely for real assets
NaN, losing critical information. ClyptQ’s TaggedArray separates them into 4 explicit fields, making every data point self-describing.
The 4 Fields
Every piece of data in ClyptQ — FIELD inputs, STATE inputs, operator outputs — is a TaggedArray with exactly 4 numpy arrays:
All 4 arrays share the same shape — either
(n_symbols,) for a single tick or (n_time, n_symbols) for buffered history.
Combined Masks
TaggedArray provides two combined properties for common checks:is_valid when you need any usable value (including forward-filled).
Use is_fresh when you only want newly computed values.
Hierarchical Gate Structure
The 3 boolean fields form a hierarchical gate — each level only matters if the previous level isTrue:
If exists=False, valid and updated are irrelevant.
If valid=False, updated is irrelevant.
When Each Field Matters
exists: Domain Membership (Survivorship Bias Prevention)
exists tracks whether a symbol is currently listed on the exchange. This is the foundation for dynamic universe support and survivorship bias prevention:
exists=True→ Symbol is actively traded at this timestampexists=False→ Symbol is not listed (never listed, or delisted)- A symbol can transition from
TruetoFalse(delisting) during a backtest
valid: Value Quality
valid=False means the symbol exists but has no usable value right now. Common causes:
- Insufficient data for computation (warmup period)
- Missing/NaN data from exchange (temporary gap)
- Computation error (division by zero, overflow)
- Upstream dependency was invalid
updated: Tick Freshness
updated=False with valid=True means the value was forward-filled — it’s the last known good value, but nothing changed this tick. This is the key to ClyptQ’s forward-fill semantics: the value persists, but you know it’s stale.
Shape: 1D vs 2D
1D: Single Tick (n_symbols,)
When an operator receives its inputs with lookback=1, or when a single tick arrives:
2D: Buffered History (n_time, n_symbols)
When an operator requests lookback > 1, the RollingBuffer delivers a 2D TaggedArray:
AxisMeta: Symbol Alignment
TaggedArrays carryAxisMeta — frozen metadata about the symbol dimension:
item_order is an immutable tuple — the ordering never changes during execution. This guarantees that index 0 always means the same symbol across all operators and all ticks.
Creating TaggedArrays
In Operators
Most operators receive TaggedArrays as inputs and return them as outputs:Factory Methods
TaggedTensor: Extended Container
TaggedTensor wraps TaggedArray with additional capabilities:
Metadata
TaggedTensors support arbitrary metadata for non-numeric data:Merge Operations
When combining two TaggedArrays (e.g., adding signals), masks propagate conservatively:
This ensures invalid data never silently contaminates downstream computations.
Practical Impact
Why Not Just NaN?
Consider a backtest that includes a token that gets delisted mid-test:
Without TaggedArray, a delisted token, a data gap, and a warmup period all look like
NaN. Operators can’t tell them apart. With the 3-gate system, each scenario is unambiguous.
Forward-Fill Distinction
This is critical for the FIELD system. When a data source hasn’t updated:updated. Operators that need any valid value check valid. This granularity prevents spurious signals from stale data.
Relationship to Other Concepts
- FIELD Data Principle: FIELD data arrives as TaggedArrays
- STATE Principle: STATE data arrives as TaggedArrays
- Lookback Buffers: RollingBuffer stores TaggedArrays and delivers them as 2D TaggedArrays
- StatefulGraph: All operator inputs and outputs are TaggedArrays
- Operator Protocol:
compute()receives and returns TaggedArrays

