Пример #1
0
    def test_load_pickled_data(self):
        # Arrange
        bar_type = BarType(
            instrument_id=GBPUSD_SIM.id,
            bar_spec=TestDataStubs.bar_spec_1min_bid(),
            aggregation_source=AggregationSource.EXTERNAL,  # <-- important
        )
        config = EMACrossConfig(
            instrument_id=str(GBPUSD_SIM.id),
            bar_type=str(bar_type),
            trade_size=Decimal(100_000),
            fast_ema=10,
            slow_ema=20,
        )
        strategy = EMACross(config=config)
        self.engine.add_strategy(strategy)

        data = self.engine.dump_pickled_data()

        # Act
        self.engine.load_pickled_data(data)
        self.engine.run()

        # Assert
        assert strategy.fast_ema.count == 30117
        assert self.engine.iteration == 60234
        assert self.engine.portfolio.account(
            self.venue).balance_total(USD) == Money(1001736.86, USD)
Пример #2
0
    def test_create_from_source(self):
        # Arrange
        config = EMACrossConfig(
            instrument_id="AUD/USD.SIM",
            bar_type="AUD/USD.SIM-1000-TICK-MID-INTERNAL",
            trade_size=1_000_000,
        )

        source = pkgutil.get_data("nautilus_trader.examples.strategies",
                                  "ema_cross.py")
        importable = ImportableStrategyConfig(
            module="my_ema_cross",
            source=source,
            config=config,
        )

        # Act
        strategy = StrategyFactory.create(importable)

        # Assert
        assert isinstance(strategy, EMACross)
        assert (
            repr(config) ==
            "EMACrossConfig(order_id_tag='000', oms_type='HEDGING', instrument_id='AUD/USD.SIM', bar_type='AUD/USD.SIM-1000-TICK-MID-INTERNAL', fast_ema_period=10, slow_ema_period=20, trade_size=Decimal('1000000'))"  # noqa
        )
Пример #3
0
    def test_create_from_path(self):
        # Arrange
        config = EMACrossConfig(
            instrument_id="AUD/USD.SIM",
            bar_type="AUD/USD.SIM-15-MINUTE-BID-EXTERNAL",
            trade_size=1_000_000,
            fast_ema_period=10,
            slow_ema_period=20,
        )
        importable = ImportableStrategyConfig(
            path="nautilus_trader.examples.strategies.ema_cross:EMACross",
            config=config,
        )

        # Act
        strategy = StrategyFactory.create(importable)

        # Assert
        assert isinstance(strategy, EMACross)
        assert (
            repr(config) ==
            "EMACrossConfig(component_id=None, order_id_tag='000', oms_type='HEDGING', "
            "instrument_id='AUD/USD.SIM', bar_type='AUD/USD.SIM-15-MINUTE-BID-EXTERNAL', "
            "fast_ema_period=10, slow_ema_period=20, trade_size=Decimal('1000000'))"  # noqa
        )
        def setup():
            config = BacktestEngineConfig(bypass_logging=True)
            engine = BacktestEngine(config=config)

            # Setup data
            wrangler = QuoteTickDataWrangler(USDJPY_SIM)
            provider = TestDataProvider()
            ticks = wrangler.process_bar_data(
                bid_data=provider.read_csv_bars("fxcm-usdjpy-m1-bid-2013.csv"),
                ask_data=provider.read_csv_bars("fxcm-usdjpy-m1-ask-2013.csv"),
            )
            engine.add_instrument(USDJPY_SIM)
            engine.add_ticks(ticks)

            engine.add_venue(
                venue=Venue("SIM"),
                oms_type=OMSType.HEDGING,
                account_type=AccountType.MARGIN,
                base_currency=USD,
                starting_balances=[Money(1_000_000, USD)],
            )

            config = EMACrossConfig(
                instrument_id=str(USDJPY_SIM.id),
                bar_type=str(TestDataStubs.bartype_usdjpy_1min_bid()),
                trade_size=Decimal(1_000_000),
                fast_ema=10,
                slow_ema=20,
            )
            strategy = EMACross(config=config)

            start = datetime(2013, 2, 1, 0, 0, 0, 0, tzinfo=pytz.utc)
            end = datetime(2013, 2, 10, 0, 0, 0, 0, tzinfo=pytz.utc)

            return (engine, start, end, strategy), {}
