def setup(self): # Fixture Setup config = BacktestEngineConfig( bypass_logging=False, run_analysis=False, cache_database=CacheDatabaseConfig(), # default redis cache_db_flush=False, ) self.engine = BacktestEngine(config=config) self.usdjpy = TestInstrumentProvider.default_fx_ccy("USD/JPY") wrangler = QuoteTickDataWrangler(self.usdjpy) 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"), ) self.engine.add_instrument(self.usdjpy) self.engine.add_ticks(ticks) self.engine.add_venue( venue=Venue("SIM"), oms_type=OMSType.HEDGING, account_type=AccountType.MARGIN, base_currency=USD, starting_balances=[Money(1_000_000, USD)], modules=[], ) self.test_redis = redis.Redis(host="localhost", port=6379, db=0)
def setup(self): # Fixture Setup config = BacktestEngineConfig( bypass_logging=True, run_analysis=False, ) self.engine = BacktestEngine(config=config) self.usdjpy = TestInstrumentProvider.default_fx_ccy("USD/JPY") # Setup data wrangler = QuoteTickDataWrangler(self.usdjpy) 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"), ) self.engine.add_instrument(self.usdjpy) self.engine.add_ticks(ticks) self.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=[], )
def setup(self): # Fixture Setup self.engine = BacktestEngine() self.usdjpy = TestInstrumentProvider.default_fx_ccy("USD/JPY") # Setup data wrangler = QuoteTickDataWrangler(self.usdjpy) provider = TestDataProvider() ticks = wrangler.process_bar_data( bid_data=provider.read_csv_bars( "fxcm-usdjpy-m1-bid-2013.csv")[:2000], ask_data=provider.read_csv_bars("fxcm-usdjpy-m1-ask-2013.csv") [:2000], ) self.engine.add_instrument(USDJPY_SIM) self.engine.add_ticks(ticks) self.engine.add_venue( venue=Venue("SIM"), oms_type=OMSType.HEDGING, account_type=AccountType.MARGIN, base_currency=USD, starting_balances=[Money(1_000_000, USD)], fill_model=FillModel(), )
def setup(self): # Fixture Setup config = BacktestEngineConfig( bypass_logging=True, run_analysis=False, ) self.engine = BacktestEngine(config=config) self.venue = Venue("SIM") self.usdjpy = TestInstrumentProvider.default_fx_ccy("USD/JPY") # Setup data wrangler = QuoteTickDataWrangler(instrument=self.usdjpy) 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"), ) self.engine.add_instrument(self.usdjpy) self.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) self.engine.add_venue( venue=self.venue, oms_type=OMSType.HEDGING, account_type=AccountType.MARGIN, base_currency=USD, starting_balances=[Money(1_000_000, USD)], modules=[fx_rollover_interest], )
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_pre_process_bar_data_with_random_seed(self): # Arrange usdjpy = TestInstrumentProvider.default_fx_ccy("USD/JPY") provider = TestDataProvider() bid_data = provider.read_csv_bars("fxcm-usdjpy-m1-bid-2013.csv")[:100] ask_data = provider.read_csv_bars("fxcm-usdjpy-m1-ask-2013.csv")[:100] wrangler = QuoteTickDataWrangler(instrument=usdjpy) # Act ticks = wrangler.process_bar_data( bid_data=bid_data, ask_data=ask_data, default_volume=1000000, random_seed=42, # <-- with random seed ) # Assert assert ticks[0].bid == Price.from_str("91.715") assert ticks[0].ask == Price.from_str("91.717") assert ticks[1].bid == Price.from_str("91.653") assert ticks[1].ask == Price.from_str("91.655") assert ticks[2].bid == Price.from_str("91.715") assert ticks[2].ask == Price.from_str("91.717") assert ticks[3].bid == Price.from_str("91.653") assert ticks[3].ask == Price.from_str("91.655")
def test_pre_process_bar_data_with_delta(self): # Arrange usdjpy = TestInstrumentProvider.default_fx_ccy("USD/JPY") provider = TestDataProvider() bid_data = provider.read_csv_bars("fxcm-usdjpy-m1-bid-2013.csv")[:100] ask_data = provider.read_csv_bars("fxcm-usdjpy-m1-ask-2013.csv")[:100] wrangler = QuoteTickDataWrangler(instrument=usdjpy) # Act ticks = wrangler.process_bar_data( bid_data=bid_data, ask_data=ask_data, default_volume=1000000, ts_init_delta=1_000_500, ) # Assert assert len(ticks) == 400 assert ticks[0].instrument_id == usdjpy.id assert ticks[0].bid == Price.from_str("91.715") assert ticks[0].ask == Price.from_str("91.717") assert ticks[0].bid_size == Quantity.from_int(1000000) assert ticks[0].ask_size == Quantity.from_int(1000000) assert ticks[0].ts_event == 1359676799700000000 assert ticks[0].ts_init == 1359676799701000500 # <-- delta diff
def setup(self): # Fixture Setup config = BacktestEngineConfig( bypass_logging=True, run_analysis=False, ) self.engine = BacktestEngine(config=config) self.venue = Venue("SIM") self.audusd = TestInstrumentProvider.default_fx_ccy("AUD/USD") # Setup data wrangler = QuoteTickDataWrangler(self.audusd) provider = TestDataProvider() ticks = wrangler.process( provider.read_csv_ticks("truefx-audusd-ticks.csv")) self.engine.add_instrument(self.audusd) self.engine.add_ticks(ticks) interest_rate_data = provider.read_csv("short-term-interest.csv") fx_rollover_interest = FXRolloverInterestModule( rate_data=interest_rate_data) self.engine.add_venue( venue=Venue("SIM"), oms_type=OMSType.HEDGING, account_type=AccountType.MARGIN, base_currency=AUD, starting_balances=[Money(1_000_000, AUD)], modules=[fx_rollover_interest], )
def test_run_quote_ticks_through_aggregator_results_in_expected_bars(self): # Arrange bar_store = ObjectStorer() handler = bar_store.store instrument = AUDUSD_SIM bar_spec = BarSpecification(1000, BarAggregation.VOLUME, PriceType.MID) bar_type = BarType(instrument.id, bar_spec) aggregator = VolumeBarAggregator( instrument, bar_type, handler, Logger(TestClock()), ) # Setup data wrangler = QuoteTickDataWrangler(instrument) provider = TestDataProvider() ticks = wrangler.process( data=provider.read_csv_ticks("truefx-audusd-ticks.csv")[:10000], default_volume=1, ) # Act for tick in ticks: aggregator.handle_quote_tick(tick) # Assert last_bar = bar_store.get_store()[-1] assert len(bar_store.get_store()) == 10 assert last_bar.open == Price.from_str("0.670635") assert last_bar.high == Price.from_str("0.670705") assert last_bar.low == Price.from_str("0.670370") assert last_bar.close == Price.from_str("0.670655") assert last_bar.volume == Quantity.from_int(1000)
def setup(): # Arrange 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"), venue_type=VenueType.BROKERAGE, oms_type=OMSType.HEDGING, account_type=AccountType.MARGIN, base_currency=USD, starting_balances=[Money(1_000_000, USD)], fill_model=FillModel(), ) strategies = [TradingStrategy()] start = datetime(2013, 1, 1, 22, 0, 0, 0, tzinfo=pytz.utc) end = datetime(2013, 8, 10, 0, 0, 0, 0, tzinfo=pytz.utc) return (engine, start, end, strategies), {}
def parser(data): if data is None: return data.loc[:, "timestamp"] = pd.to_datetime(data["timestamp"]) instrument = TestInstrumentProvider.default_fx_ccy("AUD/USD") wrangler = QuoteTickDataWrangler(instrument) ticks = wrangler.process(data.set_index("timestamp")) yield from ticks
def test_add_quote_ticks_adds_to_engine(self, capsys): # Arrange engine = BacktestEngine() # Setup data engine.add_instrument(AUDUSD_SIM) wrangler = QuoteTickDataWrangler(AUDUSD_SIM) provider = TestDataProvider() ticks = wrangler.process( provider.read_csv_ticks("truefx-audusd-ticks.csv")) # Act engine.add_ticks(ticks) # Assert log = "".join(capsys.readouterr()) assert "Added 100,000 AUD/USD.SIM QuoteTick elements." in log
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_pre_process_with_tick_data(self): # Arrange instrument = TestInstrumentProvider.btcusdt_binance() wrangler = QuoteTickDataWrangler(instrument=instrument) path = os.path.join(PACKAGE_ROOT, "data", "tardis_quotes.csv") data = TardisQuoteDataLoader.load(path) # Act ticks = wrangler.process( data, ts_init_delta=1_000_501, ) # Assert assert len(ticks) == 9999 assert ticks[0].bid == Price.from_str("9681.92") assert ticks[0].ask == Price.from_str("9682.00") assert ticks[0].bid_size == Quantity.from_str("0.670000") assert ticks[0].ask_size == Quantity.from_str("0.840000") assert ticks[0].ts_event == 1582329603502091776 assert ticks[0].ts_init == 1582329603503092277
def test_process_tick_data(self): # Arrange usdjpy = TestInstrumentProvider.default_fx_ccy("USD/JPY") wrangler = QuoteTickDataWrangler(instrument=usdjpy) provider = TestDataProvider() # Act ticks = wrangler.process( data=provider.read_csv_ticks("truefx-usdjpy-ticks.csv"), default_volume=1000000, ) # Assert assert len(ticks) == 1000 assert ticks[0].instrument_id == usdjpy.id assert ticks[0].bid == Price.from_str("86.655") assert ticks[0].ask == Price.from_str("86.728") assert ticks[0].bid_size == Quantity.from_int(1000000) assert ticks[0].ask_size == Quantity.from_int(1000000) assert ticks[0].ts_event == 1357077600295000064 assert ticks[0].ts_event == 1357077600295000064
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_given_list_of_ticks_aggregates_tick_bars(self): # Arrange instrument = TestInstrumentProvider.default_fx_ccy("USD/JPY") wrangler = QuoteTickDataWrangler(instrument) provider = TestDataProvider() ticks = wrangler.process( provider.read_csv_ticks("truefx-usdjpy-ticks.csv")) bar_store = ObjectStorer() handler = bar_store.store instrument_id = TestStubs.usdjpy_id() bar_spec = BarSpecification(3, BarAggregation.TICK, PriceType.MID) bar_type = BarType(instrument_id, bar_spec) clock = TestClock() logger = Logger(clock) builder = BulkTickBarBuilder(instrument, bar_type, logger, handler) # Act builder.receive(ticks) # Assert assert len(bar_store.get_store()[0]) == 333
if __name__ == "__main__": # Configure backtest engine config = BacktestEngineConfig( trader_id="BACKTESTER-001", ) # Build the backtest engine engine = BacktestEngine(config=config) # Setup trading instruments SIM = Venue("SIM") AUDUSD_SIM = TestInstrumentProvider.default_fx_ccy("AUD/USD", SIM) # Setup data provider = TestDataProvider() wrangler = QuoteTickDataWrangler(instrument=AUDUSD_SIM) ticks = wrangler.process(provider.read_csv_ticks("truefx-audusd-ticks.csv")) engine.add_instrument(AUDUSD_SIM) engine.add_ticks(ticks) # Create a fill model (optional) fill_model = FillModel( prob_fill_on_limit=0.2, prob_fill_on_stop=0.95, prob_slippage=0.5, random_seed=42, ) # Optional plug in module to simulate rollover interest, # the data is coming from packaged test data. interest_rate_data = provider.read_csv("short-term-interest.csv")
# Configure backtest engine config = BacktestEngineConfig( trader_id="BACKTESTER-001", use_data_cache= True, # Pre-cache data for increased performance on repeated runs ) # Build the backtest engine engine = BacktestEngine(config=config) # Setup trading instruments SIM = Venue("SIM") GBPUSD_SIM = TestInstrumentProvider.default_fx_ccy("GBP/USD", SIM) # Setup data provider = TestDataProvider() wrangler = QuoteTickDataWrangler(GBPUSD_SIM) ticks = wrangler.process_bar_data( bid_data=provider.read_csv_bars("fxcm-gbpusd-m1-bid-2012.csv"), ask_data=provider.read_csv_bars("fxcm-gbpusd-m1-ask-2012.csv"), ) engine.add_instrument(GBPUSD_SIM) engine.add_ticks(ticks) # Create a fill model (optional) fill_model = FillModel( prob_fill_on_limit=0.2, prob_fill_on_stop=0.95, prob_slippage=0.5, random_seed=42, )