Skip to main content

Core Interface

Every operator in ClyptQ implements a single method — the equivalent of a CPU instruction in the Von Neumann-inspired architecture. Stateless, deterministic, and indifferent to where its data originates:
Three guarantees:
  1. Inputs: Always Dict[str, TaggedArray] — buffered by the graph’s RollingBuffers
  2. Output: Always TaggedArray — 4 fields (value, exists, valid, updated)
  3. Stateless: No mutable state between ticks. The graph manages all state.

13 Operator Roles

Building Custom Operators

ClyptQ’s operator system is designed for extension. Inherit from BaseOperator and implement compute() to create any custom logic:

Basic Custom Operator

Register and Use

Custom Filter

Custom Metric

Any Python logic can go inside compute() — NumPy, SciPy, PyTorch, sklearn, custom algorithms. The operator protocol only requires TaggedArray in, TaggedArray out.

Self-Referencing Operators

Some operators need their own previous output as input. The classic example is EMA:
ClyptQ supports self-referencing by declaring the operator’s own node name as an input:

How It Works

  1. Topological sort excludes self-edges — The graph’s Kahn’s algorithm ignores self-references when computing execution order, preventing false cycle detection
  2. Buffer seeding — On the first tick, the self-reference buffer contains the initial/warmup value (typically valid=False)
  3. Each tick — After compute, the output is written to the self-reference buffer for the next tick

Self-Reference Use Cases

Iterative Computation Within compute()

Operators are called once per tick, but the compute() method can contain arbitrary Python logic including loops. For algorithms that require iteration (numerical solvers, differential equations, convergence-based methods), you implement the full iteration within a single compute() call:

Differential Equation Solvers

Key Principle

You don’t need incremental implementation for iterative algorithms. A single compute() call can run for loops, while loops, convergence checks — any Python control flow. The graph calls compute() once per tick, but what happens inside is unrestricted. This means:
  • Newton-Raphson for portfolio optimization — iterate to convergence within compute()
  • Runge-Kutta for ODE solvers — full integration step per tick
  • Monte Carlo simulation — generate thousands of paths within compute()
  • Gradient descent for online learning — run N steps per tick
  • ADMM / convex optimization — full solver per tick

Execution Responsibility Separation

Following the Von Neumann principle of separating computation from state, ClyptQ separates execution into three memoryless components:

Memoryless Execution

The executor is stateless — it receives an intention, computes a delta from current STATE, executes the order, updates STATE, and forgets everything. All metrics, tracking, and adaptation are done by operators in the graph, not by the executor.

FIELD & STATE

How FIELD (market data) and STATE (portfolio state) flow through the graph and enable the memoryless execution pattern

Feedback Loop Control

Because STATE flows back into the graph as input, strategies can create closed-loop feedback:
Feedback control examples:
  • Drawdown-based de-leveraging: Reduce position size when drawdown exceeds threshold
  • Equity curve trading: Pause trading during losing streaks
  • Adaptive position sizing: Scale based on realized equity volatility
  • Kelly criterion: Dynamically size based on accumulated win rate and payoff ratio
  • Regime switching: Change strategy behavior based on tracked portfolio metrics

ML and DL Integration

Online Learning (Per-Tick)

For models that update incrementally, the tick-by-tick architecture is natural:

Batch Data Collection for Offline Training

ClyptQ processes data tick-by-tick, so standard batch DL training doesn’t work directly in the graph. However, you can use a collector node to accumulate all data, then train after the iteration completes:
After driver.run() completes, all data is available for batch processing:
The collector pattern is not recommended for production strategies. It breaks the stateless operator principle and stores unbounded data in memory. Use it only for research and prototyping. For production, prefer online learning or pre-trained model inference.
Train externally, load model, run inference per tick:

Reinforcement Learning

RL agents fit naturally — each tick is an environment step:

Ephemeral Operators

Operators marked ephemeral = True make external API calls (LLM, web search) and cannot reproduce the same output for the same historical input:
  • Skip backtest validation
  • Only run in paper or live mode
  • Skip warmup (return neutral values)
  • Should be gated with Control operators for cost control
See Semantic Operators for detailed documentation.

ComputeContext

The context parameter provides execution metadata:

Performance Considerations

Tips:
  • Use NumPy vectorized operations (avoid Python loops over symbols)
  • Minimize lookback — request only what the algorithm needs
  • Cache expensive intermediate results in self (e.g., covariance matrices)
  • For ML inference, batch symbols together in one forward pass

Relationship to Other Concepts