예제 #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)
        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), {}
예제 #3
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)
예제 #4
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]), {}
    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)
예제 #8
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)
예제 #9
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)
예제 #10
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)
예제 #11
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)
예제 #12
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)
예제 #13
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)
예제 #14
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)
예제 #15
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()
예제 #16
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)
        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(
        "display.max_rows",
        100,
        "display.max_columns",
        None,
        "display.width",
        300,
예제 #18
0
    },
)
# 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
if __name__ == "__main__":
    try:
        node.start()
    finally:
        node.dispose()