def test_is_limit_order(): # a market order is a FAR, but not a FAK or a FOK new_order = NewOrderCommand(12, 324893458.324313, "342adf24441", "user_x", MARKET, BID_SIDE, FAK, Price("23.01"), 234, 2, limit_or_market=MARKET_ORDER) assert new_order.is_limit_order() is False new_order = NewOrderCommand(12, 324893458.324313, "342adf24441", "user_x", MARKET, BID_SIDE, FOK, Price("23.01"), 234, 2, limit_or_market=LIMIT_ORDER) assert new_order.is_limit_order() is True new_order = NewOrderCommand(12, 324893458.324313, "342adf24441", "user_x", MARKET, BID_SIDE, FAR, Price("23.01"), 234, 2) assert new_order.is_limit_order() is True
def test_basic_partial_fill_replenish_visible(): n = NewOrderCommand(121234, 1234235.123, 2342, "user_x", MARKET, BID_SIDE, FAR, Price("34.52"), 100, 40) oec = OrderEventChain(n, LOGGER, MonotonicIntID()) # now ack it ack = AcknowledgementReport(121235, 1234235.123, 2342, "user_x", MARKET, n, Price("34.52"), 100, 40) oec.apply_acknowledgement_report(ack) aggressor = NewOrderCommand(1111, 1234237.123, 22222, "user_y", MARKET, ASK_SIDE, FAR, Price("34.52"), 40) # now resting partial fill pf = PartialFillReport(121236, 1234237.123, 2342, "user_x", MARKET, aggressor, 40, Price("34.52"), BID_SIDE, 99999, 100-40) oec.apply_partial_fill_report(pf) assert oec.open_exposure_requests() == [] assert oec.current_exposure().price() == Price("34.52") assert oec.current_exposure().qty() == 100-40 assert oec.visible_qty() == 40 # should have replenished assert oec.iceberg_peak_qty() == 40 # should not have changed assert oec.has_partial_fill() # now test the partial fill wipes out 40 more, so visible is min aggressor2 = NewOrderCommand(1114, 1234237.123, 33333, "user_y", MARKET, ASK_SIDE, FAR, Price("34.52"), 40) # now resting partial fill pf2 = PartialFillReport(121236, 1234237.123, 2342, "user_x", MARKET, aggressor2, 40, Price("34.52"), BID_SIDE, 99999, 100-40-40) # subtract out the size of 2 40 lot fills now oec.apply_partial_fill_report(pf2) assert oec.open_exposure_requests() == [] assert oec.current_exposure().price() == Price("34.52") assert oec.current_exposure().qty() == 100-40-40 assert oec.visible_qty() == 100-40-40 # should have replenished to min of 40 and 100-40-40 assert oec.iceberg_peak_qty() == 40 # should not have changed assert oec.has_partial_fill()
def test_price_decimal_addition(): p = Price("100.01") mpi = Decimal("0.01") n = p + mpi assert isinstance(p + mpi, Price) assert n != p assert n == Price("100.02")
def test_better_than(): pl1 = PriceLevel(Price("1.4"), 2, 3, 2) pl2 = PriceLevel(Price("1.1"), 2, 3, 2) assert pl1.better_than(pl2, BID_SIDE) assert pl2.better_than(pl1, BID_SIDE) is False assert pl1.better_than(pl2, ASK_SIDE) is False assert pl2.better_than(pl1, ASK_SIDE)
def test_close_exposure_cancel_closes_all(): id_gen = MonotonicIntID(seed=23043, increment=1) n = NewOrderCommand(id_gen.id(), 1234235.123, 2342, "user_x", MARKET, BID_SIDE, FAR, Price("34.52"), 1000) oec = OrderEventChain(n, LOGGER, MonotonicIntID()) # should have 1 open exposure assert len(oec.open_exposure_requests()) == 1 assert oec.most_recent_requested_exposure() == Exposure(Price("34.52"), 1000, id_gen.last_id()) cr = CancelReplaceCommand(id_gen.id(), 1234235.863, 2342, "user_x", MARKET, BID_SIDE, Price("34.51"), 800) oec.apply_cancel_replace_command(cr) # now should have 2 open exposures assert len(oec.open_exposure_requests()) == 2 assert oec.open_exposure_requests()[1] == Exposure(Price("34.51"), 800, id_gen.last_id()) assert oec.most_recent_requested_exposure() == Exposure(Price("34.51"), 800, id_gen.last_id()) cancel_command = CancelCommand(id_gen.id(), 1234274.663, 2342, "user_x", MARKET, CancelReasons.USER_CANCEL) oec.apply_cancel_command(cancel_command) # now should have 3 open exposures assert len(oec.open_exposure_requests()) == 3 assert oec.open_exposure_requests()[2] == Exposure(None, 0, id_gen.last_id()) assert oec.most_recent_requested_exposure() == Exposure(None, 0, id_gen.last_id()) cancel_confirm = CancelReport(id_gen.id(), 1234278.663, 2342, "user_x", MARKET, cancel_command, CancelReasons.USER_CANCEL) oec.apply_cancel_report(cancel_confirm) # all exposures should be closed now assert len(oec.open_exposure_requests()) == 0 assert oec.most_recent_requested_exposure() is None assert oec.has_partial_fill() is False
def test_price_int_addition(): p = Price("100.01") mpi = 1 new_price = p + mpi assert isinstance(new_price, Price) assert new_price != p assert new_price == Price("101.01")
def test_worse_than(): pl1 = PriceLevel(Price("1.6"), 2, 3, 2) pl2 = PriceLevel(Price("2.1"), 2, 3, 2) assert pl1.worse_than(pl2, BID_SIDE) assert pl2.worse_than(pl1, BID_SIDE) is False assert pl1.worse_than(pl2, ASK_SIDE) is False assert pl2.worse_than(pl1, ASK_SIDE)
def test_partial_aggressive_fill(): # nothing should change as we only update orderbook for passive partial fills ob = build_base_order_book() # get baseline ask_prices = ob.ask_prices() bid_prices = ob.bid_prices() best_ask_price = ob.best_ask_price() best_bid_price = ob.best_bid_price() bast_ask_level = ob.best_ask_level() bast_bid_level = ob.best_bid_level() agg_new = NewOrderCommand(101, 1234002.123, 1008, "user_z", MARKET, BID_SIDE, FAR, Price("34.52"), 45) oec = OrderEventChain(agg_new, LOGGER, SUBCHAIN_ID_GENERATOR) pf = PartialFillReport(102, 1234002.123, 1008, "user_z", MARKET, agg_new, 35, Price('34.52'), BID_SIDE, 3333, 10) oec.apply_partial_fill_report(pf) ob.handle_partial_fill_report(pf, oec) # nothing at the order book should have changed assert ask_prices == ob.ask_prices() assert bid_prices == ob.bid_prices() assert best_ask_price == ob.best_ask_price() assert best_bid_price == ob.best_bid_price() assert bast_ask_level == ob.best_ask_level() assert bast_bid_level == ob.best_bid_level()
def test_quote_creation(): q = Quote(MARKET, BID_SIDE, Price("95.42"), 94) assert q.price() == Price("95.42") assert q.visible_qty() == 94 assert q.hidden_qty() == 0 assert q._price_level.number_of_orders() == 1 assert q.market().product().name() == "Microsoft" assert q.market().product().symbol() == "MSFT"
def test_worse_or_same_as(): pl1 = PriceLevel(Price("1.6"), 2, 3, 2) pl2 = PriceLevel(Price("2.1"), 2, 3, 2) pl3 = PriceLevel(Price("1.6"), 24, 4, 22) assert pl1.worse_or_same_as(pl2, BID_SIDE) assert pl2.worse_or_same_as(pl1, BID_SIDE) is False assert pl1.worse_or_same_as(pl2, ASK_SIDE) is False assert pl2.worse_or_same_as(pl1, ASK_SIDE) assert pl1.worse_or_same_as(pl3, BID_SIDE) assert pl1.worse_or_same_as(pl3, ASK_SIDE)
def test_better_or_same_as(): pl1 = PriceLevel(Price("1.4"), 2, 3, 2) pl2 = PriceLevel(Price("1.1"), 2, 3, 2) pl3 = PriceLevel(Price("1.4"), 24, 4, 22) assert pl1.better_or_same_as(pl2, BID_SIDE) assert pl2.better_or_same_as(pl1, BID_SIDE) is False assert pl1.better_or_same_as(pl2, ASK_SIDE) is False assert pl2.better_or_same_as(pl1, ASK_SIDE) assert pl1.better_or_same_as(pl3, BID_SIDE) assert pl1.better_or_same_as(pl3, ASK_SIDE)
def test_equality(): q1 = Quote(MARKET, BID_SIDE, Price("95.42"), 94) q2 = Quote(MARKET, BID_SIDE, Price("95.42"), 94) assert q1 == q2 q2 = Quote( Market(Product("APPL", "Apple"), Endpoint("Nasdaq", "NSDQ"), PriceFactory("0.01")), BID_SIDE, Price("95.42"), 94) assert q1 != q2 q2 = Quote(MARKET, BID_SIDE, Price("95.43"), 94) assert q1 != q2 q2 = Quote(MARKET, BID_SIDE, Price("95.42"), 91) assert q1 != q2 q2 = Quote(MARKET, BID_SIDE, Price("95.42"), 94, 2) assert q1 != q2 q2 = Quote(MARKET, BID_SIDE, Price("95.42"), 94, 0) assert q1 == q2 q1 = Quote(MARKET, BID_SIDE, Price("95.42"), 94, 3) q2 = Quote(MARKET, BID_SIDE, Price("95.42"), 94, 3) assert q1 == q2
def test_get_price(): pf = PriceFactory("0.01") p = pf.get_price(100) assert p == Price(100) assert p == Decimal("100.00") p = pf.get_price("100.01") assert p == Price("100.01") assert p == Decimal("100.01") p = pf.get_price(Decimal("222.22")) assert p == Price("222.22") assert p == Decimal("222.22")
def test_better_or_same_as(): p = Price("91.543") p_less = Price("84.456") p_more = Price("92.123") p_same = Price("91.543") assert p_more.better_than(p, BID_SIDE) is True assert p_more.better_than(p, ASK_SIDE) is False assert p_less.better_or_same_as(p, BID_SIDE) is False assert p_less.better_or_same_as(p, ASK_SIDE) is True assert p.better_or_same_as(p_same, BID_SIDE) is True assert p.better_or_same_as(p_same, ASK_SIDE) is True
def test_subchain_to_json(): # pretty basic, just testing that it doesn't break n = NewOrderCommand(121234, 1234235.123, 2342, "user_x", MARKET, BID_SIDE, FAR, Price("34.52"), 1000) oec = OrderEventChain(n, LOGGER, MonotonicIntID()) # now ack it ack = AcknowledgementReport(121235, 1234235.123, 2342, "user_x", MARKET, n, Price("34.52"), 1000, None) oec.apply_acknowledgement_report(ack) assert oec.most_recent_event() == ack # now check I can get a to_json of the subchain no problem oec.most_recent_subchain().to_json()
def test_worse_or_same_as(): p = Price("91.543") p_less = Price("84.456") p_more = Price("92.123") p_same = Price("91.543") assert p_less.worse_or_same_as(p, BID_SIDE) is True assert p_less.worse_or_same_as(p, ASK_SIDE) is False assert p_more.worse_or_same_as(p, BID_SIDE) is False assert p_more.worse_or_same_as(p, ASK_SIDE) is True assert p.worse_or_same_as(p_same, BID_SIDE) is True assert p.worse_or_same_as(p_same, ASK_SIDE) is True
def test_creation(): new_order = NewOrderCommand(12, 324893458.324313, "342adf24441", "user_x", MARKET, BID_SIDE, FAK, Price("23.01"), 234, 2) assert new_order.event_type_str() == "New Order Command" assert new_order.price() == Price("23.01") assert new_order.market() == MARKET assert new_order.user_id() == "user_x" assert new_order.timestamp() == 324893458.324313 assert new_order.event_id() == 12 assert new_order.side() == BID_SIDE assert new_order.qty() == 234 assert new_order.iceberg_peak_qty() == 2
def test_pricelevel_creation(): pl = PriceLevel(Price("84.5"), 12) assert pl.price() == Price("84.5") assert pl.number_of_orders() is None assert pl.visible_qty() == 12 assert pl.hidden_qty() == 0 pl = PriceLevel(Price("32.134"), 14, 23) assert pl.price() == Price("32.134") assert pl.number_of_orders() is None assert pl.visible_qty() == 14 assert pl.hidden_qty() == 23
def test_next_price(): pf = PriceFactory(".5") starting_price = pf.get_price(100) new_price = pf.next_price(starting_price, BID_SIDE) assert new_price == Price("100.5") new_price = pf.next_price(new_price, BID_SIDE) assert new_price == Price(101) new_price = pf.next_price(new_price, ASK_SIDE) assert new_price == Price("100.5") new_price = pf.next_price(new_price, ASK_SIDE) assert new_price == Price(100)
def test_creation(): n = NewOrderCommand(121234, 1234235.123, 2342, "user_x", MARKET, BID_SIDE, FAR, Price("34.52"), 1000) oec = OrderEventChain(n, LOGGER, MonotonicIntID()) assert oec.side().is_bid() assert oec.market() == MARKET assert oec.time_in_force() == FAR # no ack yet assert oec.current_exposure() is None assert len(oec.open_exposure_requests()) == 1 assert oec.most_recent_requested_exposure() == Exposure(Price("34.52"), 1000, 121234) # visible qty should be nothing still assert oec.visible_qty() == 0
def test_prev_price(): pf = PriceFactory(".5") starting_price = pf.get_price(100) new_price = pf.prev_price(starting_price, BID_SIDE) assert new_price == Price("99.5") new_price = pf.prev_price(new_price, BID_SIDE) assert new_price == Price(99) new_price = pf.prev_price(new_price, ASK_SIDE) assert new_price == Price("99.5") new_price = pf.prev_price(new_price, ASK_SIDE) assert new_price == Price(100)
def test_cancel_replace_not_allowed_on_fak_or_fok(): # FAK n = NewOrderCommand(121234, 1234235.123, 2342, "user_x", MARKET, BID_SIDE, FAK, Price("34.52"), 1000) oec = OrderEventChain(n, LOGGER, MonotonicIntID()) cr = CancelReplaceCommand(121235, 1234235.324, 2342, "user_x", MARKET, BID_SIDE, Price("43.01"), 234) with pytest.raises(AssertionError): oec.apply_cancel_replace_command(cr) # FOK n = NewOrderCommand(121234, 1234235.123, 2342, "user_x", MARKET, BID_SIDE, FOK, Price("34.52"), 1000) oec = OrderEventChain(n, LOGGER, MonotonicIntID()) cr = CancelReplaceCommand(121235, 1234235.324, 2342, "user_x", MARKET, BID_SIDE, Price("43.01"), 234) with pytest.raises(AssertionError): oec.apply_cancel_replace_command(cr)
def test_partial_fill_on_unacked_order(): # when an unacked order is filled the requested exposure gets impacted n = NewOrderCommand(121234, 1234235.123, 2342, "user_x", MARKET, BID_SIDE, FAR, Price("34.52"), 100) oec = OrderEventChain(n, LOGGER, MonotonicIntID()) assert oec.current_exposure() is None assert oec.most_recent_requested_exposure().qty() == 100 assert oec.most_recent_requested_exposure().price() == Price("34.52") # now resting partial fill pf = PartialFillReport(1212344, 1234237.123, 2342, "user_x", MARKET, n, 10, Price("34.52"), BID_SIDE, 99999, 90) oec.apply_partial_fill_report(pf) assert oec.current_exposure() is None assert oec.most_recent_requested_exposure().qty() == 90 assert oec.most_recent_requested_exposure().price() == Price("34.52")
def test_full_fill_with_too_much_size_on_unacked_new_order(): # should balk but shouldn't keep it from working n = NewOrderCommand(1, 1234235.123, 2342, "user_x", MARKET, BID_SIDE, FAR, Price("34.52"), 1000) oec = OrderEventChain(n, LOGGER, MonotonicIntID()) assert oec.visible_qty() == 0 assert oec.current_exposure() is None assert oec.most_recent_requested_exposure().price() == Price("34.52") assert oec.most_recent_requested_exposure().qty() == 1000 assert oec.is_open() full_fill = FullFillReport(3, 1234237.123, 2342, "user_x", MARKET, n, 17, Price('34.52'), BID_SIDE, 12345) oec.apply_full_fill_report(full_fill) assert oec.visible_qty() == 0 assert oec.current_exposure().price() is None assert oec.current_exposure().qty() == 0 assert oec.current_exposure().causing_event_id() == 3 assert oec.is_open() is False
def test_basic_full_fill_on_unacked_order(): n = NewOrderCommand(1, 1234235.123, 2342, "user_x", MARKET, BID_SIDE, FAR, Price("34.52"), 1000) oec = OrderEventChain(n, LOGGER, MonotonicIntID()) assert oec.visible_qty() == 0 assert oec.current_exposure() is None assert oec.most_recent_requested_exposure().price() == Price("34.52") assert oec.most_recent_requested_exposure().qty() == 1000 assert oec.is_open() full_fill = FullFillReport(3, 1234237.123, 2342, "user_x", MARKET, n, 1000, Price('34.52'), BID_SIDE, 12345) oec.apply_full_fill_report(full_fill) assert oec.visible_qty() == 0 assert oec.current_exposure().price() is None assert oec.current_exposure().qty() == 0 assert oec.current_exposure().causing_event_id() == 3 assert len(oec.open_exposure_requests()) == 0 assert oec.is_open() is False
def test_partial_fill_to_zero_closes_out_order(): # when a partialfill closses out to an order there should be a balking because it is a paritial fill so shouldn't happen, but should allow n = NewOrderCommand(121234, 1234235.123, 2342, "user_x", MARKET, BID_SIDE, FAR, Price("34.52"), 100) oec = OrderEventChain(n, LOGGER, MonotonicIntID()) # now ack it ack = AcknowledgementReport(121235, 1234235.123, 2342, "user_x", MARKET, n, Price("34.52"), 100, 100) oec.apply_acknowledgement_report(ack) aggressor = NewOrderCommand(1111, 1234237.123, 22222, "user_y", MARKET, ASK_SIDE, FAR, Price("34.52"), 100) # now resting partial fill pf = PartialFillReport(1212344, 1234237.123, 2342, "user_x", MARKET, aggressor, 100, Price("34.52"), BID_SIDE, 99999, 0) oec.apply_partial_fill_report(pf) assert oec.open_exposure_requests() == [] assert oec.is_open() is False assert oec.visible_qty() == 0 assert oec.current_exposure() == Exposure(None, 0, 1212344)
def __init__(self, market, side, price, visible_qty, hidden_qty=0): """ An individual quote expressing a desire to buy or sell a Product for a Price. Visible qty is required and hidden qty is optional, defaulting to 0 because many markets don't support hidden quantity. :param market: MarketObjects.Market.Market. :param side: Side. :param price: Price. :param visible_qty: int. Must be greater than 0 :param hidden_qty: int. Must be 0 or more. Optional. Defaults to 0. """ assert isinstance(price, Price) or isinstance(price, str) assert isinstance(side, Side) assert isinstance(market, Market) assert isinstance(visible_qty, int) assert isinstance(hidden_qty, int) assert visible_qty > 0, "A quote's visible qty must be greater than 0" assert hidden_qty >= 0, "A quote's hidden qty must be greater than or equal to 0" use_price = price if not isinstance(price, Price): use_price = Price(price) assert market.is_valid_price(use_price), \ "%s is not a valid price for a product with minimum price increment %s" % \ (str(use_price), str(market.mpi())) self._side = side self._market = market self._price_level = PriceLevel(use_price, visible_qty, hidden_qty, num_orders=1)
def test_subchain_getters_partial_fill_before_ack(): # pretty basic, just testing that it doesn't break n = NewOrderCommand(121234, 1234235.123, 2342, "user_x", MARKET, BID_SIDE, FAR, Price("34.52"), 1000) oec = OrderEventChain(n, LOGGER, MonotonicIntID()) # now aggressive partial fill pf = PartialFillReport(121236, 1234237.123, 2342, "user_x", MARKET, n, 44, Price("34.52"), BID_SIDE, 99999, 1000 - 44) oec.apply_partial_fill_report(pf) # now ack it ack = AcknowledgementReport(121235, 1234235.123, 2342, "user_x", MARKET, n, Price("34.52"), 1000-44, None) oec.apply_acknowledgement_report(ack) subchain = oec.most_recent_subchain() assert subchain.open_event() == n assert subchain.first_execution_report() == pf assert subchain.fills() == [pf] assert subchain.last_event() == ack
def test_comparison(): p = Price("91.543") p_less = Price('84.456') p_more = Price('92.123') p_same = Price('91.543') assert p_less < p_more assert p_less <= p_more assert p_less != p_more assert (p_less > p_more) is False assert (p_less >= p_more) is False assert (p_less == p_more) is False assert p >= p_same assert p <= p_same assert p == p_same assert (p != p_same) is False assert p_same >= p assert p_same <= p
def test_full_fill_on_unacked_cr_with_acked_new_order(): n = NewOrderCommand(1, 1234235.123, 2342, "user_x", MARKET, BID_SIDE, FAR, Price("34.52"), 1000) oec = OrderEventChain(n, LOGGER, MonotonicIntID()) # now ack it ack = AcknowledgementReport(2, 1234235.123, 2342, "user_x", MARKET, n, Price("34.52"), 1000, 1000) oec.apply_acknowledgement_report(ack) assert oec.visible_qty() == 1000 assert oec.current_exposure().qty() == 1000 assert oec.current_exposure().price() == Price("34.52") assert len(oec.open_exposure_requests()) == 0 assert oec.is_open() cr = CancelReplaceCommand(3, 1234236.842, 2342, "user_x", MARKET, BID_SIDE, Price("34.56"), 800) oec.apply_cancel_replace_command(cr) # now should have 2 open exposures assert oec.visible_qty() == 1000 assert oec.current_exposure().qty() == 1000 assert oec.current_exposure().price() == Price("34.52") assert oec.is_open() assert len(oec.open_exposure_requests()) == 1 assert oec.most_recent_requested_exposure() == Exposure(Price("34.56"), 800, 3) full_fill = FullFillReport(4, 1234237.123, 2342, "user_x", MARKET, cr, 800, Price("34.56"), BID_SIDE, 12345) oec.apply_full_fill_report(full_fill) assert oec.visible_qty() == 0 assert oec.current_exposure().price() is None assert oec.current_exposure().qty() == 0 assert oec.current_exposure().causing_event_id() == 4 assert len(oec.open_exposure_requests()) == 0 assert oec.is_open() is False