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_parital_passive_fill(): ob = build_base_order_book() # get baseline chain_aggressed_into = ob.best_priority_chain(ASK_SIDE) visible_qty = ob.visible_qty_at_price(ASK_SIDE, Price("34.52")) hidden_qty = ob.hidden_qty_at_price(ASK_SIDE, Price("34.52")) num_orders = ob.num_orders_at_price(ASK_SIDE, Price("34.52")) best_price = ob.best_price(ASK_SIDE) # the ack'd order getting aggresed into: # a1_ack = AcknowledgementReport(4, 1234000.888, 1002, "user_b", MARKET, a1, Price("34.52"), 35, 10) agg_new = NewOrderCommand(101, 1234002.123, 1008, "user_z", MARKET, BID_SIDE, FAR, Price("34.52"), 5) pf = PartialFillReport(102, 1234002.123, 1002, "user_b", MARKET, agg_new, 5, Price('34.52'), ASK_SIDE, 3333, 30) chain_aggressed_into.apply_partial_fill_report(pf) ob.handle_partial_fill_report(pf, chain_aggressed_into) # now test for changes # ask visible should be 5 less assert ob.visible_qty_at_price(ASK_SIDE, Price("34.52")) == visible_qty - 5 # ask hidden should stay the same assert hidden_qty == ob.hidden_qty_at_price(ASK_SIDE, Price("34.52")) # best price should be the same assert ob.best_ask_price() == best_price == Price("34.52") # num orders should stay the same assert num_orders == ob.num_orders_at_price(ASK_SIDE, Price("34.52")) # best chain on the ask should be the same assert ob.best_priority_chain(ASK_SIDE).chain_id() == chain_aggressed_into.chain_id() == 1002 # nothing on bid 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)
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_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_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 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_partial_passive_fill_for_all_qty(): # a partial fill for eveything should balk with some logs but should still be successful. # NOTE: this scenario is crazy and shouldn't actually happen (hidden getting filled before visible) # but what the hell, let's cut corners on a test ob = build_base_order_book() # get baseline chain_aggressed_into = ob.best_priority_chain(ASK_SIDE) second_ask_back = ob.order_chains_at_price(ASK_SIDE, Price("34.52"))[1] visible_qty = ob.visible_qty_at_price(ASK_SIDE, Price("34.52")) hidden_qty = ob.hidden_qty_at_price(ASK_SIDE, Price("34.52")) num_orders = ob.num_orders_at_price(ASK_SIDE, Price("34.52")) best_price = ob.best_price(ASK_SIDE) # the ack'd order getting aggresed into: # a1_ack = AcknowledgementReport(4, 1234000.888, 1002, "user_b", MARKET, a1, Price("34.52"), 35, 10) agg_new = NewOrderCommand(101, 1234002.123, 1008, "user_z", MARKET, BID_SIDE, FAR, Price("34.52"), 35) pf = PartialFillReport(102, 1234002.123, 1002, "user_b", MARKET, agg_new, 35, Price('34.52'), ASK_SIDE, 3333, 25) chain_aggressed_into.apply_partial_fill_report(pf) ob.handle_partial_fill_report(pf, chain_aggressed_into) # now test for changes # ask visible qty should be 10 less (the rest came from hidden) assert ob.visible_qty_at_price(ASK_SIDE, Price("34.52")) == visible_qty - 10 # ask hidden should be 25 (35-10 visible) less assert hidden_qty - 25 == ob.hidden_qty_at_price(ASK_SIDE, Price("34.52")) # best price should be the same assert ob.best_ask_price() == best_price == Price("34.52") # should be 1 less order assert num_orders - 1 == ob.num_orders_at_price(ASK_SIDE, Price("34.52")) # best chain on the ask should be what was the second back assert ob.best_priority_chain(ASK_SIDE).chain_id() == second_ask_back.chain_id() # chain should no longer exist in book chains = ob.order_chains_at_price(ASK_SIDE, Price("34.52")) found = False for chain in chains: if chain.chain_id() == chain_aggressed_into.chain_id(): found = True assert not found # nothing on bid 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)
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()
def test_partial_passive_fill_resets_visible_qty(): ob = build_base_order_book() # get baseline chain_aggressed_into = ob.best_priority_chain(ASK_SIDE) second_ask_back = ob.order_chains_at_price(ASK_SIDE, Price("34.52"))[1] visible_qty = ob.visible_qty_at_price(ASK_SIDE, Price("34.52")) hidden_qty = ob.hidden_qty_at_price(ASK_SIDE, Price("34.52")) num_orders = ob.num_orders_at_price(ASK_SIDE, Price("34.52")) best_price = ob.best_price(ASK_SIDE) # the ack'd order getting aggresed into: # a1_ack = AcknowledgementReport(4, 1234000.888, 1002, "user_b", MARKET, a1, Price("34.52"), 35, 10) agg_new = NewOrderCommand(101, 1234002.123, 1008, "user_z", MARKET, BID_SIDE, FAR, Price("34.52"), 10) pf = PartialFillReport(102, 1234002.123, 1002, "user_b", MARKET, agg_new, 10, Price('34.52'), ASK_SIDE, 3333, 25) chain_aggressed_into.apply_partial_fill_report(pf) ob.handle_partial_fill_report(pf, chain_aggressed_into) # now test for changes # ask visible qty should stay the same because the 10 was filled and then replenished due to iceberg activity assert ob.visible_qty_at_price(ASK_SIDE, Price("34.52")) == visible_qty # ask hidden should be 10 less becaue of replenishment of iceberg peak assert hidden_qty - 10 == ob.hidden_qty_at_price(ASK_SIDE, Price("34.52")) # best price should be the same assert ob.best_ask_price() == best_price == Price("34.52") # num orders should stay the same assert num_orders == ob.num_orders_at_price(ASK_SIDE, Price("34.52")) # best chain on the ask should be what was the second back assert ob.best_priority_chain(ASK_SIDE).chain_id() == second_ask_back.chain_id() # worst chain on the ask should be what was the first assert ob.order_chains_at_price(ASK_SIDE, Price("34.52"))[-1].chain_id() == chain_aggressed_into.chain_id() # nothing on bid 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)
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)
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