def setUp(self): # Fixture Setup # Fresh isolated loop testing pattern self.loop = asyncio.new_event_loop() asyncio.set_event_loop(self.loop) config = { "trader": { "name": "tester", "id_tag": "000", }, "logging": { "log_level_console": "INF", "log_level_file": "DBG", "log_level_store": "WRN", }, "exec_database": { "type": "in-memory", }, "strategy": { "load_state": True, "save_state": True, }, "data_clients": {}, "exec_clients": {}, } self.node = TradingNode( strategies=[TradingStrategy("000")], config=config, )
def test_get_event_loop_returns_a_loop(self): # Arrange node = TradingNode() # Act loop = node.get_event_loop() # Assert assert isinstance(loop, asyncio.AbstractEventLoop)
def test_config_with_inmemory_execution_database(self): # Arrange config = TradingNodeConfig(cache_database=CacheDatabaseConfig( type="in-memory")) # Act node = TradingNode(config=config) # Assert assert node is not None
def test_config_with_redis_execution_database(self): # Arrange config = { "trader": { "name": "tester", "id_tag": "000", }, "logging": { "log_level_console": "INF", "log_level_file": "DBG", "log_level_store": "WRN", "run_in_process": False # Avoid pytest hanging on multiprocessing resources }, "exec_database": { "type": "redis", "host": "localhost", "port": 6379, }, "strategy": { "load_state": True, "save_state": True, }, "data_clients": { "oanda": { "api_token": "OANDA_API_TOKEN", # value is the environment variable name "account_id": "OANDA_ACCOUNT_ID", # value is the environment variable name }, }, "exec_clients": { "oanda": { "api_token": "OANDA_API_TOKEN", # value is the environment variable name "account_id": "OANDA_ACCOUNT_ID", # value is the environment variable name }, } } # Act node = TradingNode( strategies=[TradingStrategy("000")], config=config, ) # Assert self.assertIsNotNone(node)
def test_config_with_inmemory_execution_database(self): # Arrange config = { "trader": { "name": "tester", "id_tag": "000", }, "logging": { "log_level_console": "INF", "log_level_file": "DBG", "log_level_store": "WRN", "run_in_process": False # Avoid pytest hanging on multiprocessing resources }, "exec_database": { "type": "in-memory", }, "strategy": { "load_state": True, "save_state": True, }, "data_clients": { "binance": { "api_key": "BINANCE_API_KEY", # value is the environment variable name "api_secret": "BINANCE_API_SECRET", # value is the environment variable name }, }, "exec_clients": { "binance": { "api_key": "BINANCE_API_KEY", # value is the environment variable name "api_secret": "BINANCE_API_SECRET", # value is the environment variable name }, } } # Act node = TradingNode( strategies=[TradingStrategy("000")], config=config, ) # Assert self.assertIsNotNone(node)
"market_id": market_id }, }, }, } # Instantiate your strategies to pass into the trading node. You could add # custom options into the configuration file or even use another configuration # file. strategy = BetfairTestStrategy( instrument_filter={"market_id": market_id}, trade_size=Decimal(10.0), order_id_tag="001", ) # Instantiate the node passing a list of strategies and configuration node = TradingNode(strategies=[strategy], config=config) # Register your client factories with the node (can take user defined factories) node.add_data_client_factory("BETFAIR", BetfairLiveDataClientFactory) node.add_exec_client_factory("BETFAIR", BetfairLiveExecutionClientFactory) node.build() # Stop and dispose of the node with SIGINT/CTRL+C if __name__ == "__main__": try: node.start() finally: node.dispose()
class TradingNodeOperationTests(unittest.TestCase): def setUp(self): # Fixture Setup # Fresh isolated loop testing pattern self.loop = asyncio.new_event_loop() asyncio.set_event_loop(self.loop) config = { "trader": { "name": "tester", "id_tag": "000", }, "logging": { "log_level_console": "INF", "log_level_file": "DBG", "log_level_store": "WRN", }, "exec_database": { "type": "in-memory", }, "strategy": { "load_state": True, "save_state": True, }, "data_clients": {}, "exec_clients": {}, } self.node = TradingNode( strategies=[TradingStrategy("000")], config=config, ) def test_get_event_loop_returns_a_loop(self): # Arrange # Act loop = self.node.get_event_loop() # Assert self.assertTrue(isinstance(loop, asyncio.AbstractEventLoop)) def test_start(self): # Arrange run = threading.Thread(target=self.node.start, daemon=True) run.start() time.sleep(0.3) # Act # Assert self.assertEqual(ComponentState.RUNNING, self.node.trader.state) self.node.stop() def test_stop(self): # Arrange run = threading.Thread(target=self.node.start, daemon=True) run.start() # Allow node to start time.sleep(0.3) self.loop.call_soon_threadsafe(self.node.stop) # Allow node to stop time.sleep(3) # Act # Assert self.assertEqual(ComponentState.STOPPED, self.node.trader.state) def test_dispose(self): # Arrange run = threading.Thread(target=self.node.start, daemon=True) run.start() # Allow node to start time.sleep(0.3) self.loop.call_soon_threadsafe(self.node.stop) # Allow node to stop time.sleep(3) self.node.dispose() # Act # Assert self.assertEqual(ComponentState.DISPOSED, self.node.trader.state)
# "api_secret": "YOUR_FTX_API_SECRET", # "account_id": "YOUR_FTX_ACCOUNT_ID", (optional) "sandbox_mode": False, # If client uses the testnet }, }, exec_clients={ "FTX": { # "api_key": "YOUR_FTX_API_KEY", # "api_secret": "YOUR_FTX_API_SECRET", # "account_id": "YOUR_FTX_ACCOUNT_ID", (optional) "sandbox_mode": False, # If client uses the testnet, }, }, ) # 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)
base_url_ws=None, # Override with custom endpoint us=False, # If client is for Binance US testnet=False, # If client uses the testnet load_all_instruments=True, # If load all instruments on start load_instrument_ids=[], # Optionally pass a list of instrument IDs instrument_provider=InstrumentProviderConfig(load_all=True), ), }, timeout_connection=5.0, timeout_reconciliation=5.0, timeout_portfolio=5.0, timeout_disconnection=5.0, check_residuals_delay=2.0, ) # Instantiate the node with a configuration node = TradingNode(config=config_node) # Configure your strategy strat_config = EMACrossConfig( instrument_id="ETHUSDT.BINANCE", bar_type="ETHUSDT.BINANCE-1-MINUTE-LAST-EXTERNAL", fast_ema_period=10, slow_ema_period=20, trade_size=Decimal("0.005"), order_id_tag="001", ) # Instantiate your strategy strategy = EMACross(config=strat_config) # Add your strategies and modules node.trader.add_strategy(strategy)
async def main(market_id: str): # Connect to Betfair client early to load instruments and account currency loop = asyncio.get_event_loop() logger = LiveLogger(loop=loop, clock=LiveClock()) client = get_cached_betfair_client( username= None, # Pass here or will source from the `BETFAIR_USERNAME` env var password= None, # Pass here or will source from the `BETFAIR_PASSWORD` env var app_key= None, # Pass here or will source from the `BETFAIR_APP_KEY` env var cert_dir= None, # Pass here or will source from the `BETFAIR_CERT_DIR` env var logger=logger, loop=loop, ) await client.connect() # Find instruments for a particular market_id market_filter = {"market_id": (market_id, )} provider = get_cached_betfair_instrument_provider( client=client, logger=logger, market_filter=tuple(market_filter.items()), ) await provider.load_all_async() instruments = provider.list_all() print(f"Found instruments:\n{instruments}") # Determine account currency account = await client.get_account_details() # Configure trading node config = TradingNodeConfig( timeout_connection=30.0, log_level="DEBUG", cache_database=CacheDatabaseConfig(type="in-memory"), exec_engine={"allow_cash_positions": True}, # Retain original behaviour for now data_clients={ "BETFAIR": { # "username": "******", # "password": "******", # "app_key": "YOUR_BETFAIR_APP_KEY", # "cert_dir": "YOUR_BETFAIR_CERT_DIR", "market_filter": market_filter, }, }, exec_clients={ "BETFAIR": { "base_currency": account["currencyCode"], # "username": "******", # "password": "******", # "app_key": "YOUR_BETFAIR_APP_KEY", # "cert_dir": "YOUR_BETFAIR_CERT_DIR", "market_filter": market_filter, }, }, ) strategies = [ OrderBookImbalance(config=OrderBookImbalanceConfig( instrument_id=instrument.id.value, max_trade_size=10, order_id_tag=instrument.selection_id, )) for instrument in instruments ] # Setup TradingNode node = TradingNode(config=config) node.trader.add_strategies(strategies) # Register your client factories with the node (can take user defined factories) node.add_data_client_factory("BETFAIR", BetfairLiveDataClientFactory) node.add_exec_client_factory("BETFAIR", BetfairLiveExecClientFactory) node.build() try: await node.start() except Exception as ex: print(ex) print(traceback.format_exc()) finally: node.dispose()
) strategy3 = EMACross( instrument_id=instrument3, bar_spec=BarSpecification(1, BarAggregation.MINUTE, PriceType.MID), fast_ema_period=10, slow_ema_period=20, trade_size=Decimal(10000), order_id_tag="003", ) strategies = [ strategy1, strategy2, strategy3, ] # Instantiate the node passing a list of strategies and configuration node = TradingNode(strategies=strategies, config=config) # Register your client factories with the node (can take user defined factories) node.add_data_client_factory("OANDA", OandaDataClientFactory) node.build() # Stop and dispose of the node with SIGINT/CTRL+C if __name__ == "__main__": try: node.start() finally: node.dispose()
def setup(self): # Fixture Setup self.node = TradingNode()
class TestTradingNodeOperation: def setup(self): # Fixture Setup self.node = TradingNode() def test_get_event_loop_returns_a_loop(self): # Arrange node = TradingNode() # Act loop = node.get_event_loop() # Assert assert isinstance(loop, asyncio.AbstractEventLoop) def test_build_called_twice_raises_runtime_error(self): # Arrange, # Act with pytest.raises(RuntimeError): self.node.build() self.node.build() def test_start_when_not_built_raises_runtime_error(self): # Arrange, # Act with pytest.raises(RuntimeError): self.node.start() def test_add_data_client_factory(self): # Arrange, # Act self.node.add_data_client_factory("BETFAIR", BetfairLiveDataClientFactory) self.node.build() # TODO(cs): Assert existence of client def test_add_exec_client_factory(self): # Arrange, # Act self.node.add_exec_client_factory("BETFAIR", BetfairLiveExecutionClientFactory) self.node.build() # TODO(cs): Assert existence of client def test_build_with_multiple_clients(self): # Arrange, # Act self.node.add_data_client_factory("BETFAIR", BetfairLiveDataClientFactory) self.node.add_exec_client_factory("BETFAIR", BetfairLiveExecutionClientFactory) self.node.build() # TODO(cs): Assert existence of client @pytest.mark.asyncio async def test_register_log_sink(self): # Arrange sink = [] # Act self.node.add_log_sink(sink.append) self.node.build() self.node.start() await asyncio.sleep(1) # Assert: Log record received assert sink[-1]["trader_id"] == self.node.trader_id.value assert sink[-1]["machine_id"] == self.node.machine_id assert sink[-1]["instance_id"] == self.node.instance_id.value @pytest.mark.asyncio async def test_start(self): # Arrange self.node.build() # Act self.node.start() await asyncio.sleep(2) # Assert assert self.node.trader.is_running @pytest.mark.asyncio async def test_stop(self): # Arrange self.node.build() self.node.start() await asyncio.sleep(2) # Allow node to start # Act self.node.stop() await asyncio.sleep(3) # Allow node to stop # Assert assert self.node.trader.is_stopped @pytest.mark.skip(reason="refactor TradingNode coroutines") @pytest.mark.asyncio async def test_dispose(self): # Arrange self.node.build() self.node.start() await asyncio.sleep(2) # Allow node to start self.node.stop() await asyncio.sleep(2) # Allow node to stop # Act self.node.dispose() await asyncio.sleep(1) # Allow node to dispose # Assert assert self.node.trader.is_disposed
def test_config_with_redis_execution_database(self): # Arrange, Act node = TradingNode() # Assert assert node is not None
instrument_id = InstrumentId( symbol=Symbol("BTC/USD"), venue=Venue("BITMEX"), ) strategy = VolatilityMarketMaker( instrument_id=instrument_id, bar_spec=BarSpecification(1, BarAggregation.MINUTE, PriceType.LAST), trade_size=Decimal("10"), atr_period=20, atr_multiple=1.5, order_id_tag="091", ) # Instantiate the node passing a list of strategies and configuration node = TradingNode(strategies=[strategy], config=config) # Register your client factories with the node (can take user defined factories) node.add_data_client_factory("CCXT", CCXTDataClientFactory) node.add_exec_client_factory("CCXT", CCXTExecutionClientFactory) node.build() # Stop and dispose of the node with SIGINT/CTRL+C if __name__ == "__main__": try: node.start() finally: node.dispose()
) strategy2 = EMACross( symbol=Symbol("EUR/USD", Venue("OANDA")), bar_spec=BarSpecification(1, BarAggregation.MINUTE, PriceType.MID), fast_ema=10, slow_ema=20, trade_size=Decimal(10000), ) strategy3 = EMACross( symbol=Symbol("GBP/USD", Venue("OANDA")), bar_spec=BarSpecification(1, BarAggregation.MINUTE, PriceType.MID), fast_ema=10, slow_ema=20, trade_size=Decimal(10000), ) # Instantiate the node passing a list of strategies and configuration node = TradingNode( strategies=[strategy1, strategy2, strategy3], config=config, ) # Stop and dispose of the node with SIGINT/CTRL+C if __name__ == "__main__": try: node.start() finally: node.dispose()
# ] # strategies_cfd = [] # for symbol in symbols_cfd: # strategies_fx.append(EMACrossPy( # symbol, # BAR_SPEC_CFD, # risk_bp=10.0, # fast_ema=10, # slow_ema=20, # atr_period=20)) strategies = strategies_fx # + strategies_cfd if __name__ == "__main__": node = TradingNode(config_path='config.json', strategies=strategies) node.connect() time.sleep(1) node.start() input() node.stop() input() node.disconnect() input() node.dispose()
"api_key": "BINANCE_API_KEY", # value is the environment variable key "api_secret": "BINANCE_API_SECRET", # value is the environment variable key "sandbox_mode": False, # If clients use the testnet }, }, } # Instantiate your strategies to pass into the trading node. You could add # custom options into the configuration file or even use another configuration # file. strategy = EMACross( symbol=Symbol("ETH/USDT", Venue("BINANCE")), bar_spec=BarSpecification(1, BarAggregation.MINUTE, PriceType.LAST), fast_ema_period=10, slow_ema_period=20, trade_size=Decimal("0.05"), order_id_tag="001", ) # Instantiate the node passing a list of strategies and configuration node = TradingNode(strategies=[strategy], config=config) # Stop and dispose of the node with SIGINT/CTRL+C if __name__ == "__main__": try: node.start() finally: node.dispose()
), routing=RoutingConfig(venues={"IDEALPRO"}), ), }, # exec_clients={ # "IB": InteractiveBrokersExecClientConfig(), # }, timeout_connection=90.0, timeout_reconciliation=5.0, timeout_portfolio=5.0, timeout_disconnection=5.0, check_residuals_delay=2.0, ) # Instantiate the node with a configuration node = TradingNode(config=config_node) # Configure your strategy strategy_config = SubscribeStrategyConfig( instrument_id="EUR/USD.IDEALPRO", book_type=BookType.L2_MBP, snapshots=True, # trade_ticks=True, # quote_ticks=True, ) # Instantiate your strategy strategy = SubscribeStrategy(config=strategy_config) # Add your strategies and modules node.trader.add_strategy(strategy)