Exemplo n.º 1
0
def test_cancel_replace_order_down_in_qty():
    # should have no impact
    ob = build_base_order_book()
    prev_order_chains = ob.order_chains_at_price(BID_SIDE, Price("34.50"))
    assert len(prev_order_chains) == 2
    # and test correct order
    assert prev_order_chains[0].chain_id() == 1001
    assert prev_order_chains[1].chain_id() == 1004
    assert ob.best_priority_chain(BID_SIDE).chain_id() == 1001
    prev_visible_qty_at_tob = ob.visible_qty_at_price(BID_SIDE, Price("34.50"))
    prev_hidden_qty_at_tob = ob.hidden_qty_at_price(BID_SIDE, Price("34.50"))
    # now cancel replace the first bid down in size
    cr = CancelReplaceCommand(77, 1234012.123, prev_order_chains[0].chain_id(), prev_order_chains[0].user_id(), MARKET,
                              prev_order_chains[0].side(), prev_order_chains[0].current_price(), prev_order_chains[0].current_qty() - 5)
    prev_order_chains[0].apply_cancel_replace_command(cr)
    cr_ack = AcknowledgementReport(78, 1234012.123, prev_order_chains[0].chain_id(), prev_order_chains[0].user_id(),
                                   MARKET, cr, prev_order_chains[0].current_price(),
                                   prev_order_chains[0].current_qty() - 5, prev_order_chains[0].current_qty() - 5)
    prev_order_chains[0].apply_acknowledgement_report(cr_ack)
    ob.handle_acknowledgement_report(cr_ack, prev_order_chains[0])
    # assert that no ordering has changed
    current_order_chains = ob.order_chains_at_price(BID_SIDE, Price("34.50"))
    assert len(current_order_chains) == 2
    for chain in current_order_chains:
        print(chain)
    assert prev_order_chains[0].chain_id() == 1001
    assert prev_order_chains[1].chain_id() == 1004
    assert ob.best_priority_chain(BID_SIDE).chain_id() == 1001
    # size is 5 less
    assert ob.visible_qty_at_price(BID_SIDE, Price("34.50")) == prev_visible_qty_at_tob - 5
    assert ob.hidden_qty_at_price(BID_SIDE, Price("34.50")) == prev_hidden_qty_at_tob
Exemplo n.º 2
0
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
Exemplo n.º 3
0
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()
Exemplo n.º 4
0
def build_base_order_book():
    ob = OrderLevelBook(MARKET, LOGGER)
    b1 = NewOrderCommand(1, 1234000.123, 1001, "user_a", MARKET, BID_SIDE, FAR,
                         Price("34.50"), 50)
    bid_oec1 = OrderEventChain(b1, LOGGER, SUBCHAIN_ID_GENERATOR)
    b1_ack = AcknowledgementReport(2, 1234000.123, 1001, "user_a", MARKET, b1, Price("34.50"), 50, 50)
    bid_oec1.apply_acknowledgement_report(b1_ack)
    ob.handle_acknowledgement_report(b1_ack, bid_oec1)
    a1 = NewOrderCommand(3, 1234000.888, 1002, "user_b", MARKET, ASK_SIDE, FAR,
                         Price("34.52"), 35, 10)
    ask_oec1 = OrderEventChain(a1, LOGGER, SUBCHAIN_ID_GENERATOR)
    a1_ack = AcknowledgementReport(4, 1234000.888, 1002, "user_b", MARKET, a1, Price("34.52"), 35, 10)
    ask_oec1.apply_acknowledgement_report(a1_ack)
    ob.handle_acknowledgement_report(a1_ack, ask_oec1)
    a2 = NewOrderCommand(5, 1234001.888, 1003, "user_c", MARKET, ASK_SIDE, FAR,
                         Price("34.52"), 20, 20)
    ask_oec2 = OrderEventChain(a2, LOGGER, SUBCHAIN_ID_GENERATOR)
    a2_ack = AcknowledgementReport(6, 1234001.888, 1003, "user_b", MARKET, a2, Price("34.52"), 20, 20)
    ask_oec2.apply_acknowledgement_report(a2_ack)
    ob.handle_acknowledgement_report(a2_ack, ask_oec2)
    b2 = NewOrderCommand(9, 1234000.123, 1004, "user_z", MARKET, BID_SIDE, FAR,
                         Price("34.50"), 70)
    bid_oec2 = OrderEventChain(b2, LOGGER, SUBCHAIN_ID_GENERATOR)
    b2_ack = AcknowledgementReport(10, 1234000.123, 1004, "user_z", MARKET, b2, Price("34.50"), 70, 70)
    bid_oec2.apply_acknowledgement_report(b2_ack)
    ob.handle_acknowledgement_report(b2_ack, bid_oec2)

    # do some asserts to ensure we built book as expected
    bid_prices = ob.prices(BID_SIDE)
    print(ob.best_bid_price())
    print(bid_prices)
    assert len(bid_prices) == 1
    assert bid_prices[0] == Price("34.50")
    assert ob.best_bid_price() == Price("34.50")
    assert ob.best_bid_level() == PriceLevel(Price("34.50"), 120, 0, 2)
    assert ob.best_priority_chain(BID_SIDE) == bid_oec1
    ask_prices = ob.ask_prices()
    assert len(ask_prices) == 1
    assert ask_prices[0] == Price("34.52")
    assert ob.best_ask_price() == Price("34.52")
    assert ob.best_ask_level() == PriceLevel(Price("34.52"), 30, 25, 2)
    assert ob.best_priority_chain(ASK_SIDE) == ask_oec1
    return ob
