# How to Use Built-In Indicators in NautilusTrader Trading Strategies

> Learn how to use built-in indicators in NautilusTrader trading strategies. Instantiate, register, and read indicator data using C-extension classes for powerful trading signals and efficient development.

- Repository: [Nautech Systems/nautilus_trader](https://github.com/nautechsystems/nautilus_trader)
- Tags: how-to-guide
- Published: 2026-02-16

---

**NautilusTrader provides a high-performance library of technical indicators implemented as C-extension classes that you instantiate, register with your strategy's actor, and read from within `on_bar` or `on_tick` callbacks to generate trading signals.**

The `nautechsystems/nautilus_trader` repository ships with a comprehensive suite of technical indicators—including EMA, SMA, MACD, Bollinger Bands, and RSI—implemented as `cdef` classes for C-speed calculations. Understanding how to use built-in indicators in trading strategies allows you to leverage these optimized tools without writing custom indicator logic from scratch.

## Creating Built-In Indicators

You can instantiate indicators either through the factory pattern for moving averages or by directly importing concrete classes for other indicator types.

### Using the MovingAverageFactory

The `MovingAverageFactory.create` method defined in `nautilus_trader/indicators/averages.pyx` (lines 898-907) provides a unified interface for creating various moving average types:

```python
from nautilus_trader.indicators import MovingAverageFactory, MovingAverageType

# Create a 10-period Exponential Moving Average

ema10 = MovingAverageFactory.create(10, MovingAverageType.EXPONENTIAL)

```

`MovingAverageType` is an `Enum` exposing supported families including `EXPONENTIAL`, `SIMPLE`, `WILDERS`, and `WEIGHTED`.

### Direct Class Instantiation

For specific implementations or non-moving-average indicators, import directly from the indicators package:

```python
from nautilus_trader.indicators import ExponentialMovingAverage

# Instantiate EMA directly (implementation in averages.pyx lines 182-207)

ema10 = ExponentialMovingAverage(10)  # Defaults to PriceType.LAST

```

The `ExponentialMovingAverage` class and other indicators are implemented as `cdef` classes in `.pyx` files, ensuring the `value` attribute updates with minimal latency.

## Registering Indicators for Automatic Updates

Indicators must be registered with the strategy's actor to receive market data updates automatically. The registration API is defined in `nautilus_trader/common/actor.pyx` (lines 444-471).

For bar-based strategies, call `register_indicator_for_bars` inside `on_start`:

```python
def on_start(self):
    # Subscribe to the bar stream

    self.subscribe_bars(self.bar_type)
    # Register indicator to receive bar updates automatically

    self.register_indicator_for_bars(self.bar_type, self.ema10)

```

When registered, the engine automatically invokes the indicator's `handle_bar` method (or `handle_quote_tick`/`handle_trade_tick` for tick data) **before** executing your strategy's `on_bar` callback. This ensures `indicator.value` reflects the current bar's calculation when you read it.

For tick-based indicators, use `register_indicator_for_quotes` or `register_indicator_for_trade_ticks` instead.

## Accessing Indicator Values in Strategy Logic

Inside your strategy callbacks (`on_bar`, `on_tick`, etc.), read the indicator's `value` property to access the latest calculated result. Always check the `initialized` property first to ensure the indicator has received sufficient data (at least `period` data points):

```python
def on_bar(self, bar: Bar):
    self.bars_processed += 1
    
    if self.ema10.initialized:
        # Indicator is ready - use the value for signal generation

        ema_value = self.ema10.value
        self.log.info(f"EMA(10) value: {ema_value:.5f}")
        
        # Example signal logic

        if bar.close > ema_value:
            # Bullish condition

            pass
    else:
        # Indicator warming up

        self.log.info(f"Waiting for EMA initialization... ({self.bars_processed} bars processed)")

```

The `value` attribute updates automatically via the indicator's internal `handle_bar` method, which the engine invoked during the registration phase.

## Complete Working Example

The repository provides a full implementation in [`examples/backtest/example_07_using_indicators/strategy.py`](https://github.com/nautechsystems/nautilus_trader/blob/main/examples/backtest/example_07_using_indicators/strategy.py) (lines 27-73). Below is a condensed version demonstrating the complete workflow:

```python
import datetime as dt
from collections import deque
from nautilus_trader.common.enums import LogColor
from nautilus_trader.indicators import MovingAverageFactory, MovingAverageType
from nautilus_trader.model.data import Bar, BarType
from nautilus_trader.trading.strategy import Strategy

class EmaDemoStrategy(Strategy):
    """
    Minimal demo showing how to use built-in indicators in trading strategies
    by calculating a 10-period EMA and logging its values.
    """
    
    def __init__(self, bar_type: BarType):
        super().__init__()
        self.bar_type = bar_type
        self.bars_processed = 0
        
        # Step 1: Create the indicator

        self.ema10 = MovingAverageFactory.create(10, MovingAverageType.EXPONENTIAL)
        self.ema_history: deque[float] = deque(maxlen=100)
    
    def on_start(self):
        # Step 2: Subscribe and register

        self.subscribe_bars(self.bar_type)
        self.register_indicator_for_bars(self.bar_type, self.ema10)
    
    def on_bar(self, bar: Bar):
        self.bars_processed += 1
        
        # Step 3: Use the indicator value

        if self.ema10.initialized:
            self.ema_history.appendleft(self.ema10.value)
            self.log.info(
                f"Bar #{self.bars_processed} | Close={bar.close} | EMA(10)={self.ema10.value:.5f}",
                color=LogColor.YELLOW,
            )
        else:
            self.log.info(
                f"Bar #{self.bars_processed} | Close={bar.close} | Waiting for EMA init...",
                color=LogColor.RED,
            )

```

When executed through the NautilusTrader backtest engine, this strategy automatically receives bar updates, calculates the EMA in C-speed via the `cdef` class implementation, and logs values once the 10-period warm-up completes.

## Summary

- **Instantiation**: Create indicators using `MovingAverageFactory.create()` for moving averages or direct class imports from `nautilus_trader.indicators` for other types like MACD or RSI.
- **Registration**: Call `register_indicator_for_bars()` (or tick variants) in `on_start()` to wire indicators to data streams, as implemented in `nautilus_trader/common/actor.pyx`.
- **Access**: Read `indicator.value` inside `on_bar()` or `on_tick()` after checking `indicator.initialized` to ensure warm-up completion.
- **Performance**: Built-in indicators use `cdef` C-extension classes defined in `.pyx` files (e.g., `averages.pyx`) for high-speed calculations without Python overhead.

## Frequently Asked Questions

### What indicator types are available in NautilusTrader?

NautilusTrader provides a comprehensive library including moving averages (EMA, SMA, WMA, Wilders), momentum indicators (RSI, MACD), volatility measures (Bollinger Bands, ATR), and volume-based tools. All are implemented as `cdef` classes in the `nautilus_trader.indicators` package for C-speed performance.

### How do I know when an indicator is ready to use?

Check the `initialized` boolean property before accessing `value`. An indicator becomes initialized once it has processed at least `period` data points. Accessing `value` before initialization may return `None` or incomplete calculations depending on the specific indicator implementation.

### Can I use indicators with tick data instead of bars?

Yes. Use `register_indicator_for_quotes()` or `register_indicator_for_trade_ticks()` instead of `register_indicator_for_bars()`. The indicator will then receive `QuoteTick` or `TradeTick` objects via its `handle_quote_tick` or `handle_trade_tick` methods, updating its `value` property accordingly.

### Where can I find example strategies using built-in indicators?

The repository includes a complete working example at [`examples/backtest/example_07_using_indicators/strategy.py`](https://github.com/nautechsystems/nautilus_trader/blob/main/examples/backtest/example_07_using_indicators/strategy.py). This file demonstrates creating an EMA indicator via `MovingAverageFactory`, registering it for bar updates, and accessing values within the `on_bar` callback to generate trading signals.