def test_serialize_and_deserialize_limit_orders_with_expire_time(self): # Arrange order = LimitOrder( ClientOrderId("O-123456"), StrategyId("S", "001"), AUDUSD_SIM.id, OrderSide.BUY, Quantity(100000), price=Price("1.00000"), time_in_force=TimeInForce.GTD, expire_time=UNIX_EPOCH, init_id=uuid4(), timestamp_ns=0, ) # Act serialized = self.serializer.serialize(order) deserialized = self.serializer.deserialize(serialized) # Assert assert deserialized == order print(b64encode(serialized)) print(order)
def test_handle_trade_tick_when_count_below_threshold_updates(self): # Arrange bar_store = ObjectStorer() handler = bar_store.store instrument_id = TestStubs.audusd_id() bar_spec = BarSpecification(3, BarAggregation.TICK, PriceType.LAST) bar_type = BarType(instrument_id, bar_spec) aggregator = TickBarAggregator(bar_type, handler, Logger(TestClock())) tick1 = TradeTick( instrument_id=AUDUSD_SIM.id, price=Price("1.00001"), size=Quantity(1), aggressor_side=AggressorSide.BUY, match_id=TradeMatchId("123456"), timestamp_ns=0, ) # Act aggregator.handle_trade_tick(tick1) # Assert self.assertEqual(0, len(bar_store.get_store()))
def test_apply_order_denied_event(self): # Arrange order = self.order_factory.market( AUDUSD_SIM.id, OrderSide.BUY, Quantity(100000), ) denied = OrderDenied( order.cl_ord_id, "SOME_REASON", uuid4(), UNIX_EPOCH, ) # Act order.apply(denied) # Assert self.assertEqual(OrderState.DENIED, order.state) self.assertEqual(2, order.event_count) self.assertEqual(denied, order.last_event) self.assertTrue(order.is_completed)
def test_can_update_order_for_working_order(self): # Arrange order = self.strategy.order_factory.market(AUDUSD_FXCM, OrderSide.BUY, Quantity(100000)) position_id = self.strategy.position_id_generator.generate() self.database.add_order(order, self.strategy.id, position_id) order_working = TestStubs.event_order_working(order) order.apply(order_working) # Act self.database.update_order(order) # Assert self.assertTrue(self.database.order_exists(order.id)) self.assertTrue(order.id in self.database.get_order_ids()) self.assertTrue(order.id in self.database.get_orders()) self.assertTrue( order.id in self.database.get_orders_working(self.strategy.id)) self.assertTrue(order.id in self.database.get_orders_working()) self.assertTrue(order.id not in self.database.get_orders_completed( self.strategy.id)) self.assertTrue(order.id not in self.database.get_orders_completed())
def test_can_submit_order(self): # Arrange strategy = TradingStrategy(order_id_tag='001') strategy.change_clock(self.clock) self.exec_engine.register_strategy(strategy) position_id = strategy.position_id_generator.generate() order = strategy.order_factory.market(AUDUSD_FXCM, OrderSide.BUY, Quantity(100000)) submit_order = SubmitOrder(self.trader_id, self.account_id, strategy.id, position_id, order, self.guid_factory.generate(), self.clock.time_now()) # Act self.exec_engine.execute_command(submit_order) # Assert self.assertIn(submit_order, self.exec_client.received_commands) self.assertTrue(self.exec_db.order_exists(order.id)) self.assertEqual(position_id, self.exec_db.get_position_id(order.id))
def test_serialize_and_deserialize_stop_orders_with_expire_time(self): # Arrange order = StopMarketOrder( ClientOrderId("O-123456"), StrategyId("S", "001"), AUDUSD_SIM.symbol, OrderSide.BUY, Quantity(100000), price=Price("1.00000"), time_in_force=TimeInForce.GTD, expire_time=UNIX_EPOCH, init_id=uuid4(), timestamp=UNIX_EPOCH, ) # Act serialized = self.serializer.serialize(order) deserialized = self.serializer.deserialize(serialized) # Assert self.assertEqual(order, deserialized) print(b64encode(serialized)) print(order)
def test_update_order_for_working_order(self): # Arrange order = self.strategy.order_factory.stop_market( AUDUSD_SIM.symbol, OrderSide.BUY, Quantity(100000), Price("1.00000"), ) self.database.add_order(order) order.apply(TestStubs.event_order_submitted(order)) self.database.update_order(order) order.apply(TestStubs.event_order_accepted(order)) self.database.update_order(order) # Act order.apply(TestStubs.event_order_working(order)) self.database.update_order(order) # Assert self.assertEqual(order, self.database.load_order(order.cl_ord_id))
def test_can_modify_atomic_order_working_stop_loss(self): # Arrange strategy = TestStrategy1(bar_type=TestStubs.bartype_usdjpy_1min_bid()) self.data_client.register_strategy(strategy) self.exec_engine.register_strategy(strategy) strategy.start() self.exec_client.process_tick(TestStubs.tick_3decimal(self.usdjpy.symbol)) # Prepare market atomic_order = strategy.order_factory.atomic_market( USDJPY_FXCM, OrderSide.BUY, Quantity(100000), Price(85.000, 3)) strategy.submit_atomic_order(atomic_order, strategy.position_id_generator.generate()) # Act strategy.modify_order(atomic_order.stop_loss, atomic_order.entry.quantity, Price(85.100, 3)) # Assert self.assertEqual(Price(85.100, 3), strategy.order(atomic_order.stop_loss.id).price) self.assertEqual(8, strategy.object_storer.count) self.assertTrue(isinstance(strategy.object_storer.get_store()[7], OrderModified))
def parse_bars_http( instrument: Instrument, bar_type: BarType, data: List[Dict[str, Any]], ts_event_delta: int, ts_init: int, ) -> List[Bar]: bars: List[Bar] = [] for row in data: bar: Bar = Bar( bar_type=bar_type, open=Price(row["open"], instrument.price_precision), high=Price(row["high"], instrument.price_precision), low=Price(row["low"], instrument.price_precision), close=Price(row["close"], instrument.price_precision), volume=Quantity(row["volume"], instrument.size_precision), check=True, ts_event=secs_to_nanos(row["time"]) + ts_event_delta, ts_init=ts_init, ) bars.append(bar) return bars
def trailing_stop_buy(self, last_bar: Bar): """ Users simple trailing stop BUY for (SHORT positions). Parameters ---------- last_bar : Bar The last bar received. """ # Round price to nearest 0.5 (for XBT/USD) price = (round((last_bar.high + (self.atr.value * self.trail_atr_multiple)) * 2) / 2) order: StopMarketOrder = self.order_factory.stop_market( instrument_id=self.instrument_id, order_side=OrderSide.BUY, 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_handle_trade_tick_when_volume_below_threshold_updates(self): # Arrange bar_store = ObjectStorer() handler = bar_store.store symbol = TestStubs.symbol_audusd_fxcm() bar_spec = BarSpecification(10000, BarAggregation.VOLUME, PriceType.LAST) bar_type = BarType(symbol, bar_spec) aggregator = VolumeBarAggregator(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, ) # Act aggregator.handle_trade_tick(tick1) # Assert self.assertEqual(0, len(bar_store.get_store()))
def test_limit_buy_post_only_reduce_only_order(self): # Arrange order = self.order_factory.limit( symbol=BTCUSDT, order_side=OrderSide.BUY, quantity=Quantity("1.0"), price=Price("50000"), post_only=True, reduce_only=True, ) # Act result = self.builder.build_py(order) # Assert expected_args = ['BTC/USDT', 'Limit', 'Buy', '1.0', '50000'] expected_custom_params = { 'clOrdID': 'O-19700101-000000-000-001-1', 'execInst': 'ParticipateDoNotInitiate,ReduceOnly', 'timeInForce': 'GoodTillCancel' } self.assertTrue(order.is_post_only) self.assertEqual((expected_args, expected_custom_params), result)
def test_order_serializer_methods_raise_not_implemented_error(self): # Arrange order_factory = OrderFactory( trader_id=TraderId("TESTER", "000"), strategy_id=StrategyId("S", "001"), clock=TestClock(), ) order = order_factory.market( AUDUSD_SIM.id, OrderSide.BUY, Quantity(100000), ) serializer = OrderSerializer() # Act # Assert with pytest.raises(NotImplementedError): serializer.serialize(order) with pytest.raises(NotImplementedError): serializer.deserialize(bytes())
def test_submit_bracket_market_order(self): # Arrange # Prepare market tick = TestStubs.quote_tick_3decimal(USDJPY_SIM.symbol) self.data_engine.process(tick) self.exchange.process_tick(tick) entry_order = self.strategy.order_factory.market( USDJPY_SIM.symbol, OrderSide.BUY, Quantity(100000), ) bracket_order = self.strategy.order_factory.bracket( entry_order, Price("80.000"), ) # Act self.strategy.submit_bracket_order(bracket_order) # Assert self.assertEqual(OrderState.FILLED, entry_order.state)
def test_apply_order_invalid_event(self): # Arrange order = self.order_factory.market( AUDUSD_SIM.symbol, OrderSide.BUY, Quantity(100000), ) invalid = OrderInvalid( order.cl_ord_id, "SOME_REASON", uuid4(), UNIX_EPOCH, ) # Act order.apply(invalid) # Assert self.assertEqual(OrderState.INVALID, order.state) self.assertEqual(2, order.event_count) self.assertEqual(invalid, order.last_event) self.assertTrue(order.is_completed)
def test_serialize_and_deserialize_amend_order_commands(self): # Arrange command = ModifyOrder( self.trader_id, StrategyId("SCALPER-001"), AUDUSD_SIM.id, ClientOrderId("O-123456"), VenueOrderId("001"), Quantity(100000, precision=0), Price(1.00001, precision=5), None, UUID4(), 0, ) # Act serialized = self.serializer.serialize(command) deserialized = self.serializer.deserialize(serialized) # Assert assert deserialized == command print(b64encode(serialized)) print(command)
def test_pack_and_unpack_stop_limit_orders_with_expire_time(self): # Arrange order = StopLimitOrder( self.trader_id, self.strategy_id, AUDUSD_SIM.id, ClientOrderId("O-123456"), OrderSide.BUY, Quantity(100000, precision=0), price=Price(1.00000, precision=5), trigger=Price(1.00010, precision=5), time_in_force=TimeInForce.GTD, expire_time=UNIX_EPOCH, init_id=UUID4(), ts_init=0, ) # Act packed = OrderInitialized.to_dict(order.last_event) unpacked = self.unpacker.unpack(packed) # Assert assert unpacked == order
def test_order_initialized(self): # Arrange uuid = uuid4() event = OrderInitialized(cl_ord_id=ClientOrderId("O-2020872378423"), strategy_id=StrategyId("SCALPER", "001"), symbol=Symbol("BTC/USDT", Exchange("BINANCE")), order_side=OrderSide.BUY, order_type=OrderType.LIMIT, quantity=Quantity("0.561000"), time_in_force=TimeInForce.DAY, event_id=uuid, event_timestamp=UNIX_EPOCH, options={"Price": "15200.10"}) # Act # Assert self.assertEqual( f"OrderInitialized(cl_ord_id=O-2020872378423, id={uuid})", str(event)) self.assertEqual( f"OrderInitialized(cl_ord_id=O-2020872378423, id={uuid})", repr(event))
def test_order_amended(self): # Arrange uuid = uuid4() event = OrderAmended( account_id=AccountId("SIM", "000"), cl_ord_id=ClientOrderId("O-2020872378423"), order_id=OrderId("123456"), quantity=Quantity(500000), price=Price('1.95000'), amended_time=UNIX_EPOCH, event_id=uuid, event_timestamp=UNIX_EPOCH, ) # Act self.assertEqual( f"OrderAmended(account_id=SIM-000, cl_order_id=O-2020872378423, " f"order_id=123456, qty=500,000, price=1.95000, id={uuid})", str(event)) self.assertEqual( f"OrderAmended(account_id=SIM-000, cl_order_id=O-2020872378423, " f"order_id=123456, qty=500,000, price=1.95000, id={uuid})", repr(event))
def test_cancel_order_when_not_connected_logs_and_does_not_send(self): # Arrange order = self.order_factory.market( ETHUSDT_BINANCE.symbol, OrderSide.BUY, Quantity(100), ) command = CancelOrder( BINANCE, self.trader_id, self.account_id, order.cl_ord_id, order.id, self.uuid_factory.generate(), self.clock.utc_now(), ) # Act self.exec_client.cancel_order(command) # Assert self.assertTrue(True) # No exceptions raised
def test_serialize_and_deserialize_stop_limit_order_initialized_events(self): # Arrange options = { "expire_time_ns": None, "price": "1.0005", "trigger_price": "1.0010", } event = OrderInitialized( self.trader_id, self.strategy_id, AUDUSD_SIM.id, ClientOrderId("O-123456"), OrderSide.SELL, OrderType.STOP_LIMIT, Quantity(100000, precision=0), TimeInForce.DAY, post_only=True, reduce_only=True, options=options, order_list_id=OrderListId("1"), contingency_type=ContingencyType.OTO, linked_order_ids=[ClientOrderId("O-123457"), ClientOrderId("O-123458")], parent_order_id=ClientOrderId("O-123455"), tags="entry,bulk", event_id=UUID4(), ts_init=0, ) # Act serialized = self.serializer.serialize(event) deserialized = self.serializer.deserialize(serialized) # Assert assert deserialized == event assert deserialized.options == options assert deserialized.tags == "entry,bulk"
def test_process_bar_when_subscriber_then_sends_to_registered_handler( self): # Arrange self.data_engine.register_client(self.binance_client) self.binance_client.connect() bar_spec = BarSpecification(1000, BarAggregation.TICK, PriceType.MID) bar_type = BarType(ETHUSDT_BINANCE.id, bar_spec, internal_aggregation=True) handler = ObjectStorer() subscribe = Subscribe( client_id=ClientId(BINANCE.value), data_type=DataType(Bar, metadata={"BarType": bar_type}), handler=handler.store, command_id=self.uuid_factory.generate(), timestamp_ns=self.clock.timestamp_ns(), ) self.data_engine.execute(subscribe) bar = Bar( bar_type, Price("1051.00000"), Price("1055.00000"), Price("1050.00000"), Price("1052.00000"), Quantity(100), 0, ) # Act self.data_engine.process(bar) # Assert self.assertEqual([bar], handler.get_store())
def test_order_initialized(self): # Arrange uuid = uuid4() event = OrderInitialized( client_order_id=ClientOrderId("O-2020872378423"), strategy_id=StrategyId("SCALPER", "001"), instrument_id=InstrumentId(Symbol("BTC/USDT"), Venue("BINANCE")), order_side=OrderSide.BUY, order_type=OrderType.LIMIT, quantity=Quantity("0.561000"), time_in_force=TimeInForce.DAY, event_id=uuid, timestamp_ns=0, options={"Price": "15200.10"}, ) # Act # Assert assert ( f"OrderInitialized(client_order_id=O-2020872378423, strategy_id=SCALPER-001, event_id={uuid})" == str(event)) assert ( f"OrderInitialized(client_order_id=O-2020872378423, strategy_id=SCALPER-001, event_id={uuid})" == repr(event))
def test_submit_order(self): # Arrange self.exec_engine.start() strategy = TradingStrategy(order_id_tag="001") strategy.register_trader( TraderId("TESTER", "000"), self.clock, self.logger, ) self.exec_engine.register_strategy(strategy) order = strategy.order_factory.market( AUDUSD_SIM.symbol, OrderSide.BUY, Quantity(100000), ) submit_order = SubmitOrder( self.venue, self.trader_id, self.account_id, strategy.id, PositionId.null(), order, self.uuid_factory.generate(), self.clock.utc_now(), ) # Act self.exec_engine.execute(submit_order) # Assert self.assertIn(submit_order, self.exec_client.commands) self.assertTrue(self.cache.order_exists(order.cl_ord_id))
def test_serialize_and_deserialize_order_working_events(self): # Arrange event = OrderWorking( self.account_id, ClientOrderId("O-123456"), OrderId("B-123456"), AUDUSD_SIM.symbol, OrderSide.SELL, OrderType.STOP_MARKET, Quantity(100000), Price("1.50000"), TimeInForce.DAY, None, UNIX_EPOCH, uuid4(), UNIX_EPOCH, ) # Act serialized = self.serializer.serialize(event) deserialized = self.serializer.deserialize(serialized) # Assert self.assertEqual(deserialized, event)
def test_serialize_and_deserialize_order_initialized_events(self): # Arrange options = {'Price': '1.0005'} event = OrderInitialized( ClientOrderId("O-123456"), StrategyId("S", "001"), AUDUSD_SIM.symbol, OrderSide.SELL, OrderType.STOP_MARKET, Quantity(100000), TimeInForce.DAY, uuid4(), UNIX_EPOCH, options=options, ) # Act serialized = self.serializer.serialize(event) deserialized = self.serializer.deserialize(serialized) # Assert self.assertEqual(deserialized, event) self.assertEqual(options, event.options)
def test_handle_trade_tick_when_value_below_threshold_updates(self): # Arrange bar_store = ObjectStorer() handler = bar_store.store instrument_id = TestStubs.audusd_id() bar_spec = BarSpecification(100000, BarAggregation.VALUE, PriceType.LAST) bar_type = BarType(instrument_id, bar_spec) aggregator = ValueBarAggregator(bar_type, handler, Logger(TestClock())) tick1 = TradeTick( instrument_id=AUDUSD_SIM.id, price=Price("15000.00"), size=Quantity("3.5"), side=OrderSide.BUY, match_id=TradeMatchId("123456"), timestamp_ns=0, ) # Act aggregator.handle_trade_tick(tick1) # Assert self.assertEqual(0, len(bar_store.get_store())) self.assertEqual(Decimal("52500.000"), aggregator.get_cumulative_value())
def test_flatten_position(self): # Arrange strategy = TradingStrategy(order_id_tag="001") strategy.register_trader( TraderId("TESTER", "000"), clock=self.clock, uuid_factory=self.uuid_factory, logger=self.logger, ) self.exec_engine.register_strategy(strategy) order = strategy.order_factory.market( USDJPY_FXCM, OrderSide.BUY, Quantity(100000), ) strategy.submit_order(order) filled = TestStubs.event_order_filled( order, position_id=PositionId("B-USD/JPY-1"), strategy_id=strategy.id, ) position = Position(filled) # Act strategy.flatten_position(position) # Assert self.assertTrue(order in strategy.execution.orders()) self.assertEqual(OrderState.FILLED, strategy.execution.orders()[0].state()) self.assertEqual(PositionSide.FLAT, strategy.execution.positions()[0].side) self.assertTrue(strategy.execution.positions()[0].is_closed()) self.assertTrue(PositionId("B-USD/JPY-1") in strategy.execution.position_closed_ids()) self.assertTrue(strategy.execution.is_completely_flat())
def _handle_market_trades( runner, instrument, timestamp_origin_ns, timestamp_ns, ): trade_ticks = [] for price, volume in runner.get("trd", []): if volume == 0: continue # Betfair doesn't publish trade ids, so we make our own # TODO - should we use clk here for ID instead of the hash? trade_id = hash_json(data=(timestamp_ns, price, volume)) tick = TradeTick( instrument_id=instrument.id, price=price_to_probability(price, force=True), # Already wrapping in Price size=Quantity(volume, precision=4), aggressor_side=AggressorSide.UNKNOWN, match_id=TradeMatchId(trade_id), timestamp_origin_ns=timestamp_origin_ns, timestamp_ns=timestamp_ns, ) trade_ticks.append(tick) return trade_ticks
def submit_order_command(): return SubmitOrder( client_id=BetfairTestStubs.instrument_id().venue.client_id, trader_id=BetfairTestStubs.trader_id(), account_id=BetfairTestStubs.account_id(), strategy_id=BetfairTestStubs.strategy_id(), position_id=BetfairTestStubs.position_id(), order=LimitOrder( client_order_id=ClientOrderId( f"O-20210410-022422-001-001-{BetfairTestStubs.strategy_id().value}" ), strategy_id=BetfairTestStubs.strategy_id(), instrument_id=BetfairTestStubs.instrument_id(), order_side=OrderSide.BUY, quantity=Quantity(10), price=Price(0.33, 5), time_in_force=TimeInForce.GTC, expire_time=None, init_id=BetfairTestStubs.uuid(), timestamp_ns=BetfairTestStubs.clock().timestamp_ns(), ), command_id=BetfairTestStubs.uuid(), timestamp_ns=BetfairTestStubs.clock().timestamp_ns(), )