Skip to content

Commit 618db14

Browse files
committed
Add EMACrossLongOnly SPY.XNAS trades example
1 parent a531435 commit 618db14

File tree

3 files changed

+126
-2
lines changed

3 files changed

+126
-2
lines changed
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
#!/usr/bin/env python3
2+
# -------------------------------------------------------------------------------------------------
3+
# Copyright (C) 2015-2024 Nautech Systems Pty Ltd. All rights reserved.
4+
# https://nautechsystems.io
5+
#
6+
# Licensed under the GNU Lesser General Public License Version 3.0 (the "License");
7+
# You may not use this file except in compliance with the License.
8+
# You may obtain a copy of the License at https://www.gnu.org/licenses/lgpl-3.0.en.html
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS,
12+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
# See the License for the specific language governing permissions and
14+
# limitations under the License.
15+
# -------------------------------------------------------------------------------------------------
16+
17+
import time
18+
from decimal import Decimal
19+
20+
import pandas as pd
21+
22+
from nautilus_trader.adapters.databento.loaders import DatabentoDataLoader
23+
from nautilus_trader.backtest.engine import BacktestEngine
24+
from nautilus_trader.backtest.engine import BacktestEngineConfig
25+
from nautilus_trader.config import LoggingConfig
26+
from nautilus_trader.examples.strategies.ema_cross_long_only import EMACrossLongOnly
27+
from nautilus_trader.examples.strategies.ema_cross_long_only import EMACrossLongOnlyConfig
28+
from nautilus_trader.model.currencies import USD
29+
from nautilus_trader.model.data import BarType
30+
from nautilus_trader.model.enums import AccountType
31+
from nautilus_trader.model.enums import OmsType
32+
from nautilus_trader.model.identifiers import TraderId
33+
from nautilus_trader.model.identifiers import Venue
34+
from nautilus_trader.model.objects import Money
35+
from nautilus_trader.test_kit.providers import TestInstrumentProvider
36+
from tests import TEST_DATA_DIR
37+
38+
39+
if __name__ == "__main__":
40+
# Configure backtest engine
41+
config = BacktestEngineConfig(
42+
trader_id=TraderId("BACKTESTER-001"),
43+
logging=LoggingConfig(
44+
log_level="INFO",
45+
log_colors=True,
46+
),
47+
)
48+
49+
# Build the backtest engine
50+
engine = BacktestEngine(config=config)
51+
52+
# Add a trading venue (multiple venues possible)
53+
NASDAQ = Venue("XNAS")
54+
engine.add_venue(
55+
venue=NASDAQ,
56+
oms_type=OmsType.NETTING,
57+
account_type=AccountType.CASH,
58+
base_currency=USD,
59+
starting_balances=[Money(1_000_000.0, USD)],
60+
)
61+
62+
# Add instruments
63+
SPY_XNAS = TestInstrumentProvider.equity(symbol="SPY", venue="XNAS")
64+
engine.add_instrument(SPY_XNAS)
65+
66+
# Add data
67+
loader = DatabentoDataLoader()
68+
69+
filenames = [
70+
"spy-xnas-trades-2024-01.dbn.zst",
71+
"spy-xnas-trades-2024-02.dbn.zst",
72+
"spy-xnas-trades-2024-03.dbn.zst",
73+
]
74+
75+
for filename in filenames:
76+
trades = loader.from_dbn_file(
77+
path=TEST_DATA_DIR / "databento" / "temp" / filename,
78+
instrument_id=SPY_XNAS.id,
79+
)
80+
engine.add_data(trades)
81+
82+
# Configure your strategy
83+
config = EMACrossLongOnlyConfig(
84+
instrument_id=SPY_XNAS.id,
85+
bar_type=BarType.from_str(f"{SPY_XNAS.id}-1000-TICK-LAST-INTERNAL"),
86+
trade_size=Decimal(100),
87+
fast_ema_period=10,
88+
slow_ema_period=20,
89+
request_historical_bars=False, # Using internally aggregated tick bars
90+
)
91+
92+
# Instantiate and add your strategy
93+
strategy = EMACrossLongOnly(config=config)
94+
engine.add_strategy(strategy=strategy)
95+
96+
time.sleep(0.1)
97+
input("Press Enter to continue...")
98+
99+
# Run the engine (from start to end of data)
100+
engine.run()
101+
102+
# Optionally view reports
103+
with pd.option_context(
104+
"display.max_rows",
105+
100,
106+
"display.max_columns",
107+
None,
108+
"display.width",
109+
300,
110+
):
111+
print(engine.trader.generate_account_report(NASDAQ))
112+
print(engine.trader.generate_order_fills_report())
113+
print(engine.trader.generate_positions_report())
114+
115+
# For repeated backtest runs make sure to reset the engine
116+
engine.reset()
117+
118+
# Good practice to dispose of the object
119+
engine.dispose()

examples/backtest/databento_ema_cross_long_only_tsla_trades.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@
8282
# Configure your strategy
8383
config = EMACrossLongOnlyConfig(
8484
instrument_id=TSLA_NYSE.id,
85-
bar_type=BarType.from_str("TSLA.NYSE-1-MINUTE-LAST-INTERNAL"),
85+
bar_type=BarType.from_str(f"{TSLA_NYSE.id}-1-MINUTE-LAST-INTERNAL"),
8686
trade_size=Decimal(500),
8787
fast_ema_period=10,
8888
slow_ema_period=20,

nautilus_trader/examples/strategies/ema_cross_long_only.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ class EMACrossLongOnlyConfig(StrategyConfig, frozen=True):
5858
The fast EMA period.
5959
slow_ema_period : int, default 20
6060
The slow EMA period.
61+
request_historical_bars : bool, default True
62+
If historical bars should be requested on start.
6163
close_positions_on_stop : bool, default True
6264
If all open positions should be closed on strategy stop.
6365
order_id_tag : str
@@ -74,6 +76,7 @@ class EMACrossLongOnlyConfig(StrategyConfig, frozen=True):
7476
trade_size: Decimal
7577
fast_ema_period: PositiveInt = 10
7678
slow_ema_period: PositiveInt = 20
79+
request_historical_bars: bool = True
7780
close_positions_on_stop: bool = True
7881

7982

@@ -114,6 +117,7 @@ def __init__(self, config: EMACrossLongOnlyConfig) -> None:
114117
self.fast_ema = ExponentialMovingAverage(config.fast_ema_period)
115118
self.slow_ema = ExponentialMovingAverage(config.slow_ema_period)
116119

120+
self.request_historical_bars = config.request_historical_bars
117121
self.close_positions_on_stop = config.close_positions_on_stop
118122
self.instrument: Instrument = None
119123

@@ -132,7 +136,8 @@ def on_start(self) -> None:
132136
self.register_indicator_for_bars(self.bar_type, self.slow_ema)
133137

134138
# Get historical data
135-
self.request_bars(self.bar_type, start=self._clock.utc_now() - pd.Timedelta(days=1))
139+
if self.request_historical_bars:
140+
self.request_bars(self.bar_type, start=self._clock.utc_now() - pd.Timedelta(days=1))
136141
# self.request_quote_ticks(self.instrument_id)
137142
# self.request_trade_ticks(self.instrument_id)
138143

0 commit comments

Comments
 (0)