Пример #5
0
    def test_run_multiple_strategies(self):
        # Arrange
        config1 = EMACrossConfig(
            instrument_id=str(self.usdjpy.id),
            bar_type="USD/JPY.SIM-15-MINUTE-BID-INTERNAL",
            trade_size=Decimal(1_000_000),
            fast_ema=10,
            slow_ema=20,
            order_id_tag="001",
        )
        strategy1 = EMACross(config=config1)

        config2 = EMACrossConfig(
            instrument_id=str(self.usdjpy.id),
            bar_type="USD/JPY.SIM-15-MINUTE-BID-INTERNAL",
            trade_size=Decimal(1_000_000),
            fast_ema=20,
            slow_ema=40,
            order_id_tag="002",
        )
        strategy2 = EMACross(config=config2)

        # Note since these strategies are operating on the same instrument_id as per
        # the EMACross BUY/SELL logic they will be flattening each others positions.
        # The purpose of the test is just to ensure multiple strategies can run together.
        self.engine.add_strategies(strategies=[strategy1, strategy2])

        # Act
        self.engine.run()

        # Assert
        assert strategy1.fast_ema.count == 2689
        assert strategy2.fast_ema.count == 2689
        assert self.engine.iteration == 115044
        assert self.engine.portfolio.account(
            self.venue).balance_total(USD) == Money(985622.52, USD)
Пример #6
0
        def setup():
            config = BacktestEngineConfig(bypass_logging=True)
            engine = BacktestEngine(config=config)

            # Setup data
            wrangler = QuoteTickDataWrangler(USDJPY_SIM)
            provider = TestDataProvider()
            ticks = wrangler.process_bar_data(
                bid_data=provider.read_csv_bars("fxcm-usdjpy-m1-bid-2013.csv"),
                ask_data=provider.read_csv_bars("fxcm-usdjpy-m1-ask-2013.csv"),
            )
            engine.add_instrument(USDJPY_SIM)
            engine.add_ticks(ticks)

            interest_rate_data = pd.read_csv(
                os.path.join(PACKAGE_ROOT, "data", "short-term-interest.csv"))
            fx_rollover_interest = FXRolloverInterestModule(
                rate_data=interest_rate_data)

            engine.add_venue(
                venue=Venue("SIM"),
                venue_type=VenueType.BROKERAGE,
                oms_type=OMSType.HEDGING,
                account_type=AccountType.MARGIN,
                base_currency=USD,
                starting_balances=[Money(1_000_000, USD)],
                modules=[fx_rollover_interest],
            )

            config = EMACrossConfig(
                instrument_id=str(USDJPY_SIM.id),
                bar_type=str(TestStubs.bartype_usdjpy_1min_bid()),
                trade_size=Decimal(1_000_000),
                fast_ema=10,
                slow_ema=20,
            )
            strategy = EMACross(config=config)

            start = datetime(2013, 2, 1, 0, 0, 0, 0, tzinfo=pytz.utc)
            end = datetime(2013, 3, 1, 0, 0, 0, 0, tzinfo=pytz.utc)

            return (engine, start, end, [strategy]), {}
Пример #7
0
    def test_run_ema_cross_strategy(self):
        # Arrange
        config = EMACrossConfig(
            instrument_id=str(self.usdjpy.id),
            bar_type="USD/JPY.SIM-15-MINUTE-BID-INTERNAL",
            trade_size=Decimal(1_000_000),
            fast_ema=10,
            slow_ema=20,
        )
        strategy = EMACross(config=config)
        self.engine.add_strategy(strategy)

        # Act
        self.engine.run()

        # Assert - Should return expected PnL
        assert strategy.fast_ema.count == 2689
        assert self.engine.iteration == 115044
        assert self.engine.portfolio.account(
            self.venue).balance_total(USD) == Money(992811.26, USD)
Пример #8
0
    def test_run_ema_cross_with_tick_bar_spec(self):
        # Arrange
        config = EMACrossConfig(
            instrument_id=str(self.audusd.id),
            bar_type="AUD/USD.SIM-100-TICK-MID-INTERNAL",
            trade_size=Decimal(1_000_000),
            fast_ema=10,
            slow_ema=20,
        )
        strategy = EMACross(config=config)
        self.engine.add_strategy(strategy)

        # Act
        self.engine.run()

        # Assert
        assert strategy.fast_ema.count == 1000
        assert self.engine.iteration == 100000
        assert self.engine.portfolio.account(
            self.venue).balance_total(AUD) == Money(994441.60, AUD)
Пример #9
0
    def test_run_ema_cross_with_minute_bar_spec(self):
        # Arrange
        config = EMACrossConfig(
            instrument_id="AUD/USD.SIM",
            bar_type="AUD/USD.SIM-1-MINUTE-MID-INTERNAL",
            trade_size=Decimal(1_000_000),
            fast_ema=10,
            slow_ema=20,
        )
        strategy = EMACross(config=config)
        self.engine.add_strategy(strategy)

        # Act
        self.engine.run()

        # Assert
        assert strategy.fast_ema.count == 1771
        assert self.engine.iteration == 100000
        assert self.engine.portfolio.account(
            self.venue).balance_total(AUD) == Money(987920.04, AUD)
