# Strategies ¶

The heart of the NautilusTrader user experience is in writing and working with trading strategies. Defining a trading strategy is achieved by inheriting the  Strategy  class, and implementing the methods required by the strategy.

Using the basic building blocks of data ingest, event handling, and order management (which we will discuss below), it’s possible to implement any type of trading strategy including directional, momentum, re-balancing, pairs, market making etc.

Refer to the  Strategy  in the API Reference for a complete description of all the possible functionality.

There are two main parts of a Nautilus trading strategy:

• The strategy implementation itself, defined by inheriting the  Strategy  class

• The optional strategy configuration, defined by inheriting the  StrategyConfig  class

Note

Once a strategy is defined, the same source can be used for backtesting and live trading.

## Implementation ¶

Since a trading strategy is a class which inherits from  Strategy  , you must define a constructor where you can handle initialization. Minimally the base/super class needs to be initialized:

class MyStrategy(Strategy):
def __init__(self) -> None:
super().__init__()  # <-- the super class must be called to initialize the strategy


## Configuration ¶

The main purpose of a separate configuration class is to provide total flexibility over where and how a trading strategy can be instantiated. This includes being able to serialize strategies and their configurations over the wire, making distributed backtesting and firing up remote live trading possible.

This configuration flexibility is actually opt-in, in that you can actually choose not to have any strategy configuration beyond the parameters you choose to pass into your strategies’ constructor. However, if you would like to run distributed backtests or launch live trading servers remotely, then you will need to define a configuration.

Here is an example configuration:

from decimal import Decimal

class MyStrategyConfig(StrategyConfig):
instrument_id: str
bar_type: str
fast_ema_period: int = 10
slow_ema_period: int = 20
order_id_tag: str

# Here we simply add an instrument ID as a string, to
# parameterize the instrument the strategy will trade.

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

# Configuration
self.instrument_id = InstrumentId.from_str(config.instrument_id)

# Once a configuration is defined and instantiated, we can pass this to our

config = MyStrategyConfig(
instrument_id="ETHUSDT-PERP.BINANCE",
bar_type="ETHUSDT-PERP.BINANCE-1000-TICK[LAST]-INTERNAL",
order_id_tag="001",
)

strategy = MyStrategy(config=config)



Note

Even though it often makes sense to define a strategy which will trade a single instrument. There is actually no limit to the number of instruments a single strategy can work with.

### Multiple strategies ¶

If you intend running multiple instances of the same strategy, with different configurations (such as trading different instruments), then you will need to define a unique  order_id_tag  for each of these strategies (as shown above).

Note

The platform has built-in safety measures in the event that two strategies share a duplicated strategy ID, then an exception will be thrown that the strategy ID has already been registered.

The reason for this is that the system must be able to identify which strategy various commands and events belong to. A strategy ID is made up of the strategy class name, and the strategies  order_id_tag  separated by a hyphen. For example the above config would result in a strategy ID of  MyStrategy-001  .

Tip

See the  StrategyId  documentation for further details.

### Managed GTD expiry ¶

It’s possible for the strategy to manage expiry for orders with a time in force of GTD ( Good ‘till Date ). This may be desirable if the exchange/broker does not support this time in force option, or for any reason you prefer the strategy to manage this.

Simply set the  manage_gtd_expiry  boolean flag on the  submit_order()  or  submit_order_list()  methods to  True  . This will then start a timer, when the timer expires the order will be canceled (if not already closed).

strategy.submit_order(order, manage_gtd_expiry=True)