def test_can_run_multiple_strategies(self): # Arrange strategies = [ EMACross(symbol=self.usdjpy.symbol, bar_spec=TestStubs.bar_spec_1min_bid(), risk_bp=10, fast_ema=10, slow_ema=20, atr_period=20, sl_atr_multiple=2.0, extra_id_tag='001'), EMACross(symbol=self.usdjpy.symbol, bar_spec=TestStubs.bar_spec_1min_bid(), risk_bp=10, fast_ema=10, slow_ema=20, atr_period=20, sl_atr_multiple=2.0, extra_id_tag='002') ] start = datetime(2013, 1, 2, 0, 0, 0, 0) stop = datetime(2013, 1, 3, 0, 0, 0, 0) # Act self.engine.run(start, stop, strategies=strategies) # Assert self.assertEqual(559, strategies[0].fast_ema.count) self.assertEqual(559, strategies[1].fast_ema.count)
def test_run_multiple_strategies(self): # Arrange strategy1 = EMACross( instrument_id=self.usdjpy.id, bar_spec=BarSpecification(15, BarAggregation.MINUTE, PriceType.BID), trade_size=Decimal(1_000_000), fast_ema=10, slow_ema=20, extra_id_tag="001", ) strategy2 = EMACross( instrument_id=self.usdjpy.id, bar_spec=BarSpecification(15, BarAggregation.MINUTE, PriceType.BID), trade_size=Decimal(1_000_000), fast_ema=20, slow_ema=40, extra_id_tag="002", ) # 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. # Act self.engine.run(strategies=[strategy1, strategy2]) # Assert self.assertEqual(2689, strategy1.fast_ema.count) self.assertEqual(2689, strategy2.fast_ema.count) self.assertEqual(115043, self.engine.iteration) self.assertEqual(Money(994662.69, USD), self.engine.portfolio.account(self.venue).balance())
def test_run_for_tick_processing(): # Arrange data = BacktestDataContainer() data.add_instrument(USDJPY_SIM) data.add_bars(USDJPY_SIM.symbol, BarAggregation.MINUTE, PriceType.BID, TestDataProvider.usdjpy_1min_bid()) data.add_bars(USDJPY_SIM.symbol, BarAggregation.MINUTE, PriceType.ASK, TestDataProvider.usdjpy_1min_ask()) strategy = EMACross( symbol=USDJPY_SIM.symbol, bar_spec=TestStubs.bar_spec_1min_bid(), trade_size=Decimal(1_000_000), fast_ema=10, slow_ema=20, ) engine = BacktestEngine( data=data, strategies=[strategy], bypass_logging=True, ) engine.add_exchange( venue=Venue("SIM"), oms_type=OMSType.HEDGING, starting_balances=[Money(1_000_000, USD)], ) start = datetime(2013, 2, 1, 0, 0, 0, 0, tzinfo=pytz.utc) stop = datetime(2013, 2, 10, 0, 0, 0, 0, tzinfo=pytz.utc) stats_file = "perf_stats_tick_processing.prof" cProfile.runctx("engine.run(start, stop)", globals(), locals(), stats_file) s = pstats.Stats(stats_file) s.strip_dirs().sort_stats("time").print_stats()
def test_run_with_ema_cross_strategy(): # Arrange engine = BacktestEngine(bypass_logging=True) engine.add_instrument(USDJPY_SIM) engine.add_bars( USDJPY_SIM.id, BarAggregation.MINUTE, PriceType.BID, TestDataProvider.usdjpy_1min_bid(), ) engine.add_bars( USDJPY_SIM.id, BarAggregation.MINUTE, PriceType.ASK, TestDataProvider.usdjpy_1min_ask(), ) 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], ) strategy = EMACross( instrument_id=USDJPY_SIM.id, bar_spec=TestStubs.bar_spec_1min_bid(), trade_size=Decimal(1_000_000), fast_ema=10, slow_ema=20, ) start = datetime(2013, 2, 1, 0, 0, 0, 0, tzinfo=pytz.utc) stop = datetime(2013, 3, 1, 0, 0, 0, 0, tzinfo=pytz.utc) stats_file = "perf_stats_backtest_run_ema.prof" cProfile.runctx( "engine.run(start, stop, strategies=[strategy])", globals(), locals(), stats_file, ) s = pstats.Stats(stats_file) s.strip_dirs().sort_stats("time").print_stats()
def test_run_for_tick_processing(): # Arrange engine = BacktestEngine(bypass_logging=True) engine.add_instrument(USDJPY_SIM) engine.add_bars( USDJPY_SIM.id, BarAggregation.MINUTE, PriceType.BID, TestDataProvider.usdjpy_1min_bid(), ) engine.add_bars( USDJPY_SIM.id, BarAggregation.MINUTE, PriceType.ASK, TestDataProvider.usdjpy_1min_ask(), ) 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)], ) strategy = EMACross( instrument_id=USDJPY_SIM.id, bar_spec=TestStubs.bar_spec_1min_bid(), trade_size=Decimal(1_000_000), fast_ema=10, slow_ema=20, ) start = datetime(2013, 2, 1, 0, 0, 0, 0, tzinfo=pytz.utc) stop = datetime(2013, 2, 10, 0, 0, 0, 0, tzinfo=pytz.utc) stats_file = "perf_stats_tick_processing.prof" cProfile.runctx( "engine.run(start, stop, strategies=[strategy])", globals(), locals(), stats_file, ) s = pstats.Stats(stats_file) s.strip_dirs().sort_stats("time").print_stats()
def test_run_ema_cross_with_minute_bar_spec(self): # Arrange strategy = EMACross( symbol=self.gbpusd.symbol, bar_spec=BarSpecification(5, BarAggregation.MINUTE, PriceType.MID), trade_size=Decimal(1_000_000), fast_ema=10, slow_ema=20, ) # Act self.engine.run(strategies=[strategy]) # Assert self.assertEqual(8353, strategy.fast_ema.count) self.assertEqual(120467, self.engine.iteration) self.assertEqual(Money(947226.84, GBP), self.engine.portfolio.account(self.venue).balance())
def test_run_ema_cross_with_tick_bar_spec(self): # Arrange strategy = EMACross( symbol=self.instrument.symbol, bar_spec=BarSpecification(250, BarAggregation.TICK, PriceType.LAST), trade_size=Decimal(100), fast_ema=10, slow_ema=20, ) # Act self.engine.run(strategies=[strategy]) # Assert self.assertEqual(39, strategy.fast_ema.count) self.assertEqual(19998, self.engine.iteration) self.assertEqual(Money('995991.41500000', USDT), self.engine.portfolio.account(self.venue).balance())
def test_run_ema_cross_strategy(self): # Arrange strategy = EMACross( symbol=self.usdjpy.symbol, bar_spec=BarSpecification(15, BarAggregation.MINUTE, PriceType.BID), trade_size=Decimal(1_000_000), fast_ema=10, slow_ema=20, ) # Act self.engine.run(strategies=[strategy]) # Assert - Should return expected PnL self.assertEqual(2689, strategy.fast_ema.count) self.assertEqual(115043, self.engine.iteration) self.assertEqual(Money(997731.21, USD), self.engine.portfolio.account(self.venue).balance())
def test_run_ema_cross_with_tick_bar_spec(self): # Arrange strategy = EMACross( symbol=self.audusd.symbol, bar_spec=BarSpecification(100, BarAggregation.TICK, PriceType.MID), trade_size=Decimal(1_000_000), fast_ema=10, slow_ema=20, ) # Act self.engine.run(strategies=[strategy]) # Assert self.assertEqual(999, strategy.fast_ema.count) self.assertEqual(99999, self.engine.iteration) self.assertEqual(Money(995431.92, AUD), self.engine.portfolio.account(self.venue).balance())
def test_run_ema_cross_with_minute_bar_spec(self): # Arrange strategy = EMACross( instrument_id=self.audusd.id, bar_spec=BarSpecification(1, BarAggregation.MINUTE, PriceType.MID), trade_size=Decimal(1_000_000), fast_ema=10, slow_ema=20, ) # Act self.engine.run(strategies=[strategy]) # Assert self.assertEqual(1771, strategy.fast_ema.count) self.assertEqual(99999, self.engine.iteration) self.assertEqual(Money(991360.19, AUD), self.engine.portfolio.account(self.venue).balance())
def test_run_ema_cross_with_tick_bar_spec(self): # Arrange strategy = EMACross( instrument_id=self.ethusdt.id, bar_spec=BarSpecification(250, BarAggregation.TICK, PriceType.LAST), trade_size=Decimal(100), fast_ema=10, slow_ema=20, ) # Act self.engine.run(strategies=[strategy]) # Assert self.assertEqual(279, strategy.fast_ema.count) self.assertEqual(69806, self.engine.iteration) self.assertEqual(Money("998873.43110000", USDT), self.engine.portfolio.account(self.venue).balance())
def test_rerunning_backtest_with_redis_db_builds_correct_index(self): # Arrange strategy = EMACross( instrument_id=self.usdjpy.id, bar_spec=BarSpecification(15, BarAggregation.MINUTE, PriceType.BID), trade_size=Decimal(1_000_000), fast_ema=10, slow_ema=20, ) # Generate a lot of data self.engine.run(strategies=[strategy]) # Reset engine self.engine.reset() self.engine.run() # Act # Assert self.assertTrue(self.engine.get_exec_engine().cache.check_integrity())
def test_run_ema_cross_strategy(self): # Arrange strategies = [ EMACross(symbol=self.usdjpy.symbol, bar_spec=TestStubs.bar_spec_1min_bid(), fast_ema=10, slow_ema=20) ] start = datetime(2013, 1, 2, 0, 0, 0, 0) stop = datetime(2013, 1, 3, 0, 0, 0, 0) # Act self.engine.run(start, stop, strategies=strategies) # Assert self.assertEqual(559, strategies[0].fast_ema.count) self.assertEqual(-1857.67, self.engine.analyzer.get_performance_stats() ['PNL']) # Money represented as double here
def test_rerun_ema_cross_strategy_returns_identical_performance(self): # Arrange strategy = EMACross( symbol=self.usdjpy.symbol, bar_spec=BarSpecification(15, BarAggregation.MINUTE, PriceType.BID), trade_size=Decimal(1_000_000), fast_ema=10, slow_ema=20, ) self.engine.run(strategies=[strategy]) result1 = self.engine.analyzer.get_performance_stats_pnls() # Act self.engine.reset() self.engine.run() result2 = self.engine.analyzer.get_performance_stats_pnls() # Assert self.assertEqual(all(result1), all(result2))
def test_exec_cache_check_integrity_when_index_cleared_fails(self): # Arrange strategy = EMACross( symbol=self.usdjpy.symbol, bar_spec=BarSpecification(15, BarAggregation.MINUTE, PriceType.BID), trade_size=Decimal(1_000_000), fast_ema=10, slow_ema=20, ) # Generate a lot of data self.engine.run(strategies=[strategy]) # Clear index self.cache.clear_index() # Act # Assert self.assertFalse(self.cache.check_integrity())
def test_rerun_ema_cross_strategy_returns_identical_performance(self): # Arrange strategies = [ EMACross(symbol=self.usdjpy.symbol, bar_spec=TestStubs.bar_spec_1min_bid(), fast_ema=10, slow_ema=20) ] start = datetime(2013, 1, 2, 0, 0, 0, 0) stop = datetime(2013, 1, 3, 0, 0, 0, 0) self.engine.run(start, stop, strategies=strategies) result1 = self.engine.analyzer.get_performance_stats() # Act self.engine.run(start, stop) result2 = self.engine.analyzer.get_performance_stats() # Assert self.assertEqual(all(result1), all(result2))
def test_run_for_tick_processing(self): # Arrange usdjpy = InstrumentLoader.default_fx_ccy(TestStubs.symbol_usdjpy_fxcm()) data = BacktestDataContainer() data.add_instrument(usdjpy) data.add_bars(usdjpy.symbol, BarAggregation.MINUTE, PriceType.BID, TestDataProvider.usdjpy_1min_bid()) data.add_bars(usdjpy.symbol, BarAggregation.MINUTE, PriceType.ASK, TestDataProvider.usdjpy_1min_ask()) strategies = [EMACross( symbol=usdjpy.symbol, bar_spec=TestStubs.bar_spec_1min_bid(), fast_ema=10, slow_ema=20)] config = BacktestConfig( exec_db_type="in-memory", bypass_logging=True, console_prints=False) engine = BacktestEngine( data=data, strategies=strategies, venue=Venue("FXCM"), oms_type=OMSType.HEDGING, generate_position_ids=True, config=config, fill_model=None, ) start = datetime(2013, 2, 1, 0, 0, 0, 0, tzinfo=pytz.utc) stop = datetime(2013, 2, 10, 0, 0, 0, 0, tzinfo=pytz.utc) stats_file = "perf_stats_tick_processing.prof" cProfile.runctx("engine.run(start, stop)", globals(), locals(), stats_file) s = pstats.Stats(stats_file) s.strip_dirs().sort_stats("time").print_stats() self.assertTrue(True)
def test_run_for_tick_processing(self): # Arrange usdjpy = TestStubs.instrument_usdjpy() data = BacktestDataContainer() data.add_instrument(usdjpy) data.add_bars(usdjpy.symbol, BarStructure.MINUTE, PriceType.BID, TestDataProvider.usdjpy_1min_bid()) data.add_bars(usdjpy.symbol, BarStructure.MINUTE, PriceType.ASK, TestDataProvider.usdjpy_1min_ask()) strategies = [EMACross( symbol=usdjpy.symbol, bar_spec=TestStubs.bar_spec_1min_bid(), risk_bp=10, fast_ema=10, slow_ema=20, atr_period=20, sl_atr_multiple=2.0)] config = BacktestConfig( exec_db_type='in-memory', bypass_logging=True, console_prints=False) engine = BacktestEngine( data=data, strategies=strategies, config=config, fill_model=None) start = datetime(2013, 2, 1, 0, 0, 0, 0, tzinfo=timezone.utc) stop = datetime(2013, 2, 10, 0, 0, 0, 0, tzinfo=timezone.utc) stats_file = 'perf_stats_tick_processing.prof' cProfile.runctx('engine.run(start, stop)', globals(), locals(), stats_file) s = pstats.Stats(stats_file) s.strip_dirs().sort_stats("time").print_stats() self.assertTrue(True)
# BAR_SPEC_FX = BarSpecification(100, BarStructure.TICK, PriceType.BID) # BAR_SPEC_CFD = BarSpecification(500, BarStructure.TICK, PriceType.BID) symbols_fx = [ Symbol('AUD/USD', Venue('FXCM')), Symbol('EUR/USD', Venue('FXCM')), Symbol('GBP/USD', Venue('FXCM')), Symbol('USD/JPY', Venue('FXCM')), ] strategies_fx = [] for symbol in symbols_fx: strategies_fx.append( EMACross(symbol, BAR_SPEC_FX, risk_bp=10.0, fast_ema=10, slow_ema=20, atr_period=20)) # symbols_cfd = [ # Symbol('XAUUSD', Venue('FXCM')), # Symbol('SPX500', Venue('FXCM')), # Symbol('AUS200', Venue('FXCM')), # Symbol('USOil', Venue('FXCM')), # Symbol('GER30', Venue('FXCM')), # ] # strategies_cfd = [] # for symbol in symbols_cfd: # strategies_fx.append(EMACrossPy( # symbol,