Пример #10
0
    def test_run_ema_cross_with_minute_bar_spec(self):
        # Arrange
        config = EMACrossConfig(
            instrument_id=str(self.gbpusd.id),
            bar_type="GBP/USD.SIM-5-MINUTE-MID-INTERNAL",
            trade_size=Decimal(1_000_000),
            fast_ema=10,
            slow_ema=20,
        )
        strategy = EMACross(config=config)
        self.engine.add_strategy(strategy)

        # Act
        self.engine.run()

        # Assert
        assert strategy.fast_ema.count == 8353
        assert self.engine.iteration == 120468
        assert self.engine.portfolio.account(
            self.venue).balance_total(GBP) == Money(931346.81, GBP)
    def test_exec_cache_check_integrity_when_index_cleared_fails(self):
        # Arrange
        config = EMACrossConfig(
            instrument_id=str(self.usdjpy.id),
            bar_type="USD/JPY.SIM-15-MINUTE-BID-INTERNAL",
            trade_size=Decimal(1_000_000),
            fast_ema=10,
            slow_ema=20,
        )
        strategy = EMACross(config=config)
        self.engine.add_strategy(strategy)

        # Generate a lot of data
        self.engine.run()

        # Clear index
        self.engine.cache.clear_index()

        # Act, Assert
        assert not self.engine.cache.check_integrity()
    def test_exec_cache_check_integrity_when_cache_cleared_fails(self):
        # Arrange
        config = EMACrossConfig(
            instrument_id=str(self.usdjpy.id),
            bar_type=str(TestStubs.bartype_usdjpy_1min_bid()),
            trade_size=Decimal(1_000_000),
            fast_ema=10,
            slow_ema=20,
        )
        strategy = EMACross(config=config)
        self.engine.add_strategy(strategy)

        # Generate a lot of data
        self.engine.run()

        # Remove data
        self.engine.cache.clear_cache()

        # Act, Assert
        assert not self.engine.cache.check_integrity()
    def test_run_ema_cross_with_tick_bar_spec(self):
        # Arrange
        config = EMACrossConfig(
            instrument_id=str(self.ethusdt.id),
            bar_type="ETH/USDT.BINANCE-250-TICK-LAST-INTERNAL",
            trade_size=Decimal(100),
            fast_ema=10,
            slow_ema=20,
        )
        strategy = EMACross(config=config)
        self.engine.add_strategy(strategy)

        # Act
        self.engine.run()

        # Assert
        assert strategy.fast_ema.count == 279
        assert self.engine.iteration == 69806
        assert self.engine.portfolio.account(
            self.venue).balance_total(USDT) == Money(998450.62196820, USDT)
Пример #14
0
    def test_run_ema_cross_with_minute_bar_spec(self):
        # Arrange
        config = EMACrossConfig(
            instrument_id=str(self.gbpusd.id),
            bar_type="GBP/USD.SIM-1-MINUTE-BID-EXTERNAL",
            trade_size=Decimal(1_000_000),
            fast_ema=10,
            slow_ema=20,
        )
        strategy = EMACross(config=config)
        self.engine.add_strategy(strategy)

        # Act
        self.engine.run()

        # Assert
        assert strategy.fast_ema.count == 30117
        assert self.engine.iteration == 60234
        ending_balance = self.engine.portfolio.account(
            self.venue).balance_total(USD)
        assert ending_balance == Money(1016188.45, USD)
Пример #15
0
 def setup(self):
     data_catalog_setup()
     self.catalog = DataCatalog.from_env()
     self.venue_config = BacktestVenueConfig(
         name="SIM",
         venue_type="ECN",
         oms_type="HEDGING",
         account_type="MARGIN",
         base_currency="USD",
         starting_balances=["1000000 USD"],
         # fill_model=fill_model,  # TODO(cs): Implement next iteration
     )
     self.data_config = BacktestDataConfig(
         catalog_path="/root",
         catalog_fs_protocol="memory",
         data_cls_path="nautilus_trader.model.data.tick.QuoteTick",
         instrument_id="AUD/USD.SIM",
         start_time=1580398089820000000,
         end_time=1580504394501000000,
     )
     self.backtest_configs = [
         BacktestRunConfig(
             engine=BacktestEngineConfig(),
             venues=[self.venue_config],
             data=[self.data_config],
         )
     ]
     self.strategies = [
         ImportableStrategyConfig(
             path="nautilus_trader.examples.strategies.ema_cross:EMACross",
             config=EMACrossConfig(
                 instrument_id="AUD/USD.SIM",
                 bar_type="AUD/USD.SIM-100-TICK-MID-INTERNAL",
                 fast_ema_period=10,
                 slow_ema_period=20,
                 trade_size=Decimal(1_000_000),
                 order_id_tag="001",
             ),
         )
     ]
