Tutorials
EMA cross
Define the reusable bar-based EMA cross strategy used by the FX bars tutorial.
from __future__ import annotations
from decimal import Decimal
from nautilus_trader.config import StrategyConfig
from nautilus_trader.indicators import ExponentialMovingAverage
from nautilus_trader.model import Bar
from nautilus_trader.model import BarType
from nautilus_trader.model import InstrumentId
from nautilus_trader.model import OrderSide
from nautilus_trader.trading import Strategy
class EMACrossConfig(StrategyConfig):
_CUSTOM_FIELDS = (
"instrument_id",
"bar_type",
"trade_size",
"fast_ema_period",
"slow_ema_period",
)
def __new__(cls, *args, **kwargs):
for field in cls._CUSTOM_FIELDS:
kwargs.pop(field, None)
return super().__new__(cls, *args, **kwargs)
def __init__(
self,
instrument_id: InstrumentId,
bar_type: BarType,
trade_size: Decimal,
fast_ema_period: int = 10,
slow_ema_period: int = 20,
**_kwargs,
) -> None:
super().__init__()
self.instrument_id = instrument_id
self.bar_type = bar_type
self.trade_size = trade_size
self.fast_ema_period = fast_ema_period
self.slow_ema_period = slow_ema_period
class EMACross(Strategy):
def __init__(self, config: EMACrossConfig):
super().__init__(config)
self.fast_ema = ExponentialMovingAverage(config.fast_ema_period)
self.slow_ema = ExponentialMovingAverage(config.slow_ema_period)
def on_start(self):
self.register_indicator_for_bars(self.config.bar_type, self.fast_ema)
self.register_indicator_for_bars(self.config.bar_type, self.slow_ema)
self.subscribe_bars(self.config.bar_type)
def on_bar(self, bar: Bar):
if not self.indicators_initialized():
return
if self.fast_ema.value >= self.slow_ema.value:
if self.portfolio.is_net_flat(self.config.instrument_id):
self.buy()
elif self.portfolio.is_net_short(self.config.instrument_id):
self.close_all_positions(self.config.instrument_id)
self.buy()
elif self.fast_ema.value < self.slow_ema.value:
if self.portfolio.is_net_flat(self.config.instrument_id):
self.sell()
elif self.portfolio.is_net_long(self.config.instrument_id):
self.close_all_positions(self.config.instrument_id)
self.sell()
def buy(self):
instrument = self.cache.instrument(self.config.instrument_id)
order = self.order_factory.market(
self.config.instrument_id,
OrderSide.BUY,
instrument.make_qty(self.config.trade_size),
)
self.submit_order(order)
def sell(self):
instrument = self.cache.instrument(self.config.instrument_id)
order = self.order_factory.market(
self.config.instrument_id,
OrderSide.SELL,
instrument.make_qty(self.config.trade_size),
)
self.submit_order(order)
def on_stop(self):
self.close_all_positions(self.config.instrument_id)Backtest with Order Book Depth Data (Bybit)
Replay Bybit ob500 order book deltas through BacktestNode and run the OrderBookImbalance strategy. Same shape as the Binance variant, different loader and...
Order Book Data
Load Bybit order book archives and convert normalized venue rows into NautilusTrader order book deltas for the Binance and Bybit backtest tutorials.