Exemplo n.º 5
0
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()
Exemplo n.º 6
0
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)
Exemplo n.º 7
0
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
Exemplo n.º 8
0
def test_basic_partial_fill():
    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, 1000)
    oec.apply_acknowledgement_report(ack)
    aggressor = NewOrderCommand(1111, 1234237.123, 22222, "user_x", MARKET, ASK_SIDE, FAR, Price("34.52"), 44)
    # now resting partial fill
    pf = PartialFillReport(121236, 1234237.123, 2342, "user_x", MARKET, aggressor, 44, Price("34.52"),
                           BID_SIDE, 99999, 1000-44)
    oec.apply_partial_fill_report(pf)

    assert oec.open_exposure_requests() == []
    assert oec.current_exposure().price() == Price("34.52")
    assert oec.current_exposure().qty() == 1000-44
    assert oec.visible_qty() == 1000-44
    assert oec.iceberg_peak_qty() == 1000  # should not have changed
    assert oec.has_partial_fill()
Exemplo n.º 9
0
def test_basic_full_fill_on_acked_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 oec.is_open()
    aggressor = NewOrderCommand(1111, 1234237.123, 22222, "user_y", MARKET, ASK_SIDE, FAR, Price("34.52"), 1000)
    full_fill = FullFillReport(3, 1234237.123, 2342, "user_x", MARKET, aggressor, 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 oec.is_open() is False
Exemplo n.º 10
0
def test_acking_fak():
    # should not allow -- so no changes to order book
    ob = build_base_order_book()
    a = NewOrderCommand(56, 1234002.123, 1008, "user_z", MARKET, ASK_SIDE, FAK,
                        Price("34.51"), 35)
    ask_oec = OrderEventChain(a, LOGGER, SUBCHAIN_ID_GENERATOR)
    a_ack = AcknowledgementReport(57, 1234002.123, 1008, "user_z", MARKET, a, Price("34.51"), 35, 35)
    ask_oec.apply_acknowledgement_report(a_ack)
    ob.handle_acknowledgement_report(a_ack, ask_oec)
    # NOTHING SHOULD HAVE CHANGED
    bid_prices = ob.bid_prices()
    assert len(bid_prices) == 1
    assert bid_prices[0] == Price("34.50")
    assert ob.best_bid_price() == Price("34.50")
    assert ob.best_bid_level() == PriceLevel(Price("34.50"), 120, 0, 2)
    ask_prices = ob.ask_prices()
    assert len(ask_prices) == 1
    assert ask_prices[0] == Price("34.52")
    assert ob.best_ask_price() == Price("34.52")
    assert ob.best_ask_level() == PriceLevel(Price("34.52"), 30, 25, 2)
Exemplo n.º 11
0
def test_establish_new_ask_tob():
    ob = build_base_order_book()
    a = NewOrderCommand(56, 1234002.123, 1008, "user_z", MARKET, ASK_SIDE, FAR,
                        Price("34.51"), 35)
    ask_oec = OrderEventChain(a, LOGGER, SUBCHAIN_ID_GENERATOR)
    a_ack = AcknowledgementReport(57, 1234002.123, 1008, "user_z", MARKET, a, Price("34.51"), 35, 35)
    ask_oec.apply_acknowledgement_report(a_ack)
    ob.handle_acknowledgement_report(a_ack, ask_oec)
    # ask should  have changed
    ask_prices = ob.ask_prices()
    assert len(ask_prices) == 2  # now 2 prices
    assert ob.best_priority_chain(ASK_SIDE) == ask_oec  # the bid order chain above should now be best
    assert ask_prices[0] == Price("34.51")  # should be new best price
    assert ob.best_ask_price() == Price("34.51")  # should be new best price
    assert ob.best_ask_level() == PriceLevel(Price("34.51"), 35, 0,
                                             1)  # should have new best price level with only 1 order
    # bid should not have changed
    bid_prices = ob.bid_prices()
    assert len(bid_prices) == 1
    assert bid_prices[0] == Price("34.50")
    assert ob.best_bid_price() == Price("34.50")
    assert ob.best_bid_level() == PriceLevel(Price("34.50"), 120, 0, 2)
Exemplo n.º 12
0
def test_cancel_confirm_entire_price_level():
    ob = build_base_order_book()

    # first add an order at a second price (34.53)
    a = NewOrderCommand(56, 1234002.123, 1009, "user_x", MARKET, ASK_SIDE, FAR,
                        Price("34.53"), 20)
    ask_oec = OrderEventChain(a, LOGGER, SUBCHAIN_ID_GENERATOR)
    a_ack = AcknowledgementReport(57, 1234002.123, 1009, "user_z", MARKET, a, Price("34.53"), 20, 20)
    ask_oec.apply_acknowledgement_report(a_ack)
    ob.handle_acknowledgement_report(a_ack, ask_oec)

    # cancel the orderchains at best price
    id_generator = MonotonicIntID()
    for i, chain in enumerate(ob.order_chains_at_price(ASK_SIDE, ob.best_price(ASK_SIDE))):
        cancel_command = CancelCommand(id_generator.id(), 1234002.123, chain.chain_id(), chain.user_id(), MARKET,
                                       USER_CANCEL)
        chain.apply_cancel_command(cancel_command)
        cancel_report = CancelReport(id_generator.id(), 1234002.123, chain.chain_id(), chain.user_id(), MARKET,
                                     cancel_command, USER_CANCEL)
        chain.apply_cancel_report(cancel_report)
        ob.handle_cancel_report(cancel_report, chain)

    assert ob.best_priority_chain(ASK_SIDE).chain_id() == ask_oec.chain_id()
    # best price should now be 34.53
    assert ob.best_ask_price() == Price('34.53')
    # visible qty is 20
    assert ob.visible_qty_at_price(ASK_SIDE, ob.best_ask_price()) == 20
    # hidden qty is 0
    assert ob.hidden_qty_at_price(ASK_SIDE, ob.best_ask_price()) == 0
    # num orders is 1
    assert ob.num_orders_at_price(ASK_SIDE, ob.best_ask_price()) == 1

    # bids shouldn't change
    bid_prices = ob.bid_prices()
    assert len(bid_prices) == 1
    assert bid_prices[0] == Price("34.50")
    assert ob.best_bid_price() == Price("34.50")
    assert ob.best_bid_level() == PriceLevel(Price("34.50"), 120, 0, 2)
Exemplo n.º 13
0
def test_new_iceberg_order_ack():
    n = NewOrderCommand(121234, 1234235.123, 2342, "user_x", MARKET, BID_SIDE, FAR, Price("34.52"), 1000, 50)
    oec = OrderEventChain(n, LOGGER, MonotonicIntID())
    # no ack yet
    assert oec.most_recent_event() == n
    # check exposure
    assert len(oec.open_exposure_requests()) == 1
    assert oec.most_recent_requested_exposure() == oec.open_exposure_requests()[-1]
    assert oec.current_exposure() is None
    assert oec.most_recent_requested_exposure() == Exposure(Price("34.52"), 1000, 121234)
    # visible qty should be nothing still
    assert oec.visible_qty() == 0

    # now ack it
    ack = AcknowledgementReport(121235, 1234235.123, 2342, "user_x", MARKET, n, Price("34.52"), 1000, 50)
    oec.apply_acknowledgement_report(ack)
    assert oec.most_recent_event() == ack
    # check exposure
    assert len(oec.open_exposure_requests()) == 0
    assert oec.most_recent_requested_exposure() is None
    assert oec.current_exposure() == Exposure(Price("34.52"), 1000, 121235)
    # check visible qty
    assert oec.visible_qty() == 50
Exemplo n.º 14
0
def test_cancel_replace_order_up_in_qty():
    ob = build_base_order_book()
    # add a third order to the base order book bid side
    b = NewOrderCommand(56, 1234002.123, 1008, "user_z", MARKET, BID_SIDE, FAR,
                        Price("34.50"), 35)
    bid_oec = OrderEventChain(b, LOGGER, SUBCHAIN_ID_GENERATOR)
    b_ack = AcknowledgementReport(57, 1234002.123, 1008, "user_z", MARKET, b, Price("34.50"), 35, 35)
    bid_oec.apply_acknowledgement_report(b_ack)
    ob.handle_acknowledgement_report(b_ack, bid_oec)
    # should now be three order chains
    prev_order_chains = ob.order_chains_at_price(BID_SIDE, Price("34.50"))
    prev_visible_qty_at_tob = ob.visible_qty_at_price(BID_SIDE, Price("34.50"))
    prev_hidden_qty_at_tob = ob.hidden_qty_at_price(BID_SIDE, Price("34.50"))
    assert len(prev_order_chains) == 3
    # and test correct order
    assert prev_order_chains[0].chain_id() == 1001
    assert prev_order_chains[1].chain_id() == 1004
    assert prev_order_chains[2].chain_id() == 1008
    assert ob.best_priority_chain(BID_SIDE).chain_id() == 1001

    # cancel replace the first orderchain up in qty
    cr = CancelReplaceCommand(77, 1234012.123, prev_order_chains[0].chain_id(), prev_order_chains[0].user_id(), MARKET,
                              prev_order_chains[0].side(), prev_order_chains[0].current_price(), prev_order_chains[0].current_qty() + 40)
    prev_order_chains[0].apply_cancel_replace_command(cr)
    cr_ack = AcknowledgementReport(78, 1234012.123, prev_order_chains[0].chain_id(), "user_z", MARKET, cr,
                                   prev_order_chains[0].current_price(), prev_order_chains[0].current_qty() + 40,
                                   prev_order_chains[0].current_qty() + 40)
    prev_order_chains[0].apply_acknowledgement_report(cr_ack)
    ob.handle_acknowledgement_report(cr_ack, prev_order_chains[0])

    # should still only be one price on bid side as no price changes`
    assert len(ob.prices(BID_SIDE)) == 1
    # and that best price is still 34.50
    assert ob.best_price(BID_SIDE) == Price("34.50")
    # visible qty on the bid tob should have gone up by 40
    assert ob.visible_qty_at_price(BID_SIDE, Price("34.50")) == prev_visible_qty_at_tob + 40
    # hidden qty should not have gone up at all
    assert ob.hidden_qty_at_price(BID_SIDE, Price("34.50")) == prev_hidden_qty_at_tob, str(
        ob.hidden_qty_at_price(BID_SIDE, Price("34.50"))) + " != " + str(prev_hidden_qty_at_tob)
    # there should still be three but the order should be different
    current_order_chains = ob.order_chains_at_price(BID_SIDE, Price("34.50"))
    assert len(current_order_chains) == 3
    assert current_order_chains[0].chain_id() == 1004, "First chain at level should be 1004"
    assert current_order_chains[1].chain_id() == 1008, "Second chain at level should be 1008"
    assert current_order_chains[2].chain_id() == 1001, "Third chain at level should be 1001"
    # best priority order chain should now be 1004
    assert ob.best_priority_chain(BID_SIDE).chain_id() == 1004, "Best priority chain in order book should be 1004"

    prev_visible_qty_at_tob = ob.visible_qty_at_price(BID_SIDE, Price("34.50"))
    prev_hidden_qty_at_tob = ob.hidden_qty_at_price(BID_SIDE, Price("34.50"))

    # now move the middle order up in qty, which should move it to back of list
    cr2 = CancelReplaceCommand(79, 1234052.123, current_order_chains[1].chain_id(), current_order_chains[1].user_id(),
                               MARKET, current_order_chains[1].side(), current_order_chains[1].current_price(),
                               current_order_chains[1].current_qty() + 100, current_order_chains[1].current_qty() + 50)
    current_order_chains[1].apply_cancel_replace_command(cr2)
    cr_ack2 = AcknowledgementReport(80, 1234062.123, current_order_chains[1].chain_id(),
                                    current_order_chains[1].user_id(), MARKET, cr2,
                                    current_order_chains[1].current_price(),
                                    current_order_chains[1].current_qty() + 100,
                                    current_order_chains[1].current_qty() + 50)
    current_order_chains[1].apply_acknowledgement_report(cr_ack2)
    ob.handle_acknowledgement_report(cr_ack2, current_order_chains[1])
    # should still only be one price on bid side as no price changes`
    assert len(ob.prices(BID_SIDE)) == 1
    # and that best price is still 34.50
    assert ob.best_price(BID_SIDE) == Price("34.50")
    # visible qty on the bid tob should have gone up by 40
    assert ob.visible_qty_at_price(BID_SIDE, Price("34.50")) == prev_visible_qty_at_tob + 50
    # hidden qty should not have gone up at all
    assert ob.hidden_qty_at_price(BID_SIDE, Price("34.50")) == prev_hidden_qty_at_tob + 50, str(
        ob.hidden_qty_at_price(BID_SIDE, Price("34.50"))) + " != " + str(prev_hidden_qty_at_tob + 50)
    # there should still be three but the order should be different
    current_order_chains = ob.order_chains_at_price(BID_SIDE, Price("34.50"))
    assert len(current_order_chains) == 3
    assert current_order_chains[0].chain_id() == 1004, "First chain at level should be 1004"
    assert current_order_chains[1].chain_id() == 1001, "Second chain at level should be 1001"
    assert current_order_chains[2].chain_id() == 1008, "Third chain at level should be 1008"
    # best priority order chain should now be 1004
    assert ob.best_priority_chain(BID_SIDE).chain_id() == 1004, "Best priority chain in order book should be 1004"
Exemplo n.º 15
0
def test_partial_fill_on_multiple_unacked_requests():
    n = NewOrderCommand(1, 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, 1)

    cr1 = CancelReplaceCommand(2, 1234235.863, 2342, "user_x", MARKET, BID_SIDE, Price("34.51"), 800)
    oec.apply_cancel_replace_command(cr1)
    # now should have 2 open exposures
    assert len(oec.open_exposure_requests()) == 2
    assert oec.open_exposure_requests()[0] == Exposure(Price("34.52"), 1000, 1)
    assert oec.open_exposure_requests()[1] == Exposure(Price("34.51"), 800, 2)

    cr2 = CancelReplaceCommand(3, 1234236.842, 2342, "user_x", MARKET, BID_SIDE, Price("34.55"), 800)
    oec.apply_cancel_replace_command(cr2)
    # now should have 2 open exposures
    assert len(oec.open_exposure_requests()) == 3
    assert oec.open_exposure_requests()[0] == Exposure(Price("34.52"), 1000, 1)
    assert oec.open_exposure_requests()[1] == Exposure(Price("34.51"), 800, 2)
    assert oec.open_exposure_requests()[2] == Exposure(Price("34.55"), 800, 3)

    cr3 = CancelReplaceCommand(4, 1234236.842, 2342, "user_x", MARKET, BID_SIDE, Price("34.56"), 800)
    oec.apply_cancel_replace_command(cr3)
    # now should have 2 open exposures
    assert len(oec.open_exposure_requests()) == 4
    assert oec.open_exposure_requests()[0] == Exposure(Price("34.52"), 1000, 1)
    assert oec.open_exposure_requests()[1] == Exposure(Price("34.51"), 800, 2)
    assert oec.open_exposure_requests()[2] == Exposure(Price("34.55"), 800, 3)
    assert oec.open_exposure_requests()[3] == Exposure(Price("34.56"), 800, 4)

    # a partial fill should should only impact the one the partial fill is for
    # partially filling orderid 3 (cr2)
    pf1 = PartialFillReport(5, 1234237.123, 2342, "user_x", MARKET, cr2, 10, Price("34.55"),
                            BID_SIDE, 999, 790)
    oec.apply_partial_fill_report(pf1)
    assert len(oec.open_exposure_requests()) == 4
    assert oec.open_exposure_requests()[0] == Exposure(Price("34.52"), 1000, 1)
    assert oec.open_exposure_requests()[1] == Exposure(Price("34.51"), 800, 2)
    assert oec.open_exposure_requests()[2] == Exposure(Price("34.55"), 790, 3)
    assert oec.open_exposure_requests()[3] == Exposure(Price("34.56"), 800, 4)

    # and again
    pf2 = PartialFillReport(6, 1234237.123, 2342, "user_x", MARKET, cr2, 10, Price("34.55"),
                            BID_SIDE, 1000, 780)
    oec.apply_partial_fill_report(pf2)
    assert len(oec.open_exposure_requests()) == 4
    assert oec.open_exposure_requests()[0] == Exposure(Price("34.52"), 1000, 1)
    assert oec.open_exposure_requests()[1] == Exposure(Price("34.51"), 800, 2)
    assert oec.open_exposure_requests()[2] == Exposure(Price("34.55"), 780, 3)
    assert oec.open_exposure_requests()[3] == Exposure(Price("34.56"), 800, 4)

    # and now I can fill order id 4 (cr 3)
    pf3 = PartialFillReport(6, 1234237.123, 2342, "user_x", MARKET, cr3, 50, Price("34.56"),
                            BID_SIDE, 1001, 750)
    oec.apply_partial_fill_report(pf3)
    assert len(oec.open_exposure_requests()) == 4
    assert oec.open_exposure_requests()[0] == Exposure(Price("34.52"), 1000, 1)
    assert oec.open_exposure_requests()[1] == Exposure(Price("34.51"), 800, 2)
    assert oec.open_exposure_requests()[2] == Exposure(Price("34.55"), 780, 3)
    assert oec.open_exposure_requests()[3] == Exposure(Price("34.56"), 750, 4)

    # now start acking them
    ack1 = AcknowledgementReport(10, 1234235.123, 2342, "user_x", MARKET, n, Price("34.52"), 1000, None)
    oec.apply_acknowledgement_report(ack1)
    assert len(oec.open_exposure_requests()) == 3
    assert oec.open_exposure_requests()[0] == Exposure(Price("34.51"), 800, 2)
    assert oec.open_exposure_requests()[1] == Exposure(Price("34.55"), 780, 3)
    assert oec.open_exposure_requests()[2] == Exposure(Price("34.56"), 750, 4)
    assert oec.current_exposure() == Exposure(Price("34.52"), 1000, 10)

    ack2 = AcknowledgementReport(11, 1234235.123, 2342, "user_x", MARKET, cr1, Price("34.51"), 800, None)
    oec.apply_acknowledgement_report(ack2)
    assert len(oec.open_exposure_requests()) == 2
    assert oec.open_exposure_requests()[0] == Exposure(Price("34.55"), 780, 3)
    assert oec.open_exposure_requests()[1] == Exposure(Price("34.56"), 750, 4)
    assert oec.current_exposure() == Exposure(Price("34.51"), 800, 11)

    ack3 = AcknowledgementReport(12, 1234235.123, 2342, "user_x", MARKET, cr2, Price("34.55"), 780, None)
    oec.apply_acknowledgement_report(ack3)
    assert len(oec.open_exposure_requests()) == 1
    print(oec.open_exposure_requests()[0])
    assert oec.open_exposure_requests()[0] == Exposure(Price("34.56"), 750, 4)
    assert oec.current_exposure() == Exposure(Price("34.55"), 780, 12)

    ack4 = AcknowledgementReport(13, 1234235.123, 2342, "user_x", MARKET, cr3, Price("34.56"), 750, None)
    oec.apply_acknowledgement_report(ack4)
    assert len(oec.open_exposure_requests()) == 0
    assert oec.current_exposure() == Exposure(Price("34.56"), 750, 13)
Exemplo n.º 16
0
def test_populating_tob():
    ob = OrderLevelBook(MARKET, LOGGER)
    b1 = NewOrderCommand(1, 1234000.123, 1001, "user_a", MARKET, BID_SIDE, FAR,
                         Price("34.50"), 50)
    bid_oec1 = OrderEventChain(b1, LOGGER, SUBCHAIN_ID_GENERATOR)
    b1_ack = AcknowledgementReport(2, 1234000.123, 1001, "user_a", MARKET, b1, Price("34.50"), 50, 50)
    bid_oec1.apply_acknowledgement_report(b1_ack)
    ob.handle_acknowledgement_report(b1_ack, bid_oec1)
    assert ob.best_bid_price() == Price("34.50")
    assert ob.best_priority_chain(BID_SIDE).chain_id() == bid_oec1.chain_id()
    assert ob.best_bid_level().price() == Price("34.50")
    assert ob.best_bid_level().visible_qty() == 50
    assert ob.best_bid_level().hidden_qty() == 0

    # now add an offer
    a1 = NewOrderCommand(3, 1234000.888, 1002, "user_b", MARKET, ASK_SIDE, FAR,
                         Price("34.52"), 35, 10)
    ask_oec1 = OrderEventChain(a1, LOGGER, SUBCHAIN_ID_GENERATOR)
    a1_ack = AcknowledgementReport(4, 1234000.888, 1002, "user_b", MARKET, a1, Price("34.52"), 35, 10)
    ask_oec1.apply_acknowledgement_report(a1_ack)
    ob.handle_acknowledgement_report(a1_ack, ask_oec1)
    assert ob.best_ask_price() == Price("34.52")
    assert ob.best_priority_chain(ASK_SIDE).chain_id() == ask_oec1.chain_id()
    assert ob.best_ask_level().price() == Price("34.52")
    assert ob.best_ask_level().visible_qty() == 10
    assert ob.best_ask_level().hidden_qty() == 25
    assert ob.best_ask_level().number_of_orders() == 1

    # bid should not have changed
    assert ob.best_bid_price() == Price("34.50")
    assert ob.best_priority_chain(BID_SIDE).chain_id() == bid_oec1.chain_id()
    assert ob.best_bid_level().price() == Price("34.50")
    assert ob.best_bid_level().visible_qty() == 50
    assert ob.best_bid_level().hidden_qty() == 0
    assert ob.best_ask_level().number_of_orders() == 1
    assert ob.num_orders_at_price(BID_SIDE, Price("34.50")) == 1

    # add a second ask order to top of book
    a2 = NewOrderCommand(5, 1234001.888, 1003, "user_c", MARKET, ASK_SIDE, FAR,
                         Price("34.52"), 20, 20)
    ask_oec2 = OrderEventChain(a2, LOGGER, SUBCHAIN_ID_GENERATOR)
    a2_ack = AcknowledgementReport(6, 1234001.888, 1003, "user_b", MARKET, a2, Price("34.52"), 20, 20)
    ask_oec2.apply_acknowledgement_report(a2_ack)
    ob.handle_acknowledgement_report(a2_ack, ask_oec2)
    assert ob.best_ask_price() == Price("34.52")  # best price has not changed
    assert ob.best_priority_chain(ASK_SIDE).chain_id() == ask_oec1.chain_id()  # best priority chain has not changed
    assert ob.best_ask_level().price() == Price("34.52")  # price of best level has not changed
    print(ob.best_ask_level().visible_qty())
    assert ob.best_ask_level().visible_qty() == 10 + 20  # visible qty should have got up by 20
    assert ob.best_ask_level().hidden_qty() == 25  # hidden qty should not have changed
    assert ob.best_ask_level().number_of_orders() == 2  # num orders should go up 2
    assert ob.num_orders_at_price(ASK_SIDE, Price("34.52")) == 2

    # bid should not have changed
    assert ob.best_bid_price() == Price("34.50")
    assert ob.best_priority_chain(BID_SIDE).chain_id() == bid_oec1.chain_id()
    assert ob.best_bid_level().price() == Price("34.50")
    assert ob.best_bid_level().visible_qty() == 50
    assert ob.best_bid_level().hidden_qty() == 0
    assert ob.best_bid_level().number_of_orders() == 1
    assert ob.num_orders_at_price(BID_SIDE, Price("34.50")) == 1

    # add a new bid at tob price
    b2 = NewOrderCommand(9, 1234000.123, 1004, "user_z", MARKET, BID_SIDE, FAR,
                         Price("34.50"), 70)
    bid_oec2 = OrderEventChain(b2, LOGGER, SUBCHAIN_ID_GENERATOR)
    b2_ack = AcknowledgementReport(10, 1234000.123, 1004, "user_z", MARKET, b2, Price("34.50"), 70, 70)
    bid_oec2.apply_acknowledgement_report(b2_ack)
    ob.handle_acknowledgement_report(b2_ack, bid_oec2)
    assert ob.best_bid_price() == Price("34.50")
    assert ob.best_priority_chain(BID_SIDE).chain_id() == bid_oec1.chain_id()
    assert ob.best_bid_level().price() == Price("34.50")
    assert ob.best_bid_level().visible_qty() == 120
    assert ob.best_bid_level().hidden_qty() == 0
    assert ob.best_ask_level().number_of_orders() == 2
    assert ob.num_orders_at_price(BID_SIDE, Price("34.50")) == 2

    # asks should not have changed
    assert ob.best_ask_price() == Price("34.52")  # best price has not changed
    assert ob.best_priority_chain(ASK_SIDE).chain_id() == ask_oec1.chain_id()  # best priority chain has not changed
    assert ob.best_ask_level().price() == Price("34.52")  # price of best level has not changed
    assert ob.best_ask_level().visible_qty() == 10 + 20  # visible qty should have got up by 20
    assert ob.best_ask_level().hidden_qty() == 25  # hidden qty should not have changed
    assert ob.best_ask_level().number_of_orders() == 2  # num orders should go up 2
    assert ob.num_orders_at_price(ASK_SIDE, Price("34.52")) == 2
Exemplo n.º 17
0
def get_events():
    # set up a Market for the events. For that you need at least:
    #  1) the Product
    #  2) the Endpoint
    #  3) the PriceFactory
    prod = Product("AAAA", "Test Product")
    ep = Endpoint("Exchange 1", "EXC1")
    pf = PriceFactory(
        "0.01"
    )  # pricefactory needs the minimum price increment, which is 0.01 for this example
    market = Market(prod, ep, pf)

    # now create a mapping of what we'll parse out of the file to the Market.
    # This comes in even more handy when there are multiple markets
    mrkt_dict = {("AAAA", "EXC1"): market}

    # set up the time stamp parser
    time_stamp_frmt = "%Y-%m-%d %H:%M:%S.%f"

    # we are going to keep a dictionary of event_id to Command so that we can properly create Execution Reports
    id_to_cmd = {}

    created_events = []

    # first we need to parse each line
    for line in EXAMPLE_DATA:
        parts = line[:-1].split(',')
        # skip header
        if parts[0] == "Order ID":
            continue

        # Order Id is the unique identifier of the order chain
        chain_id = parts[0]
        # Index is the unique identifier of the event
        event_id = int(parts[1])
        # Need an identifier of the user that placed the order
        user = parts[7]

        # get the event time
        event_time = datetime.strptime(parts[3], time_stamp_frmt)
        # Event objects what the time stamp as a float (seconds.microseconds) so convert to time since epoch
        time_stamp = datetime_to_epoch(event_time)

        # now get the market
        prod_name = parts[4]
        ep_name = parts[5]
        mrkt = mrkt_dict[(prod_name, ep_name)]

        # get the side: not all events contain side so default is None.
        # Buttonwood provides a helper that converts the most common str representations of Buy & Sell to Side objects
        side = Side.get_side(parts[8])

        # get the time in force. Not all events need time in force so the default is None.
        # Note: could have used OrderEventContants.TIME_IN_FORCE_STR_TO_INT here but wanted to show a more extensive use
        #   of the constants
        if parts[6] == "FAR":
            tif = OrderEventConstants.FAR
        elif parts[6] == "FAK":
            tif = OrderEventConstants.FAK
        elif parts[6] == "FOK":
            tif = OrderEventConstants.FOK
        elif parts[6] == "":
            tif = None
        else:
            raise Exception("Could not convert %s to a known TimeInForce" %
                            parts[6])

        # get event type so we can create the right events
        event_type = parts[2]

        if event_type == "New":  # for event type "New" create a new event
            # get price, using Market's get_price function that will gets a Price object for a string, Decimal, or int
            price = mrkt.get_price(parts[9])
            qty = int(parts[10])
            event = NewOrderCommand(event_id, time_stamp, chain_id, user,
                                    market, side, tif, price, qty)
            # add the event to the event id to command dictionary
            id_to_cmd[event_id] = event
        elif event_type == "Mod":  # for event type "Mod" create a cancel replace event
            # get price, using Market's get_price function that will gets a Price object for a string, Decimal, or int
            price = mrkt.get_price(parts[9])
            qty = int(parts[10])
            event = CancelReplaceCommand(event_id, time_stamp, chain_id, user,
                                         market, side, price, qty)
            # add the event to the event id to command dictionary
            id_to_cmd[event_id] = event
        elif event_type == "Cancel":  # for event type "Cancel" create a Cancel command event
            # there can be different types of cancels, but in this case we are assuming it is a user requested cancel
            cancel_type = CancelReasons.USER_CANCEL
            event = CancelCommand(event_id, time_stamp, chain_id, user, market,
                                  cancel_type)
            # add the event to the event id to command dictionary
            id_to_cmd[event_id] = event
        elif event_type == "Ack":  # for event type "Ack" create an Acknowledgement
            # this example file has no concept of iceberg orders so iceberg_peak is None (which will cause buttonwood to
            #  to treat the entire order qty as an iceberg
            iceberg_peak = None
            # get price, using Market's get_price function that gets a Price object for a string, Decimal, or int
            price = mrkt.get_price(parts[9])
            qty = int(parts[10])
            # response to command is the command it is acknowledging, get that ID and look it up from our id_to_cmd dict
            response_to_id = int(parts[12])
            response_to_cmd = id_to_cmd[response_to_id]
            event = AcknowledgementReport(event_id, time_stamp, chain_id, user,
                                          market, response_to_cmd, price, qty,
                                          iceberg_peak)
        elif event_type == "Cancel Conf":  # for event type "Cancel Conf" create a Cancel report event
            # get the cancel reason
            if parts[15] == "FOK Miss":
                reason = CancelReasons.FOK_CANCEL
            elif parts[15] == "Requested":
                reason = CancelReasons.USER_REQUESTED
            else:
                raise Exception("Could not convert %s to a cancel reason." %
                                parts[15])
            # cancel command is the command that caused the cancel, get that ID and look it up from our id_to_cmd dict
            response_to_id = int(parts[12])
            response_to_cmd = id_to_cmd[response_to_id]
            event = CancelReport(event_id, time_stamp, chain_id, user, market,
                                 response_to_cmd, reason)
        elif event_type == "Part Fill":  # if event type "Part Fill" create a Partial Fill event
            # the aggressing command comes from getting the id and looking it up in the id to cmd dict
            aggressing_id = int(parts[13])
            aggressing_cmd = id_to_cmd[aggressing_id]
            # get fill price, using Market's get_price function that gets a Price object for a string, Decimal, or int
            fill_price = mrkt.get_price(parts[9])
            fill_qty = int(parts[10])
            # get leaves qty from the file
            leaves_qty = int(parts[11])
            # get the match_id from the file
            match_id = parts[14]
            event = PartialFillReport(event_id, time_stamp, chain_id, user,
                                      market, aggressing_cmd, fill_qty,
                                      fill_price, side, match_id, leaves_qty)
        elif event_type == "Full Fill":  # if event type "Full Fill" create a Partial Fill event
            # the aggressing command comes from getting the id and looking it up in the id to cmd dict
            aggressing_id = int(parts[13])
            aggressing_cmd = id_to_cmd[aggressing_id]
            # get fill price, using Market's get_price function that gets a Price object for a string, Decimal, or int
            fill_price = mrkt.get_price(parts[9])
            fill_qty = int(parts[10])
            # full fills don't need/have a leaves qty because nothing is left.
            # get the match_id from the file
            match_id = parts[14]
            event = FullFillReport(event_id, time_stamp, chain_id, user,
                                   market, aggressing_cmd, fill_qty,
                                   fill_price, side, match_id)
        else:
            raise Exception("Could not convert %s to an Event" % event_type)

        created_events.append(event)
    return created_events