Пример #16
0
    def test_run_ema_cross_with_trade_ticks_from_bar_data(self):
        # Arrange
        wrangler = QuoteTickDataWrangler(instrument=self.btcusdt)

        provider = TestDataProvider()

        # Build ticks from bar data
        ticks = wrangler.process_bar_data(
            bid_data=provider.read_csv_bars(
                "ftx-btc-perp-20211231-20220201_1m.csv")[:10000],
            ask_data=provider.read_csv_bars(
                "ftx-btc-perp-20211231-20220201_1m.csv")[:10000],
        )

        self.engine.add_ticks(ticks)

        config = EMACrossConfig(
            instrument_id=str(self.btcusdt.id),
            bar_type="BTCUSDT.BINANCE-1-MINUTE-BID-INTERNAL",
            trade_size=Decimal(0.001),
            fast_ema=10,
            slow_ema=20,
        )
        strategy = EMACross(config=config)
        self.engine.add_strategy(strategy)

        # Act
        self.engine.run()

        # Assert
        assert strategy.fast_ema.count == 10000
        assert self.engine.iteration == 40000
        btc_ending_balance = self.engine.portfolio.account(
            self.venue).balance_total(BTC)
        usdt_ending_balance = self.engine.portfolio.account(
            self.venue).balance_total(USDT)
        assert btc_ending_balance == Money(9.57200000, BTC)
        assert usdt_ending_balance == Money(10017114.27716700, USDT)
Пример #17
0
    def test_run_ema_cross_with_minute_trade_bars(self):
        # Arrange
        wrangler = BarDataWrangler(
            bar_type=BarType.from_str(
                "BTCUSDT.BINANCE-1-MINUTE-LAST-EXTERNAL"),
            instrument=self.btcusdt,
        )

        provider = TestDataProvider()

        # Build externally aggregated bars
        bars = wrangler.process(data=provider.read_csv_bars(
            "ftx-btc-perp-20211231-20220201_1m.csv")[:10000], )

        self.engine.add_bars(bars)

        config = EMACrossConfig(
            instrument_id=str(self.btcusdt.id),
            bar_type="BTCUSDT.BINANCE-1-MINUTE-LAST-EXTERNAL",
            trade_size=Decimal(0.001),
            fast_ema=10,
            slow_ema=20,
        )
        strategy = EMACross(config=config)
        self.engine.add_strategy(strategy)

        # Act
        self.engine.run()

        # Assert
        assert strategy.fast_ema.count == 10000
        assert self.engine.iteration == 10000
        btc_ending_balance = self.engine.portfolio.account(
            self.venue).balance_total(BTC)
        usdt_ending_balance = self.engine.portfolio.account(
            self.venue).balance_total(USDT)
        assert btc_ending_balance == Money(9.57200000, BTC)
        assert usdt_ending_balance == Money(10017114.27716700, USDT)
Пример #18
0
    def test_rerunning_backtest_with_redis_db_builds_correct_index(self):
        # Arrange
        config = EMACrossConfig(
            instrument_id=str(self.usdjpy.id),
            bar_type=str(TestStubs.bartype_usdjpy_1min_bid()),
            trade_size=Decimal(1_000_000),
            fast_ema=10,
            slow_ema=20,
        )
        strategy = EMACross(config=config)
        self.engine.add_strategy(strategy)

        # Generate a lot of data
        self.engine.run()

        # Reset engine
        self.engine.reset()
        self.engine.add_instrument(self.usdjpy)

        # Act
        self.engine.run()

        # Assert
        assert self.engine.cache.check_integrity()
