NautilusTrader
Concepts

Actors

An Actor receives data, handles events, and manages state. The Strategy class extends Actor with order management capabilities.

Key capabilities:

  • Data subscription and requests (market data, custom data).
  • Event handling and publishing.
  • Timers and alerts.
  • Cache and portfolio access.
  • Logging.

Basic example

Actors support configuration through a pattern similar to strategies.

from nautilus_trader.config import ActorConfig
from nautilus_trader.model import InstrumentId
from nautilus_trader.model import Bar, BarType
from nautilus_trader.common.actor import Actor


class MyActorConfig(ActorConfig):
    instrument_id: InstrumentId   # example value: "ETHUSDT-PERP.BINANCE"
    bar_type: BarType             # example value: "ETHUSDT-PERP.BINANCE-15-MINUTE[LAST]-INTERNAL"
    lookback_period: int = 10


class MyActor(Actor):
    def __init__(self, config: MyActorConfig) -> None:
        super().__init__(config)

        # Custom state variables
        self.count_of_processed_bars: int = 0

    def on_start(self) -> None:
        # Subscribe to bars matching the configured bar type
        self.subscribe_bars(self.config.bar_type)

    def on_bar(self, bar: Bar) -> None:
        self.count_of_processed_bars += 1

Lifecycle

Actors follow a defined state machine through their lifecycle:

Override these methods to hook into lifecycle events:

MethodWhen called
on_start()Actor is starting (subscribe to data here).
on_stop()Actor is stopping (cancel timers, clean up resources).
on_resume()Actor is resuming from a stopped state.
on_reset()Reset indicators and internal state (called between backtest runs).
on_degrade()Actor is entering a degraded state (partial functionality).
on_fault()Actor has encountered a fault.
on_dispose()Actor is being disposed (final cleanup).

Timers and alerts

Actors have access to a clock for scheduling:

def on_start(self) -> None:
    # Set a recurring timer with a callback (fires every 5 seconds)
    self.clock.set_timer(
        "my_timer",
        timedelta(seconds=5),
        callback=self._on_timer,
    )

    # Set a one-time alert with a callback
    self.clock.set_time_alert(
        "my_alert",
        self.clock.utc_now() + timedelta(minutes=1),
        callback=self._on_alert,
    )

def on_stop(self) -> None:
    # Cancel timers to prevent resource leaks across stop/resume cycles
    self.clock.cancel_timer("my_timer")

def _on_timer(self, event: TimeEvent) -> None:
    self.log.info("Timer fired!")

def _on_alert(self, event: TimeEvent) -> None:
    self.log.info("Alert triggered!")

Pass a callback to direct TimeEvent objects to your own method. If you omit the callback, the event is delivered to on_event instead.

System access

Actors have access to core system components:

PropertyDescription
self.cacheShared state for instruments, orders, positions, etc.
self.portfolioPortfolio state and calculations.
self.clockCurrent time and timer/alert scheduling.
self.logStructured logging.
self.msgbusPublish/subscribe to custom messages.

For custom messaging between components, see the Message Bus guide.

Data handling and callbacks

The system uses different callback handlers depending on whether data is historical or real-time. Understanding the relationship between data requests/subscriptions and their handlers is key.

Historical vs real-time data

The system distinguishes between two data flows:

  1. Historical data (from requests):

    • Obtained through methods like request_bars(), request_quote_ticks(), etc.
    • Processed through the on_historical_data() handler.
    • Used for initial data loading and historical analysis.
  2. Real-time data (from subscriptions):

    • Obtained through methods like subscribe_bars(), subscribe_quote_ticks(), etc.
    • Processed through specific handlers like on_bar(), on_quote_tick(), etc.
    • Used for live data processing.

Callback handlers

Different data operations map to these handlers:

OperationCategoryHandlerPurpose
subscribe_data()Real‑timeon_data()Live data updates.
subscribe_instrument()Real‑timeon_instrument()Live instrument definition updates.
subscribe_instruments()Real‑timeon_instrument()Live instrument definition updates (for venue).
subscribe_order_book_deltas()Real‑timeon_order_book_deltas()Live order book deltas.
subscribe_order_book_depth()Real‑timeon_order_book_depth()Live order book depth snapshots.
subscribe_order_book_at_interval()Real‑timeon_order_book()Live order book snapshots at intervals.
subscribe_quote_ticks()Real‑timeon_quote_tick()Live quote updates.
subscribe_trade_ticks()Real‑timeon_trade_tick()Live trade updates.
subscribe_mark_prices()Real‑timeon_mark_price()Live mark price updates.
subscribe_index_prices()Real‑timeon_index_price()Live index price updates.
subscribe_bars()Real‑timeon_bar()Live bar updates.
subscribe_funding_rates()Real‑timeon_funding_rate()Live funding rate updates.
subscribe_instrument_status()Real‑timeon_instrument_status()Live instrument status updates.
subscribe_instrument_close()Real‑timeon_instrument_close()Live instrument close updates.
subscribe_option_greeks()Real‑timeon_option_greeks()Live option greeks updates.
subscribe_option_chain()Real‑timeon_option_chain()Live option chain slice snapshots.
subscribe_order_fills()Real‑timeon_order_filled()Live order fill events for an instrument.
subscribe_order_cancels()Real‑timeon_order_canceled()Live order cancel events for an instrument.
request_data()Historicalon_historical_data()Historical data processing.
request_order_book_deltas()Historicalon_historical_data()Historical order book deltas.
request_order_book_depth()Historicalon_historical_data()Historical order book depth.
request_order_book_snapshot()Historicalon_historical_data()Historical order book snapshot.
request_instrument()Historicalon_instrument()Instrument definition.
request_instruments()Historicalon_instrument()Instrument definitions.
request_quote_ticks()Historicalon_historical_data()Historical quotes processing.
request_trade_ticks()Historicalon_historical_data()Historical trades processing.
request_bars()Historicalon_historical_data()Historical bars processing.
request_aggregated_bars()Historicalon_historical_data()Historical aggregated bars (on‑the‑fly).
request_funding_rates()Historicalon_historical_data()Historical funding rates processing.

