Skip to content

Lifecycle and Universe Nodes

AQS lifecycle and universe nodes expose the AQE component model in the visual strategy graph. They let you keep strategy behavior modular without manually editing generated src/main.rs in .aqmeta projects.

You can still write this logic inline in Rust. The nodes are for segmentation: separate responsibilities, clearer graph structure, reusable files, and easier configuration in the editor.

AQS provides four modular node types for this workflow:

  • On Start Logic creates an OnStartLogic component.
  • On Init Logic creates an OnInitLogic component.
  • On Teardown Logic creates an OnTeardownLogic component.
  • Universe Model creates a UniverseModel component.

Lifecycle logic files use the .logic.rs suffix. Universe model files use the .universe.rs suffix.

When a project has a .aqmeta file, AQS owns the graph and regenerates src/main.rs. Do not manually edit generated src/main.rs for these components. Add or edit the custom component file and update the node configuration instead.

Codegen handles the registration:

  • lifecycle logic nodes become AQE lifecycle wrappers;
  • universe model nodes become AQE universe model wrappers;
  • constructor arguments are exposed as public node properties;
  • private struct fields may appear as read-only/private properties in the panel;
  • execution order follows the graph topology where nodes are chained.

Lifecycle nodes have a timing setting:

  • Before generated runs the component before the generated body for that lifecycle method.
  • After generated runs the component after the generated body for that lifecycle method.

Use Before generated for prerequisites and validation. Use After generated when the logic depends on generated registration or setup already being complete.

Examples:

  • seed ctx.variables() before alpha models read it;
  • validate required environment variables before the strategy starts;
  • initialize symbol-specific metadata after the asset is known;
  • flush runtime diagnostics after teardown.

Each node has a can_fail setting.

  • can_fail = false means an unsuccessful result should stop the run.
  • can_fail = true means AQE logs the failure and continues.

Startup and init logic should usually be strict. Teardown can usually fail without stopping the remaining cleanup work.

Universe Model nodes return symbols programmatically. They are useful when the static universe list is too limited.

Use a Universe Model node for:

  • loading a watchlist;
  • filtering symbols by metadata;
  • choosing symbols by date or regime;
  • selecting symbols from account, broker, or risk constraints;
  • sharing the same universe selection logic across strategies.

The final AQE universe is the union of the static universe returned by the generated strategy and every connected universe model. Duplicate symbols are removed.

This means you can keep a simple static universe node and add a Universe Model node for dynamic additions.

The node workflow is not mandatory. For small strategies, inline Rust is often enough:

  • add startup code directly in on_start;
  • add per-asset setup directly in init;
  • return symbols directly from universe;
  • add cleanup directly in on_teardown.

Use nodes when the code deserves its own file, should be visible in the AQS graph, needs configuration in the property panel, or will be reused.

  • Keep constructor arguments for user-tuned settings only.
  • Put runtime-only state in ctx.variables() instead of struct fields.
  • Use lifecycle nodes for setup and cleanup, not trading signal generation.
  • Keep signal generation in alpha models.
  • Keep sizing, submission, cancellation, close, and management logic in insight pipes.
  • Chain lifecycle nodes when exact ordering matters.
  • Return clear LifecycleResult and UniverseResult messages so logs and AQS surfaces are useful.

For startup:

  1. connect On Start Logic to the strategy lifecycle port;
  2. set timing to Before generated if generated alpha/pipe registration depends on it;
  3. seed shared state in ctx.variables();
  4. return a successful LifecycleResult.

For per-asset initialization:

  1. connect On Init Logic to the init lifecycle port;
  2. use the asset argument to initialize symbol-specific state;
  3. store that state under the component name and asset symbol.

For teardown:

  1. connect On Teardown Logic to the teardown lifecycle port;
  2. set can_fail = true unless failure must invalidate the run;
  3. persist or summarize runtime diagnostics.

For universe selection:

  1. create a Universe Model node;
  2. implement UniverseModel::run(ctx) -> UniverseResult;
  3. return only symbols the model is responsible for;
  4. let AQE merge those symbols with the static universe and other universe models.