Пример #19
0
    def test_rerun_ema_cross_strategy_returns_identical_performance(self):
        # Arrange
        config = EMACrossConfig(
            instrument_id=str(self.usdjpy.id),
            bar_type="USD/JPY.SIM-15-MINUTE-BID-INTERNAL",
            trade_size=Decimal(1_000_000),
            fast_ema=10,
            slow_ema=20,
        )
        strategy = EMACross(config=config)
        self.engine.add_strategy(strategy)

        self.engine.run()
        result1 = self.engine.trader.analyzer.get_performance_stats_pnls()

        # Act
        self.engine.reset()
        self.engine.add_instrument(
            self.usdjpy)  # TODO(cs): Having to replace instrument
        self.engine.run()
        result2 = self.engine.trader.analyzer.get_performance_stats_pnls()

        # Assert
        assert all(result2) == all(result1)
    # Add an exchange (multiple exchanges possible)
    # Add starting balances for single-currency or multi-currency accounts
    engine.add_venue(
        venue=SIM,
        oms_type=OMSType.HEDGING,  # Venue will generate position IDs
        account_type=AccountType.MARGIN,
        base_currency=USD,  # Standard single-currency account
        starting_balances=[Money(1_000_000, USD)],
        fill_model=fill_model,
        modules=[fx_rollover_interest],
    )

    # Configure your strategy
    config = EMACrossConfig(
        instrument_id=str(AUDUSD_SIM.id),
        bar_type="AUD/USD.SIM-100-TICK-MID-INTERNAL",
        fast_ema_period=10,
        slow_ema_period=20,
        trade_size=Decimal(1_000_000),
        order_id_tag="001",
    )
    # Instantiate and add your strategy
    strategy = EMACross(config=config)
    engine.add_strategy(strategy=strategy)

    input("Press Enter to continue...")  # noqa (always Python 3)

    # Run the engine (from start to end of data)
    engine.run()

    # Optionally view reports
    with pd.option_context(
Пример #21
0
    # Add starting balances for single-currency or multi-currency accounts
    engine.add_venue(
        venue=BINANCE,
        oms_type=OMSType.NETTING,
        account_type=AccountType.CASH,  # Spot cash account
        base_currency=None,  # Multi-currency account
        starting_balances=[Money(1_000_000, USDT),
                           Money(10, ETH)],
        fill_model=fill_model,
    )

    # Configure your strategy
    config = EMACrossConfig(
        instrument_id=str(ETHUSDT_BINANCE.id),
        bar_type="ETHUSDT.BINANCE-250-TICK-LAST-INTERNAL",
        trade_size=Decimal("0.05"),
        fast_ema=10,
        slow_ema=20,
        order_id_tag="001",
    )
    # Instantiate and add your strategy
    strategy = EMACross(config=config)
    engine.add_strategy(strategy=strategy)

    input("Press Enter to continue...")  # noqa (always Python 3)

    # Run the engine (from start to end of data)
    engine.run()

    # Optionally view reports
    with pd.option_context(
            "display.max_rows",
Пример #22
0
        "FTX": {
            # "api_key": "YOUR_FTX_API_KEY",
            # "api_secret": "YOUR_FTX_API_SECRET",
            # "account_id": "YOUR_FTX_ACCOUNT_ID", (optional)
            "sandbox_mode": False,  # If client uses the testnet,
        },
    },
)
# Instantiate the node with a configuration
node = TradingNode(config=config_node)

# Configure your strategy
strat_config = EMACrossConfig(
    instrument_id="ETH/USD.FTX",
    bar_type="ETH/USD.FTX-1-MINUTE-LAST-INTERNAL",
    fast_ema_period=10,
    slow_ema_period=20,
    trade_size=Decimal("0.01"),
    order_id_tag="001",
)
# Instantiate your strategy
strategy = EMACross(config=strat_config)

# Add your strategies and modules
node.trader.add_strategy(strategy)

# Register your client factories with the node (can take user defined factories)
node.add_data_client_factory("FTX", FTXLiveDataClientFactory)
node.add_exec_client_factory("FTX", FTXLiveExecutionClientFactory)
node.build()

# Stop and dispose of the node with SIGINT/CTRL+C
        ),
    },
    timeout_connection=5.0,
    timeout_reconciliation=5.0,
    timeout_portfolio=5.0,
    timeout_disconnection=5.0,
    check_residuals_delay=2.0,
)
# Instantiate the node with a configuration
node = TradingNode(config=config_node)

# Configure your strategy
strat_config = EMACrossConfig(
    instrument_id="ETHUSDT.BINANCE",
    bar_type="ETHUSDT.BINANCE-1-MINUTE-LAST-EXTERNAL",
    fast_ema_period=10,
    slow_ema_period=20,
    trade_size=Decimal("0.005"),
    order_id_tag="001",
)
# Instantiate your strategy
strategy = EMACross(config=strat_config)

# Add your strategies and modules
node.trader.add_strategy(strategy)

# Register your client factories with the node (can take user defined factories)
node.add_data_client_factory("BINANCE", BinanceLiveDataClientFactory)
node.add_exec_client_factory("BINANCE", BinanceLiveExecClientFactory)
node.build()