def l1_feed(): updates = [] for _, row in TestDataProvider.usdjpy_ticks().iterrows(): for side, order_side in zip( ("bid", "ask"), (OrderSide.BUY, OrderSide.SELL) ): updates.append( { "op": "update", "order": Order( price=Price(row[side], precision=6), size=Quantity(1e9, precision=2), side=order_side, ), } ) return updates
def test_add_position(self): # Arrange order = self.strategy.order_factory.market( AUDUSD_SIM.symbol, OrderSide.BUY, Quantity(100000), ) position_id = PositionId('P-1') self.cache.add_order(order, position_id) order_filled = TestStubs.event_order_filled( order, instrument=AUDUSD_SIM, position_id=PositionId('P-1'), fill_price=Price("1.00000"), ) position = Position(order_filled) # Act self.cache.add_position(position) # Assert self.assertTrue(self.cache.position_exists(position.id)) self.assertIn(position.id, self.cache.position_ids()) self.assertIn(position, self.cache.positions()) self.assertIn(position, self.cache.positions_open()) self.assertIn(position, self.cache.positions_open(symbol=position.symbol)) self.assertIn(position, self.cache.positions_open(strategy_id=self.strategy.id)) self.assertIn( position, self.cache.positions_open(symbol=position.symbol, strategy_id=self.strategy.id)) self.assertNotIn(position, self.cache.positions_closed()) self.assertNotIn(position, self.cache.positions_closed(symbol=position.symbol)) self.assertNotIn( position, self.cache.positions_closed(strategy_id=self.strategy.id)) self.assertNotIn( position, self.cache.positions_closed(symbol=position.symbol, strategy_id=self.strategy.id))
def test_update_order_raises_not_implemented_error(self): # Arrange # Act command = UpdateOrder( AUDUSD_SIM.id, self.trader_id, self.account_id, ClientOrderId("O-123456789"), Quantity(120000), Price("1.00000"), self.uuid_factory.generate(), self.clock.timestamp_ns(), ) # Assert self.assertRaises(NotImplementedError, self.client.update_order, command)
def _on_order_modify(self, trade: IBTrade): instrument_id = self._instrument_provider.contract_id_to_instrument_id[trade.contract.conId] instrument: Instrument = self._cache.instrument(instrument_id) client_order_id = self._venue_order_id_to_client_order_id[trade.order.orderId] strategy_id = self._client_order_id_to_strategy_id[client_order_id] venue_order_id = VenueOrderId(str(trade.orderStatus.permId)) self.generate_order_updated( strategy_id=strategy_id, instrument_id=instrument_id, client_order_id=client_order_id, venue_order_id=venue_order_id, quantity=Quantity(trade.order.totalQuantity, precision=instrument.size_precision), price=Price(trade.order.lmtPrice, precision=instrument.price_precision), trigger_price=None, ts_event=dt_to_unix_nanos(trade.log[-1].time), venue_order_id_modified=False, # TODO - does this happen? )
def test_to_serializable_returns_expected_string(self): # Arrange tick = TradeTick( AUDUSD_SIM.id, Price.from_str("1.00000"), Quantity.from_int(10000), AggressorSide.BUY, TradeMatchId("123456789"), 0, 0, ) # Act result = tick.to_serializable_str() # Assert self.assertEqual("1.00000,10000,BUY,123456789,0,0", result)
def test_limit_order_to_dict(self): # Arrange order = self.order_factory.limit( AUDUSD_SIM.id, OrderSide.BUY, Quantity.from_int(100000), Price.from_str("1.00000"), display_qty=Quantity.from_int(20000), ) # Act result = order.to_dict() # Assert assert result == { "trader_id": "TESTER-000", "strategy_id": "S-001", "instrument_id": "AUD/USD.SIM", "client_order_id": "O-19700101-000000-000-001-1", "venue_order_id": None, "position_id": None, "account_id": None, "execution_id": None, "type": "LIMIT", "side": "BUY", "quantity": "100000", "price": "1.00000", "liquidity_side": "NONE", "expire_time_ns": 0, "time_in_force": "GTC", "filled_qty": "0", "avg_px": None, "slippage": "0", "status": "INITIALIZED", "is_post_only": False, "is_reduce_only": False, "display_qty": "20000", "order_list_id": None, "parent_order_id": None, "child_order_ids": None, "contingency": "NONE", "contingency_ids": None, "tags": None, "ts_last": 0, "ts_init": 0, }
def test_duplicate_trades(betfair_data_client): messages = [] for update in BetfairTestStubs.raw_market_updates(market="1.180305278", runner1="2696769", runner2="4297085"): messages.extend( on_market_update( instrument_provider=betfair_data_client.instrument_provider(), update=update, )) if update["pt"] >= 1615222877785: break trades = [ m for m in messages if isinstance(m, TradeTick) and m.price == Price("0.69930", 5) ] assert len(trades) == 5
def trailing_stop_sell(self, last_bar: Bar): """ Users simple trailing stop SELL for (LONG positions). """ # Round price to nearest 0.5 (for XBT/USD) price = round((last_bar.low - (self.atr.value * self.trail_atr_multiple)) * 2) / 2 order: StopMarketOrder = self.order_factory.stop_market( symbol=self.symbol, order_side=OrderSide.SELL, quantity=Quantity(self.trade_size), price=Price(price, self.instrument.price_precision), reduce_only=True, ) self.trailing_stop = order self.submit_order(order)
def test_modify_order_raises_not_implemented_error(self): # Arrange # Act command = ModifyOrder( self.venue, self.trader_id, self.account_id, ClientOrderId("O-123456789"), Quantity(120000), Price("1.00000"), self.uuid_factory.generate(), self.clock.utc_now(), ) # Assert self.assertRaises(NotImplementedError, self.client.modify_order, command)
def event_order_filled( order, instrument, position_id=None, strategy_id=None, fill_price=None, fill_qty=None, liquidity_side=LiquiditySide.TAKER, ) -> OrderFilled: if position_id is None: position_id = order.position_id if strategy_id is None: strategy_id = order.strategy_id if fill_price is None: fill_price = Price("1.00000") if fill_qty is None: fill_qty = order.quantity commission = instrument.calculate_commission( quantity=order.quantity, avg_price=fill_price, liquidity_side=liquidity_side, ) return OrderFilled( account_id=TestStubs.account_id(), cl_ord_id=order.cl_ord_id, order_id=order.id, execution_id=ExecutionId(order.cl_ord_id.value.replace("O", "E")), position_id=position_id, strategy_id=strategy_id, symbol=order.symbol, order_side=order.side, fill_qty=fill_qty, cum_qty=Quantity(order.filled_qty + fill_qty), leaves_qty=Quantity( max(0, order.quantity - order.filled_qty - fill_qty)), fill_price=order.price if fill_price is None else fill_price, currency=instrument.quote_currency, is_inverse=instrument.is_inverse, commission=commission, liquidity_side=liquidity_side, execution_time=UNIX_EPOCH, event_id=uuid4(), event_timestamp=UNIX_EPOCH, )
def test_from_dict_returns_expected_tick(self): # Arrange tick = TradeTick( AUDUSD_SIM.id, Price.from_str("1.00000"), Quantity.from_int(10000), AggressorSide.BUY, "123456789", 0, 0, ) # Act result = TradeTick.from_dict(TradeTick.to_dict(tick)) # Assert assert tick == result
def test_from_dict_returns_expected_tick(self): # Arrange tick = TradeTick( instrument_id=AUDUSD_SIM.id, price=Price.from_str("1.00000"), size=Quantity.from_int(10000), aggressor_side=AggressorSide.BUY, trade_id=TradeId("123456789"), ts_event=0, ts_init=0, ) # Act result = TradeTick.from_dict(TradeTick.to_dict(tick)) # Assert assert tick == result
def test_handle_trade_tick_sends_to_data_engine(self): # Arrange tick = TradeTick( AUDUSD_SIM.id, Price.from_str("1.00050"), Quantity.from_int(1), AggressorSide.BUY, "123456", 0, 0, ) # Act self.client._handle_data_py(tick) # Assert self.assertEqual(1, self.data_engine.data_count)
def test_pack_and_unpack_limit_orders(self): # Arrange order = self.order_factory.limit( AUDUSD_SIM.id, OrderSide.BUY, Quantity(100000, precision=0), Price(1.00000, precision=5), TimeInForce.DAY, display_qty=Quantity(50000, precision=0), ) # Act packed = OrderInitialized.to_dict(order.last_event) unpacked = self.unpacker.unpack(packed) # Assert assert unpacked == order
def test_submit_order_with_no_market_rejects_order(self): # Arrange order = self.strategy.order_factory.stop_market( USDJPY_SIM.symbol, OrderSide.BUY, Quantity(100000), Price("80.000"), ) # Act self.strategy.submit_order(order) # Assert self.assertEqual(2, self.strategy.object_storer.count) self.assertTrue( isinstance(self.strategy.object_storer.get_store()[1], OrderRejected))
def test_position_to_dict(self): # Arrange order = self.order_factory.market( AUDUSD_SIM.id, OrderSide.BUY, Quantity.from_int(100000), ) fill = TestEventStubs.order_filled( order, instrument=AUDUSD_SIM, position_id=PositionId("P-123456"), strategy_id=StrategyId("S-001"), last_px=Price.from_str("1.00001"), ) position = Position(instrument=AUDUSD_SIM, fill=fill) # Act result = position.to_dict() # Assert assert result == { "position_id": "P-123456", "account_id": "SIM-000", "from_order": "O-19700101-000000-000-001-1", "strategy_id": "S-001", "instrument_id": "AUD/USD.SIM", "entry": "BUY", "side": "LONG", "net_qty": "100000", "quantity": "100000", "peak_qty": "100000", "ts_opened": 0, "ts_closed": 0, "duration_ns": 0, "avg_px_open": "1.00001", "avg_px_close": "None", "quote_currency": "USD", "base_currency": "AUD", "cost_currency": "USD", "realized_points": "0", "realized_return": "0.00000", "realized_pnl": "-2.00 USD", "commissions": "['2.00 USD']", }
def test_hash_str_and_repr(self): # Arrange tick = TradeTick( instrument_id=AUDUSD_SIM.id, price=Price.from_str("1.00000"), size=Quantity.from_int(50000), aggressor_side=AggressorSide.BUY, trade_id="123456789", ts_event=0, ts_init=0, ) # Act, Assert assert isinstance(hash(tick), int) assert str(tick) == "AUD/USD.SIM,1.00000,50000,BUY,123456789,0" assert repr( tick) == "TradeTick(AUD/USD.SIM,1.00000,50000,BUY,123456789,0)"
def test_get_trade_tick(self): tick = TradeTick( AUDUSD_FXCM, Price("1.00000"), Quantity(10000), Maker.BUYER, MatchId("123456789"), datetime(2018, 1, 1, 19, 59, 1, 0, pytz.utc), ) self.data_engine.handle_trade_tick(tick) # Act result = self.strategy.trade_tick(tick.symbol, 0) # Assert self.assertEqual(tick, result)
def create_buy_order(self, last: QuoteTick): """ A market makers simple buy limit method (example). """ price: Decimal = last.bid - (self.atr.value * self.atr_multiple) order: LimitOrder = self.order_factory.limit( instrument_id=self.instrument_id, order_side=OrderSide.BUY, quantity=Quantity(self.trade_size), price=Price(price, self.price_precision), time_in_force=TimeInForce.GTC, post_only=True, # Default value is True hidden=False, # Default value is False ) self.buy_order = order self.submit_order(order)
def test_stop_order_with_gtd_and_expire_time_none_raises_exception(self): # Arrange # Act self.assertRaises( TypeError, StopMarketOrder, ClientOrderId("O-123456"), StrategyId("S", "001"), AUDUSD_SIM.symbol, OrderSide.BUY, Quantity(100000), price=Price("1.00000"), init_id=uuid4(), timestamp=UNIX_EPOCH, time_in_force=TimeInForce.GTD, expire_time=None, )
def make_order(engine: MockLiveExecutionEngine) -> LimitOrder: strategy = TradingStrategy(order_id_tag="001") strategy.register_trader( TraderId("TESTER", "000"), BetfairTestStubs.clock(), BetfairTestStubs.logger(), ) engine.register_strategy(strategy) order = strategy.order_factory.limit( BetfairTestStubs.instrument_id(), OrderSide.BUY, Quantity(10), Price("0.50"), ) return order
def create_sell_order(self, last: QuoteTick): """ A market makers simple sell limit method (example). """ price: Decimal = last.ask + (self.atr.value * self.atr_multiple) order: LimitOrder = self.order_factory.limit( symbol=self.symbol, order_side=OrderSide.SELL, quantity=Quantity(self.trade_size), price=Price(price, self.price_precision), time_in_force=TimeInForce.GTC, post_only=True, # Default value is True hidden=False, # Default value is False ) self.sell_order = order self.submit_order(order)
async def test_post_order_update_success(execution_client, exec_engine): # Add fake order to cache order = BetfairTestStubs.make_order(exec_engine) order.apply(BetfairTestStubs.event_order_submitted(order=order)) order.apply( BetfairTestStubs.event_order_accepted( order=order, venue_order_id=VenueOrderId("229435133092"))) exec_engine.cache.add_order(order, PositionId("1")) client_order_id = exec_engine.cache.orders()[0].client_order_id f = asyncio.Future() f.set_result(BetfairTestStubs.replace_orders_resp_success()) execution_client._post_update_order(f, client_order_id) await asyncio.sleep(0) event = exec_engine.events[0] assert isinstance(event, OrderUpdated) assert event.price == Price("0.47619")
def test_stop_market_order_with_gtd_and_expire_time_none_raises_type_error( self): # Arrange, Act, Assert with pytest.raises(TypeError): StopMarketOrder( self.trader_id, self.strategy_id, AUDUSD_SIM.id, ClientOrderId("O-123456"), OrderSide.BUY, Quantity.from_int(100000), price=Price.from_str("1.00000"), init_id=UUID4(), ts_init=0, time_in_force=TimeInForce.GTD, expire_time=None, )
def test_handle_trade_tick_when_volume_at_threshold_sends_bar_to_handler(self): # Arrange bar_store = ObjectStorer() handler = bar_store.store instrument_id = TestStubs.audusd_id() bar_spec = BarSpecification(10000, BarAggregation.VOLUME, PriceType.LAST) bar_type = BarType(instrument_id, bar_spec) aggregator = VolumeBarAggregator(bar_type, handler, Logger(TestClock())) tick1 = TradeTick( instrument_id=AUDUSD_SIM.id, price=Price("1.00001"), size=Quantity(3000), side=OrderSide.BUY, match_id=TradeMatchId("123456"), timestamp_ns=0, ) tick2 = TradeTick( instrument_id=AUDUSD_SIM.id, price=Price("1.00002"), size=Quantity(4000), side=OrderSide.BUY, match_id=TradeMatchId("123457"), timestamp_ns=0, ) tick3 = TradeTick( instrument_id=AUDUSD_SIM.id, price=Price("1.00000"), size=Quantity(3000), side=OrderSide.BUY, match_id=TradeMatchId("123458"), timestamp_ns=0, ) # Act aggregator.handle_trade_tick(tick1) aggregator.handle_trade_tick(tick2) aggregator.handle_trade_tick(tick3) # Assert self.assertEqual(1, len(bar_store.get_store())) self.assertEqual(Price("1.00001"), bar_store.get_store()[0].open) self.assertEqual(Price("1.00002"), bar_store.get_store()[0].high) self.assertEqual(Price("1.00000"), bar_store.get_store()[0].low) self.assertEqual(Price("1.00000"), bar_store.get_store()[0].close) self.assertEqual(Quantity(10000), bar_store.get_store()[0].volume)
def test_handle_trade_tick_when_count_at_threshold_sends_bar_to_handler(self): # Arrange bar_store = ObjectStorer() handler = bar_store.store symbol = TestStubs.symbol_audusd_fxcm() bar_spec = BarSpecification(3, BarAggregation.TICK, PriceType.LAST) bar_type = BarType(symbol, bar_spec) aggregator = TickBarAggregator(bar_type, handler, TestLogger(TestClock())) tick1 = TradeTick( symbol=AUDUSD_SIM.symbol, price=Price("1.00001"), size=Quantity(1), side=OrderSide.BUY, match_id=TradeMatchId("123456"), timestamp=UNIX_EPOCH, ) tick2 = TradeTick( symbol=AUDUSD_SIM.symbol, price=Price("1.00002"), size=Quantity(1), side=OrderSide.BUY, match_id=TradeMatchId("123457"), timestamp=UNIX_EPOCH, ) tick3 = TradeTick( symbol=AUDUSD_SIM.symbol, price=Price("1.00000"), size=Quantity(1), side=OrderSide.BUY, match_id=TradeMatchId("123458"), timestamp=UNIX_EPOCH, ) # Act aggregator.handle_trade_tick(tick1) aggregator.handle_trade_tick(tick2) aggregator.handle_trade_tick(tick3) # Assert self.assertEqual(1, len(bar_store.get_store())) self.assertEqual(Price("1.00001"), bar_store.get_store()[0].bar.open) self.assertEqual(Price("1.00002"), bar_store.get_store()[0].bar.high) self.assertEqual(Price("1.00000"), bar_store.get_store()[0].bar.low) self.assertEqual(Price("1.00000"), bar_store.get_store()[0].bar.close) self.assertEqual(Quantity(3), bar_store.get_store()[0].bar.volume)
def test_process_trade_tick_when_subscribers_then_sends_to_registered_handlers( self, ): # Arrange self.data_engine.register_client(self.binance_client) self.binance_client.connect() handler1 = [] subscribe1 = Subscribe( client_id=ClientId(BINANCE.value), data_type=DataType(TradeTick, metadata={"instrument_id": ETHUSDT_BINANCE.id}), handler=handler1.append, command_id=self.uuid_factory.generate(), timestamp_ns=self.clock.timestamp_ns(), ) handler2 = [] subscribe2 = Subscribe( client_id=ClientId(BINANCE.value), data_type=DataType(TradeTick, metadata={"instrument_id": ETHUSDT_BINANCE.id}), handler=handler2.append, command_id=self.uuid_factory.generate(), timestamp_ns=self.clock.timestamp_ns(), ) self.data_engine.execute(subscribe1) self.data_engine.execute(subscribe2) tick = TradeTick( ETHUSDT_BINANCE.id, Price.from_str("1050.00000"), Quantity.from_int(100), AggressorSide.BUY, "123456789", 0, 0, ) # Act self.data_engine.process(tick) # Assert self.assertEqual([tick], handler1) self.assertEqual([tick], handler2)
def test_process(self): # Arrange instrument = TestInstrumentProvider.btcusdt_binance() wrangler = TradeTickDataWrangler(instrument=instrument) path = os.path.join(PACKAGE_ROOT, "data", "tardis_trades.csv") data = TardisTradeDataLoader.load(path) # Act ticks = wrangler.process(data) # Assert assert len(ticks) == 9999 assert ticks[0].price == Price.from_str("9682.00") assert ticks[0].size == Quantity.from_str("0.132000") assert ticks[0].aggressor_side == AggressorSide.BUY assert ticks[0].trade_id == TradeId("42377944") assert ticks[0].ts_event == 1582329602418379008 assert ticks[0].ts_init == 1582329602418379008
def test_process(self): # Arrange ethusdt = TestInstrumentProvider.ethusdt_binance() wrangler = TradeTickDataWrangler(instrument=ethusdt) provider = TestDataProvider() # Act ticks = wrangler.process( provider.read_csv_ticks("binance-ethusdt-trades.csv")[:100]) # Assert assert len(ticks) == 100 assert ticks[0].price == Price.from_str("423.760") assert ticks[0].size == Quantity.from_str("2.67900") assert ticks[0].aggressor_side == AggressorSide.SELL assert ticks[0].trade_id == TradeId("148568980") assert ticks[0].ts_event == 1597399200223000064 assert ticks[0].ts_init == 1597399200223000064
def test_initialize_stop_order(self): # Arrange # Act order = self.order_factory.stop_market( AUDUSD_SIM.symbol, OrderSide.BUY, Quantity(100000), Price("1.00000"), ) # Assert self.assertEqual(OrderType.STOP_MARKET, order.type) self.assertEqual(OrderState.INITIALIZED, order.state) self.assertEqual(TimeInForce.GTC, order.time_in_force) self.assertTrue(order.is_passive) self.assertFalse(order.is_aggressive) self.assertFalse(order.is_completed) self.assertEqual(OrderInitialized, type(order.init_event))