# How to Create a Custom Trading Strategy in Nautilus Trader

> Learn to create a custom trading strategy in Nautilus Trader. Define parameters, override event handlers, and integrate with a Trader for advanced trading.

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

---

**Create a custom trading strategy by subclassing `Strategy` from `nautilus_trader.trading.strategy`, defining a frozen `StrategyConfig` for parameters, overriding event handlers like `on_start` and `on_bar`, then registering the instance with a `Trader` via `add_strategy` and `start_strategy` to begin processing market data.**

Nautilus Trader is a high-performance algorithmic trading platform that enables you to create a custom trading strategy by extending its core Python classes. Whether you are backtesting historical data or trading live markets, the framework provides a structured lifecycle for your algorithms through configuration models and event-driven handlers defined in the `nautechsystems/nautilus_trader` repository.

## Understanding the Strategy Architecture

### Strategy Configuration (StrategyConfig)

The configuration layer uses immutable data models defined in [`nautilus_trader/trading/config.py`](https://github.com/nautechsystems/nautilus_trader/blob/main/nautilus_trader/trading/config.py). Every custom strategy requires a **frozen** `msgspec` model that inherits from `StrategyConfig`. This class holds static parameters such as the target `InstrumentId`, order ID tags, and OMS (Order Management System) type. Because the config is frozen, it can be safely hashed and serialized for distributed deployments.

### Strategy Implementation (Strategy Class)

The execution logic resides in a class that inherits from `Strategy`, implemented in `nautilus_trader/trading/strategy.pyx`. This Cython base class provides the **order factory**, portfolio access, and a suite of `on_*` event hooks. You only override the handlers relevant to your algorithm—such as `on_start` for initialization, `on_bar` for bar-driven signals, or `on_order_filled` for fill notifications. The base class supplies no-op defaults that emit warnings if called unexpectedly.

## Step-by-Step Guide to Create a Custom Trading Strategy

1. **Define the Configuration Class**

Create a frozen model inheriting from `StrategyConfig` to declare your strategy's parameters.

```python
from nautilus_trader.trading.config import StrategyConfig
from nautilus_trader.model.identifiers import InstrumentId

class MyStrategyConfig(StrategyConfig, frozen=True):
    """
    Configuration for MyStrategy.
    """
    instrument_id: InstrumentId
    order_id_tag: str = "001"
    quantity: int = 10

```

2. **Implement the Strategy Class**

Subclass `Strategy` and override the event handlers required for your logic.

```python
from nautilus_trader.trading.strategy import Strategy
from nautilus_trader.model.data import Bar
from nautilus_trader.model.enums import OrderSide
from nautilus_trader.model.objects import Quantity

class MyStrategy(Strategy):
    """
    Example strategy that submits a market order on every bar close.
    """

    def __init__(self, config: MyStrategyConfig) -> None:
        super().__init__(config)

    def on_start(self) -> None:
        """Called when the strategy starts."""
        self.log.info("Strategy starting")
        self.subscribe_bars(self.config.instrument_id)

    def on_bar(self, bar: Bar) -> None:
        """Called on every new bar."""
        order = self.order_factory.market(
            instrument_id=self.config.instrument_id,
            order_side=OrderSide.BUY,
            quantity=Quantity(self.config.quantity),
        )
        self.submit_order(order)

    def on_order_filled(self, event) -> None:
        """Called when an order fill is received."""
        self.log.info(f"Fill received: {event.order_id}")

```

3. **Register with the Trader**

Instantiate your strategy and add it to a `Trader` instance defined in [`nautilus_trader/trading/trader.py`](https://github.com/nautechsystems/nautilus_trader/blob/main/nautilus_trader/trading/trader.py).

```python
from nautilus_trader.trading.trader import Trader

# Assuming trader is already instantiated

strategy = MyStrategy(config)
trader.add_strategy(strategy)

```

4. **Start the Strategy**

Begin processing market data by starting the strategy lifecycle.

```python
trader.start_strategy(strategy.id)

```

## Complete Working Example

The repository provides a canonical blank template at [`nautilus_trader/examples/strategies/blank.py`](https://github.com/nautechsystems/nautilus_trader/blob/main/nautilus_trader/examples/strategies/blank.py) that demonstrates the minimal required structure.

```python
from nautilus_trader.trading.config import StrategyConfig
from nautilus_trader.model.data import Bar
from nautilus_trader.model.identifiers import InstrumentId
from nautilus_trader.trading.strategy import Strategy

class MyStrategyConfig(StrategyConfig, frozen=True):
    instrument_id: InstrumentId

class MyStrategy(Strategy):
    def __init__(self, config: MyStrategyConfig) -> None:
        super().__init__(config)

    def on_start(self) -> None:
        self.log.info("MyStrategy started")

    def on_bar(self, bar: Bar) -> None:
        self.log.info(f"Received bar {bar}")

```

To run this example:

```python
from nautilus_trader.examples.strategies.blank import MyStrategy, MyStrategyConfig
from nautilus_trader.model.identifiers import InstrumentId

cfg = MyStrategyConfig(instrument_id=InstrumentId.from_str("ETHUSDT-PERP.BINANCE"))
strategy = MyStrategy(cfg)

trader.add_strategy(strategy)
trader.start_strategy(strategy.id)

```

## Key Source Files and References

- [`nautilus_trader/trading/config.py`](https://github.com/nautechsystems/nautilus_trader/blob/main/nautilus_trader/trading/config.py) – Defines `StrategyConfig`, `ImportableStrategyConfig`, and `StrategyFactory` for serializable configuration.
- `nautilus_trader/trading/strategy.pyx` – Cython base class providing the `Strategy` interface, order factory, and event hooks.
- [`nautilus_trader/trading/trader.py`](https://github.com/nautechsystems/nautilus_trader/blob/main/nautilus_trader/trading/trader.py) – Manages strategy lifecycle via `add_strategy`, `start_strategy`, and `stop_strategy`.
- [`nautilus_trader/examples/strategies/blank.py`](https://github.com/nautechsystems/nautilus_trader/blob/main/nautilus_trader/examples/strategies/blank.py) – Minimal template for new strategies.
- [`nautilus_trader/trading/messages.py`](https://github.com/nautechsystems/nautilus_trader/blob/main/nautilus_trader/trading/messages.py) – Command definitions for internal strategy control.

## Summary

- Create a custom trading strategy by defining a frozen `StrategyConfig` subclass for static parameters and a `Strategy` subclass for logic.
- Place configuration in [`nautilus_trader/trading/config.py`](https://github.com/nautechsystems/nautilus_trader/blob/main/nautilus_trader/trading/config.py) and implementation in `nautilus_trader/trading/strategy.pyx`.
- Override lifecycle hooks (`on_start`, `on_stop`) and data handlers (`on_bar`, `on_quote_tick`) as needed.
- Use the built-in `order_factory` to create orders and `submit_order` to execute them.
- Register the strategy with a `Trader` using `add_strategy` and activate it with `start_strategy` to begin processing events.

## Frequently Asked Questions

### What is the difference between StrategyConfig and Strategy?

`StrategyConfig` is an immutable data model defined in [`nautilus_trader/trading/config.py`](https://github.com/nautechsystems/nautilus_trader/blob/main/nautilus_trader/trading/config.py) that holds static parameters like instrument IDs and order tags. `Strategy` is the executable class defined in `nautilus_trader/trading/strategy.pyx` that contains the trading logic and event handlers. The configuration instance is passed to the strategy's constructor during instantiation.

### How do I subscribe to market data in my custom strategy?

Override the `on_start` method and call subscription methods such as `self.subscribe_bars(instrument_id)`, `self.subscribe_quote_ticks(instrument_id)`, or `self.subscribe_trade_ticks(instrument_id)`. These methods register your strategy with the data engine, ensuring that the corresponding `on_bar`, `on_quote_tick`, or `on_trade_tick` handlers receive events automatically.

### Can I load a custom strategy from a YAML configuration file?

Yes, use `ImportableStrategyConfig` from [`nautilus_trader/trading/config.py`](https://github.com/nautechsystems/nautilus_trader/blob/main/nautilus_trader/trading/config.py). Define `strategy_path` as the dot-path to your strategy class and `config_path` as the dot-path to your config class, along with a `config` dictionary of parameters. The `StrategyFactory.create` method resolves these strings, instantiates the configuration, and builds the strategy for registration with the trader.

### What lifecycle methods should I implement for proper resource management?

At minimum, implement `on_start` to subscribe to market data and initialize internal state, and `on_stop` to cancel pending orders and release resources. For graceful shutdowns in live trading environments, you may also override `on_market_exit` to flatten positions. The base class in `nautilus_trader/trading/strategy.pyx` provides these hooks; only override the ones your algorithm requires.