NAUTILUS / RUST source 3eb18933
Pages

Rust edition: this page follows the live DeepWiki structure but treats the current Rust crates as implementation authority. Non-Rust surfaces are identified at their boundary and are not presented as Rust APIs.

Actors and Component Lifecycle

Relevant Rust source files

  • crates/common/src/actor/data_actor.rs

Overview

This page documents the Actor base class, which serves as the foundation for custom data-processing components in NautilusTrader. Actors consume market data, process events, register indicators, and maintain state without submitting orders or managing positions. They are fundamental building blocks within the data system for analysis, signal generation, and system monitoring.

Scope:

  • Actor class structure and initialization via register_base()
  • Component lifecycle states and transition methods (on_start, on_stop, etc.)
  • Event handler methods (on_quote_tick, on_bar, on_data, etc.)
  • Data subscription and request patterns
  • Indicator registration and automatic updates
  • State persistence with on_save() and on_load()
  • Signal publishing for inter-component communication
  • Rust-native DataActor implementation and DataEngine interaction
  • How to write Rust actors using the nautilus_actor! macro and DataActorCore.

Related pages:

  • Component state machine fundamentals:
  • Data routing and engine orchestration:
  • Trading strategies with order management:

Actor Base Class

The Actor class is defined in and inherits from Component, providing event-driven data processing without order management capabilities.

Key characteristics:

Feature Description
Event-driven Responds to market data via handler methods (on_quote_tick, on_bar, etc.)
Non-trading Does not submit orders; use Strategy for trading logic
Stateful Supports state persistence via on_save() and on_load()
Data consumer Subscribes to instruments, ticks, bars, order books, custom data
Concurrent Supports async task execution through ActorExecutor

Common use cases:

  • Market data analysis and signal generation
  • Custom indicator calculations
  • System health monitoring
  • Data recording and archival
  • Inter-component signaling

Class Hierarchy and Dependencies

Inheritance hierarchy:

DataActor and Strategy build on shared component lifecycle and actor contracts; strategy adds order and portfolio behavior while data actors remain focused on subscriptions, requests and custom data processing.

Actor dependencies and interfaces:

Actors and strategies communicating with data, risk, execution, portfolio and cache through the Nautilus message bus.

Key fields initialized via register_base():

Field Type Source
msgbus MessageBus
cache CacheFacade
clock Clock
portfolio PortfolioFacade
greeks GreeksCalculator

Registration and Initialization

Actors must be registered with the system before use. Registration connects the actor to core services and transitions it from PRE_INITIALIZED to READY state.

Registration Process


Component Lifecycle States

Actors inherit the Component lifecycle state machine. Key states relevant to actor operation:

Primary states:

State Transition Description
PRE_INITIALIZED __init__() Actor constructed, not yet registered
READY register_base() Registered with system, ready to start
RUNNING start() Processing events and data
STOPPED stop() Paused, can resume or reset
DISPOSED dispose() Permanently shut down

State transitions for actors:

LiveNode startup and lifecycle showing when registered actors and strategies enter the running kernel.


Lifecycle Methods

Actors override lifecycle methods defined in to control initialization and cleanup.

Core lifecycle methods:

Method Called During Typical Use
on_start() READYRUNNING Subscribe to data, initialize resources
on_stop() RUNNINGSTOPPED Pause processing, log status
on_resume() STOPPEDRUNNING Resume after pause
on_reset() READY Clear state, reset indicators
on_dispose() DISPOSED Release resources
on_save() System shutdown Return state for persistence
on_load() System startup Restore from persistence

Event Handler Methods

Actors implement event handlers defined in to receive market data.

Market data handlers:

Handler Method Data Type Source
on_quote_tick(tick) QuoteTick
on_trade_tick(tick) TradeTick
on_bar(bar) Bar
on_order_book(book) OrderBook
on_order_book_deltas(deltas) OrderBookDeltas
on_instrument(instrument) Instrument

Derivative data handlers:

Handler Method Data Type Source
on_mark_price(update) MarkPriceUpdate
on_index_price(update) IndexPriceUpdate
on_funding_rate(update) FundingRateUpdate

Data Subscription and Requests

Actors manage data flow via subscription and request commands routed through the DataEngine.

Subscription Methods

  • subscribe_quote_ticks(instrument_id): Subscribes to BBO updates
  • subscribe_trade_ticks(instrument_id): Subscribes to trade execution updates
  • subscribe_bars(bar_type): Subscribes to aggregated bars
  • subscribe_order_book(instrument_id): Subscribes to full L2/L3 order book updates

Request Methods

  • request_quote_ticks(instrument_id, start, end): Requests historical quote data
  • request_trade_ticks(instrument_id, start, end): Requests historical trade data
  • request_bars(bar_type, start, end): Requests historical bar data
  • request_order_book_snapshot(instrument_id): Requests current order book state

Indicator Registration

Indicators can be registered to receive automatic updates before actor handlers are called.

Registration methods:

  • register_indicator_for_quote_ticks(instrument_id, indicator):
  • register_indicator_for_trade_ticks(instrument_id, indicator):
  • register_indicator_for_bars(bar_type, indicator):

Update flow:

  1. Market data arrives via MessageBus.
  2. Actor.handle_quote_tick (or similar) is called
  3. Registered indicators for that instrument/type are updated
  4. The user-defined on_quote_tick (or similar) is called

DataActor (Rust)

The DataActor trait and DataActorCore provide a high-performance Rust implementation for actors.

DataActor Trait

The Rust DataActor trait provides lifecycle and market-data callbacks such as on_start, on_quote, on_trade, and on_bar.

DataActorCore

DataActorCore is the foundational struct for Rust actors, managing common actor functionalities such as logging, message bus interaction, cache access, and request handling It is embedded within any concrete Rust actor implementation.

Writing Rust Actors with nautilus_actor!

The nautilus_actor! macro simplifies the creation of Rust actors by automatically implementing the Component and DataActor traits, and providing the necessary Deref and DerefMut implementations to access DataActorCore

Example:

#[derive(Debug)]
struct TestDataActor {
    core: DataActorCore,
    pub received_time_events: Vec<TimeEvent>,
    // ... other fields
}

nautilus_actor!(TestDataActor); // This macro implements the necessary traits

impl DataActor for TestDataActor {
    fn on_start(&mut self) -> anyhow::Result<()> {
        log::info!("Starting actor");
        Ok(())
    }
    // ... implement other on_* methods
}

This macro allows TestDataActor to behave as a DataActor and Component, delegating core functionalities to its core field.

Deferred Commands

The Rust DataEngine supports DeferredCommand objects (Subscribe, Unsubscribe, etc.) pushed to a DeferredCommandQueue by components like handlers or timers that lack direct client access These commands are processed by the DataEngine loop.

Rust DataEngine Handlers

The DataEngine in Rust uses specialized handlers for various aggregation tasks:

  • BarBarHandler: Handles bar-to-bar aggregation
  • BarTradeHandler: Handles trade-to-bar aggregation
  • BarQuoteHandler: Handles quote-to-bar aggregation
  • SpreadQuoteHandler: Handles aggregation of spread quotes

Summary of Interaction Patterns

Actors receive lifecycle and data callbacks through the component and message-bus contracts. Registration establishes the subscriptions and indicators an actor owns; startup activates them; deferred commands safely cross into the data-engine loop; and stop/dispose removes those resources in dependency order. Rust actors should keep domain work inside typed callbacks and leave provider networking, persistence, and node orchestration to their owning adapters and services.