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), {}
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)
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)
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_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)
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)
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)
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)
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)
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)
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()
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,
}, ) # 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()