Example

This example shows both historical and real-time data handling:

from nautilus_trader.common.actor import Actor
from nautilus_trader.config import ActorConfig
from nautilus_trader.core.data import Data
from nautilus_trader.model import Bar, BarType
from nautilus_trader.model import ClientId, InstrumentId


class MyActorConfig(ActorConfig):
    instrument_id: InstrumentId  # example value: "AAPL.XNAS"
    bar_type: BarType            # example value: "AAPL.XNAS-1-MINUTE-LAST-EXTERNAL"


class MyActor(Actor):
    def __init__(self, config: MyActorConfig) -> None:
        super().__init__(config)
        self.bar_type = config.bar_type

    def on_start(self) -> None:
        # Request historical data - will be processed by on_historical_data() handler
        self.request_bars(
            bar_type=self.bar_type,
            # Many optional parameters
            start=None,                # pd.Timestamp | None
            end=None,                  # pd.Timestamp | None
            callback=None,             # Callable[[UUID4], None] | None
            update_catalog_mode=None,  # UpdateCatalogMode | None
            params=None,               # dict[str, Any] | None
        )

        # Subscribe to real-time data - will be processed by on_bar() handler
        self.subscribe_bars(
            bar_type=self.bar_type,
            # Many optional parameters
            client_id=None,  # ClientId, optional
            params=None,     # dict[str, Any], optional
        )

    def on_historical_data(self, data: Data) -> None:
        # Handle historical data (from requests)
        if isinstance(data, Bar):
            self.log.info(f"Received historical bar: {data}")

    def on_bar(self, bar: Bar) -> None:
        # Handle real-time bar updates (from subscriptions)
        self.log.info(f"Received real-time bar: {bar}")

Separating historical and real-time handlers lets you apply different processing logic based on context. For example:

  • Use historical data to initialize indicators or establish baseline metrics.
  • Process real-time data differently for live trading decisions.
  • Apply different validation or logging for historical vs real-time data.

When debugging data flow issues, check that you're looking at the correct handler for your data source. If you're not seeing data in on_bar() but see log messages about receiving bars, check on_historical_data() as the data might be coming from a request rather than a subscription.

Order fill subscriptions

Actors can subscribe to order fill events for specific instruments using subscribe_order_fills(). This is useful for monitoring trading activity, fill analysis, or tracking execution quality.

When subscribed, the handler on_order_filled() receives all fills for the specified instrument, regardless of which strategy or component generated the original order.

Example

from nautilus_trader.common.actor import Actor
from nautilus_trader.config import ActorConfig
from nautilus_trader.model import InstrumentId
from nautilus_trader.model.events import OrderFilled


class MyActorConfig(ActorConfig):
    instrument_id: InstrumentId  # example value: "ETHUSDT-PERP.BINANCE"


class FillMonitorActor(Actor):
    def __init__(self, config: MyActorConfig) -> None:
        super().__init__(config)
        self.fill_count = 0
        self.total_volume = 0.0

    def on_start(self) -> None:
        # Subscribe to all fills for the instrument
        self.subscribe_order_fills(self.config.instrument_id)

    def on_order_filled(self, event: OrderFilled) -> None:
        # Handle order fill events
        self.fill_count += 1
        self.total_volume += float(event.last_qty)

        self.log.info(
            f"Fill received: {event.order_side} {event.last_qty} @ {event.last_px}, "
            f"Total fills: {self.fill_count}, Volume: {self.total_volume}"
        )

    def on_stop(self) -> None:
        # Unsubscribe from fills
        self.unsubscribe_order_fills(self.config.instrument_id)

Order fill subscriptions use the message bus only and do not involve the data engine. The on_order_filled() handler receives events only while the actor is running.

Order cancel subscriptions

Actors can subscribe to order cancel events for specific instruments using subscribe_order_cancels(). This is useful for monitoring cancellations or tracking order lifecycle events.

When subscribed, the handler on_order_canceled() receives all cancels for the specified instrument, regardless of which strategy or component generated the original order.

Example

from nautilus_trader.common.actor import Actor
from nautilus_trader.config import ActorConfig
from nautilus_trader.model import InstrumentId
from nautilus_trader.model.events import OrderCanceled


class MyActorConfig(ActorConfig):
    instrument_id: InstrumentId  # example value: "ETHUSDT-PERP.BINANCE"


class CancelMonitorActor(Actor):
    def __init__(self, config: MyActorConfig) -> None:
        super().__init__(config)
        self.cancel_count = 0

    def on_start(self) -> None:
        # Subscribe to all cancels for the instrument
        self.subscribe_order_cancels(self.config.instrument_id)

    def on_order_canceled(self, event: OrderCanceled) -> None:
        # Handle order cancel events
        self.cancel_count += 1

        self.log.info(
            f"Cancel received: {event.client_order_id}, "
            f"Total cancels: {self.cancel_count}"
        )

    def on_stop(self) -> None:
        # Unsubscribe from cancels
        self.unsubscribe_order_cancels(self.config.instrument_id)

Order cancel subscriptions use the message bus only and do not involve the data engine. The on_order_canceled() handler receives events only while the actor is running.

  • Strategies - Strategies extend actors with order management capabilities.
  • Data - Data types and subscriptions available to actors.
  • Message Bus - The messaging system actors use for communication.

On this page