def main(): # Define the data cache path. hummingsim.set_data_path(os.path.join(os.environ["PWD"], "data")) # Define the parameters for the backtest. start = pd.Timestamp("2018-12-12", tz="UTC") end = pd.Timestamp("2019-01-12", tz="UTC") binance_trading_pair = ("ETHUSDT", "ETH", "USDT") ddex_trading_pair = ("WETH-DAI", "WETH", "DAI") binance_market = BacktestMarket() ddex_market = BacktestMarket() binance_market.config = MarketConfig(AssetType.BASE_CURRENCY, 0.001, AssetType.QUOTE_CURRENCY, 0.001, {}) ddex_market.config = MarketConfig(AssetType.BASE_CURRENCY, 0.001, AssetType.QUOTE_CURRENCY, 0.001, {}) binance_loader = BinanceOrderBookLoaderV2(*binance_trading_pair) ddex_loader = DDEXOrderBookLoader(*ddex_trading_pair) binance_market.add_data(binance_loader) ddex_market.add_data(ddex_loader) binance_market.set_quantization_param( QuantizationParams("ETHUSDT", 5, 3, 5, 3)) ddex_market.set_quantization_param( QuantizationParams("WETH-DAI", 5, 3, 5, 3)) market_pair = CrossExchangeMarketPair( *([ddex_market] + list(ddex_trading_pair) + [binance_market] + list(binance_trading_pair))) strategy = CrossExchangeMarketMakingStrategy( [market_pair], 0.003, logging_options=CrossExchangeMarketMakingStrategy. OPTION_LOG_MAKER_ORDER_FILLED) clock = Clock(ClockMode.BACKTEST, start_time=start.timestamp(), end_time=end.timestamp()) clock.add_iterator(binance_market) clock.add_iterator(ddex_market) clock.add_iterator(strategy) binance_market.set_balance("ETH", 10.0) binance_market.set_balance("USDT", 1000.0) ddex_market.set_balance("WETH", 10.0) ddex_market.set_balance("DAI", 1000.0) clock.backtest() binance_loader.close() ddex_loader.close()
class ClockUnitTest(unittest.TestCase): backtest_start_timestamp: float = pd.Timestamp("2021-01-01", tz="UTC").timestamp() backtest_end_timestamp: float = pd.Timestamp("2021-01-01 01:00:00", tz="UTC").timestamp() tick_size: int = 1 @classmethod def setUpClass(cls): super().setUpClass() cls.ev_loop: asyncio.BaseEventLoop = asyncio.get_event_loop() def setUp(self): super().setUp() self.realtime_start_timestamp = time.time() self.realtime_end_timestamp = self.realtime_start_timestamp + 2.0 # self.clock_realtime = Clock(ClockMode.REALTIME, self.tick_size, self.realtime_start_timestamp, self.realtime_end_timestamp) self.clock_backtest = Clock(ClockMode.BACKTEST, self.tick_size, self.backtest_start_timestamp, self.backtest_end_timestamp) def test_clock_mode(self): self.assertEqual(ClockMode.REALTIME, self.clock_realtime.clock_mode) self.assertEqual(ClockMode.BACKTEST, self.clock_backtest.clock_mode) def test_start_time(self): self.assertEqual(self.realtime_start_timestamp, self.clock_realtime.start_time) self.assertEqual(self.backtest_start_timestamp, self.clock_backtest.start_time) def test_tick_time(self): self.assertEqual(self.tick_size, self.clock_realtime.tick_size) self.assertEqual(self.tick_size, self.clock_backtest.tick_size) def test_child_iterators(self): # Tests child_iterators property after initialization. See also test_add_iterator self.assertEqual(0, len(self.clock_realtime.child_iterators)) self.assertEqual(0, len(self.clock_backtest.child_iterators)) def test_current_timestamp(self): self.assertEqual(self.backtest_start_timestamp, self.clock_backtest.current_timestamp) self.assertAlmostEqual( (self.realtime_start_timestamp // self.tick_size) * self.tick_size, self.clock_realtime.current_timestamp) self.clock_backtest.backtest() self.clock_realtime.backtest() self.assertEqual(self.backtest_end_timestamp, self.clock_backtest.current_timestamp) self.assertLessEqual(self.realtime_end_timestamp, self.clock_realtime.current_timestamp) def test_add_iterator(self): self.assertEqual(0, len(self.clock_realtime.child_iterators)) self.assertEqual(0, len(self.clock_backtest.child_iterators)) time_iterator: TimeIterator = TimeIterator() self.clock_realtime.add_iterator(time_iterator) self.clock_backtest.add_iterator(time_iterator) self.assertEqual(1, len(self.clock_realtime.child_iterators)) self.assertEqual(time_iterator, self.clock_realtime.child_iterators[0]) self.assertEqual(1, len(self.clock_backtest.child_iterators)) self.assertEqual(time_iterator, self.clock_backtest.child_iterators[0]) def test_remove_iterator(self): self.assertEqual(0, len(self.clock_realtime.child_iterators)) self.assertEqual(0, len(self.clock_backtest.child_iterators)) time_iterator: TimeIterator = TimeIterator() self.clock_realtime.add_iterator(time_iterator) self.clock_backtest.add_iterator(time_iterator) self.assertEqual(1, len(self.clock_realtime.child_iterators)) self.assertEqual(time_iterator, self.clock_realtime.child_iterators[0]) self.assertEqual(1, len(self.clock_backtest.child_iterators)) self.assertEqual(time_iterator, self.clock_backtest.child_iterators[0]) self.clock_realtime.remove_iterator(time_iterator) self.clock_backtest.remove_iterator(time_iterator) self.assertEqual(0, len(self.clock_realtime.child_iterators)) self.assertEqual(0, len(self.clock_backtest.child_iterators)) def test_run(self): # Note: Technically you do not execute `run()` when in BACKTEST mode # Tests EnvironmentError raised when not runnning within a context with self.assertRaises(EnvironmentError): self.ev_loop.run_until_complete(self.clock_realtime.run()) # Note: run() will essentially run indefinitely hence the enforced timeout. with self.assertRaises(asyncio.TimeoutError), self.clock_realtime: self.ev_loop.run_until_complete( asyncio.wait_for(self.clock_realtime.run(), 1)) self.assertLess(self.realtime_start_timestamp, self.clock_realtime.current_timestamp) def test_run_til(self): # Note: Technically you do not execute `run_til()` when in BACKTEST mode # Tests EnvironmentError raised when not runnning within a context with self.assertRaises(EnvironmentError): self.ev_loop.run_until_complete( self.clock_realtime.run_til(self.realtime_end_timestamp)) with self.clock_realtime: self.ev_loop.run_until_complete( self.clock_realtime.run_til(self.realtime_end_timestamp)) self.assertGreaterEqual(self.clock_realtime.current_timestamp, self.realtime_end_timestamp) def test_backtest(self): # Note: Technically you do not execute `backtest()` when in REALTIME mode self.clock_backtest.backtest() self.assertGreaterEqual(self.clock_backtest.current_timestamp, self.backtest_end_timestamp) def test_backtest_til(self): # Note: Technically you do not execute `backtest_til()` when in REALTIME mode self.clock_backtest.backtest_til(self.backtest_start_timestamp + self.tick_size) self.assertGreater(self.clock_backtest.current_timestamp, self.clock_backtest.start_time) self.assertLess(self.clock_backtest.current_timestamp, self.backtest_end_timestamp)