def test_to_detailed_json(): # this is only testing that it isn't broken / bad code prod = Product("AAA", "Some Product named AAA") prod.set_identifier("CUSIP", "12345") prod.set_identifier("internal_id", "8u98792") mrkt = Market(prod, ENDPOINT, PRICE_FACTORY) json.dumps(mrkt.to_detailed_json())
def test_failed_instantiation_products_not_the_same(): market1 = Market(Product("MSFT", "Microsoft"), Endpoint("Nasdaq", "NSDQ"), PriceFactory(".01")) market2 = Market(Product("APPL", "Apple"), Endpoint("Nasdaq", "NSDQ"), PriceFactory(".01")) bid_quote = Quote(market1, BID_SIDE, "25.23", 18) ask_quote = Quote(market2, ASK_SIDE, "26.20", 233) with pytest.raises(Exception): TwoSidedQuote(bid_quote, ask_quote)
def test_failed_set_sell_quote_wrong_product(): market1 = Market(Product("MSFT", "Microsoft"), Endpoint("Nasdaq", "NSDQ"), PriceFactory("0.01")) market2 = Market(Product("APPL", "Apple"), Endpoint("Nasdaq", "NSDQ"), PriceFactory("0.01")) bid_quote = Quote(market1, BID_SIDE, "25.23", 18) ask_quote = Quote(market1, ASK_SIDE, "26.20", 233) ask_quote2 = Quote(market2, ASK_SIDE, "25.98", 3) tsq = TwoSidedQuote(bid_quote, ask_quote) with pytest.raises(Exception): tsq.set_sell_quote(ask_quote2)
def test_default_market_creation(): mrkt = Market(PRODUCT, ENDPOINT, PRICE_FACTORY) assert PRODUCT == mrkt.product() assert ENDPOINT == mrkt.endpoint() assert mrkt.min_price_increment() == mrkt.mpi() == Decimal("0.01") assert mrkt.min_qty() == 1 assert mrkt.qty_increment() == 1 assert mrkt.max_qty() == sys.maxsize
def test_market_creation(): mrkt = Market(PRODUCT, ENDPOINT, PRICE_FACTORY, min_qty=2, qty_increment=4) assert PRODUCT == mrkt.product() assert ENDPOINT == mrkt.endpoint() assert mrkt.min_price_increment() == mrkt.mpi() == Decimal("0.01") assert mrkt.min_qty() == 2 assert mrkt.qty_increment() == 4
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_is_valid_qty_defaaults(): mrkt = Market(PRODUCT, ENDPOINT, PRICE_FACTORY) assert not mrkt.is_valid_qty(0) assert mrkt.is_valid_qty(1) assert mrkt.is_valid_qty(3) assert mrkt.is_valid_qty(234566346) assert mrkt.is_valid_qty(sys.maxsize) assert not mrkt.is_valid_qty(sys.maxsize + 1)
def test_basic_equality(): mrkt1 = Market(PRODUCT, ENDPOINT, PRICE_FACTORY) mrkt2 = Market(PRODUCT, ENDPOINT, PRICE_FACTORY) assert mrkt1 == mrkt2 mrkt2 = Market(Product("AAA", "Some Product named AAA"), ENDPOINT, PRICE_FACTORY) assert mrkt1 == mrkt2 mrkt2 = Market(PRODUCT, Endpoint("GenMatch", "Generic matching venue"), PRICE_FACTORY) assert mrkt1 == mrkt2 mrkt2 = Market(Product("BBB", "blah"), ENDPOINT, PRICE_FACTORY) assert mrkt1 != mrkt2 mrkt2 = Market(PRODUCT, Endpoint("xxx", "another endpoint"), PRICE_FACTORY) assert mrkt1 != mrkt2
def test_is_valid_qty(): mrkt = Market(PRODUCT, ENDPOINT, PRICE_FACTORY, min_qty=2, qty_increment=4, max_qty=1000) assert not mrkt.is_valid_qty(0) assert not mrkt.is_valid_qty(1) assert mrkt.is_valid_qty(2) assert not mrkt.is_valid_qty(3) assert not mrkt.is_valid_qty(4) assert not mrkt.is_valid_qty(5) assert mrkt.is_valid_qty(6) assert not mrkt.is_valid_qty(7) assert not mrkt.is_valid_qty(8) assert not mrkt.is_valid_qty(9) assert mrkt.is_valid_qty(10) assert mrkt.is_valid_qty(14) assert not mrkt.is_valid_qty(1001)
def test_to_json(): # this is only testing that it isn't broken / bad code mrkt = Market(PRODUCT, ENDPOINT, PRICE_FACTORY) json.dumps(mrkt.to_json())
SOFTWARE. """ import pytest from buttonwood.MarketObjects.Events.OrderEventConstants import * from buttonwood.MarketObjects.Events.OrderEvents import NewOrderCommand from buttonwood.MarketObjects.Endpoint import Endpoint from buttonwood.MarketObjects.Market import Market from buttonwood.MarketObjects.Price import Price from buttonwood.MarketObjects.Price import PriceFactory from buttonwood.MarketObjects.Product import Product from buttonwood.MarketObjects.Side import BID_SIDE from buttonwood.MarketObjects.Events.OrderEventConstants import MARKET as MARKET_ORDER from buttonwood.MarketObjects.Events.OrderEventConstants import LIMIT as LIMIT_ORDER MARKET = Market(Product("MSFT", "Microsoft"), Endpoint("Nasdaq", "NSDQ"), PriceFactory("0.01")) 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 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