def test_inverse_price(): GIVEN("a price") buy_price = 2 WHEN("we calculate the inverse") sell_price = calc_inverse_price(buy_price) THEN("the correct price is returned") assert sell_price == 2 GIVEN("another valid price") buy_price = 1.5 WHEN("we calculate the sell price") sell_price = calc_inverse_price(buy_price) THEN("the correct price is returned") assert sell_price == 1 / (1 - (1 / buy_price)) GIVEN("a string price") buy_price = "a price" WHEN("we calculate the sell price") sell_price = calc_inverse_price(buy_price) THEN("the sell price is shown to be not a number") assert is_not_a_number(sell_price) GIVEN("a negative price") buy_price = -2 WHEN("we calculate the sell price") sell_price = calc_inverse_price(buy_price) THEN("the sell price is shown to be not a number") assert is_not_a_number(sell_price) GIVEN("a price between 0 and 1") buy_price = 0.99 WHEN("we calculate the sell price") sell_price = calc_inverse_price(buy_price) THEN("the sell price is shown to be not a number") assert is_not_a_number(sell_price)
def test_get_ids_for_model_data(): GIVEN("a data handler with some data and two fixed probabilities") GIVEN("a data handler and the directory and file name of a test file") directory = "./data/29184567" file_name = "1.156230797.txt" file = HistoricalExternalAPIFileHander(directory=directory, file=file_name) record = file.get_file_as_list()[0] market_start_time = file.get_market_start_time() adapter = ExternalAPIMarketRecordAdapter( market_start_time=market_start_time) mediator = MockMediator() handler = DataHandler( mediator=mediator, adapter=adapter, container=DataContainer(), ) handler.process_data(record) WHEN( "we set the probabilities of two items and get the ids required for the next model run" ) ids = handler.get_unique_ids() for runner_id in ids[0:2]: handler._set_probability(runner_id=runner_id, probability=0.1) ids.pop(0) THEN("the list omits the items which have fixed probabilities") model_ids = handler._get_ids_for_model_data() assert model_ids == ids assert len(model_ids) < len(handler.get_unique_ids())
def test_regex_match(): GIVEN("a pattern and a string that match") a_str = "This is a string" pattern = r"This\sis" WHEN("we call regex_match") return_str = regex_match(pattern=pattern, str=a_str) THEN("the string is returned") assert return_str == a_str GIVEN("a pattern and a string that do not match") a_str = "This is a string" pattern = r"This\sisnt" WHEN("we call regex_match") return_str = regex_match(pattern=pattern, str=a_str) THEN("the string is returned") assert return_str is None GIVEN("a date pattern and a string that match") a_str = "1984-11-07T12:45:00Z" pattern = r"\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z" WHEN("we call regex_match") return_str = regex_match(pattern=pattern, str=a_str) THEN("the string is returned") assert return_str == a_str GIVEN("a different date pattern and a string that match") a_str = "1984-11-07T12:45:00.000Z" pattern = r"\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z" WHEN("we call regex_match") return_str = regex_match(pattern=pattern, str=a_str) THEN("the string is returned") assert return_str == a_str
def test_calc_sell_liability(): GIVEN("a price and a size") price = 1.01 size = 100 WHEN("we calculate the sell liability") liability = calc_sell_liability(price=price, size=size) THEN("the correct value is returned") assert liability == 100 * (1.01 - 1) GIVEN("an invalid price and a size") price = 0.99 size = 1000000 WHEN("we calculate the sell liability") liability = calc_sell_liability(price=price, size=size) THEN("the correct value is returned") assert liability == 0 GIVEN("a price and an invalid size") price = 1.99 size = -1 WHEN("we calculate the sell liability") liability = calc_sell_liability(price=price, size=size) THEN("the correct value is returned") assert liability == 0 GIVEN("an invalid price and an invalid size") price = 1 size = -1 WHEN("we calculate the sell liability") liability = calc_sell_liability(price=price, size=size) THEN("the correct value is returned") assert liability == 0
def test_date_time_epoch(): GIVEN("a UTC date time string with milliseconds") utc_date_time_str = "2019-01-01T00:00:00.000Z" WHEN("we get the epoch representation") epoch = DateTime(utc_date_time_str).get_epoch() THEN("the correct epoch is returned") local_epoch = 1546261200 assert epoch == local_epoch GIVEN("a UTC date time string and another that is 60 seconds afterwards") first_date_time_str = "2019-01-01T00:00:00.000Z" second_date_time_str = "2019-01-01T00:01:00.000Z" WHEN( "we create instances of DateTime and subtract the epochs from one another" ) seconds_difference = (DateTime(first_date_time_str).get_epoch() - DateTime(second_date_time_str).get_epoch()) THEN("the difference is as expected") assert seconds_difference == -60 GIVEN("a UTC date time strings") utc_date_time_str = "2019-01-01T00:00:00.000Z" WHEN( "we create instances of DateTime and subtract the epochs from one another" ) seconds_difference = (DateTime(utc_date_time_str).get_epoch() - DateTime(utc_date_time_str).get_epoch()) THEN("there is no difference") assert seconds_difference == 0 GIVEN("two UTC date time strings 60 seconds apart") first_date_time_str = "2019-01-01T00:01:00.000Z" second_date_time_str = "2019-01-01T00:00:00.000Z" WHEN( "we create instances of DateTime and subtract the epochs from one another" ) seconds_difference = (DateTime(first_date_time_str).get_epoch() - DateTime(second_date_time_str).get_epoch()) THEN("the difference is as expected") assert seconds_difference == 60 GIVEN("two milliseconds since epoch 1 second apart") first_epoch = 1569876588922 second_epoch = 1569876587922 WHEN( "we create instances of DateTime and subtract the epochs from one another" ) seconds_difference = (DateTime(first_epoch).get_epoch() - DateTime(second_epoch).get_epoch()) THEN("the difference is as expected") assert seconds_difference == 1
def test_is_valid_price(): GIVEN("a price") price = 1.01 WHEN("we check if the price is valid") valid = is_valid_price(price) THEN("a true value is returned") assert valid is True GIVEN("an invalid price") price = 1 WHEN("we check if the price is valid") valid = is_valid_price(price) THEN("a false value is returned") assert valid is False
def test_number_dict(): GIVEN("a dictionary") data = {"a": 1, "b": 2, "c": 3} WHEN("we test if it is a number") true = is_a_number(data) THEN("it is not") assert not true GIVEN("a numeric only dictionary") data = {1: 1, 2: 2, 3: 3} WHEN("we test if it is a number") true = is_a_number(data) THEN("it is not") assert not true
def test_not_nan(): GIVEN("a value that is a number") number = 1 WHEN("we check if the value is not a number") true = is_not_a_number(number) THEN("it is not") assert not true GIVEN("a None value") none = None WHEN("we check if the value is not a number") true = is_not_a_number(none) THEN("it is not") assert not true
def test_nan_to_num(): GIVEN("a value that is not a number") nan = not_a_number() WHEN("we convert the value to a number") number = not_a_number_to_number(nan) THEN("it is now the number 0") assert number == 0
def test_number_none(): GIVEN("a None value") none = None WHEN("we test if it is a number") true = is_a_number(none) THEN("it is not") assert not true
def test_number_list(): GIVEN("a list") data = [1, 2, 3, 4] WHEN("we test if it is a number") true = is_a_number(data) THEN("it is not") assert not true
def test_simple_comp_data(): GIVEN("a simple set of data and a probability handler") items = ( { "id": 123, "sp_probability": 0.476190476190476 }, { "id": 456, "sp_probability": 0.476190476190476 }, ) handler = ProbabilityHandler(items=items, name="sp_probability", correct_probability=1) WHEN("we calculate the compositional probabilities") compositional_probabilities = handler.calc_compositional_probabilities() THEN("a list of dictionaries with the correct values is returned") assert compositional_probabilities == [ { "id": 123, "compositional_probability": 0.5 }, { "id": 456, "compositional_probability": 0.5 }, ]
def test_exit_run_on_no_data(mock_call_exchange): GIVEN("a handler") external_api = ExternalAPIMarketHandler(environment="Dev", headers={}, market_id=45678) handler = MarketHandler( market_id=45678, external_api=external_api, market_start_time="2019-01-01T00:00:00.000Z", ) external_api.set_mediator(mediator=handler) mock_call_exchange.return_value = {} WHEN("we call run and no data is return from the api") for i in range(9): try: maybe_s = "s" if i > 0 else "" THEN(f"the handler will run {i + 1} time{maybe_s} without error") handler.run() except SystemExit: fail("Unexpected SystemExit") WHEN("we call run and no data is returned a 10th time") with raises(SystemExit) as system_exit: handler.run() THEN("the system will exit") assert system_exit.type == SystemExit assert system_exit.value.code == 0
def test_calc_order_size(): GIVEN("a handler and a list of items with risk_percentages") bank = 1000 mediator = MockMediator() handler = OrdersHandler(mediator=mediator, bank=bank) items = [ { "id": 123, "risk_percentage": -5 }, { "id": 101, "risk_percentage": 0.001 }, { "id": 456, "risk_percentage": 0.01 }, { "id": 789, "risk_percentage": 0.1 }, { "id": 202, "risk_percentage": 0.156788 }, ] WHEN("we calculate the size of the orders") for item in items: size = handler._calc_order_size(item=item) THEN("the correct sizes are returned") assert size == round(max(item.get("risk_percentage"), 0) * bank, 2)
def test_simple_comp_data(): GIVEN("a simple set of data and a data transform handler") items = ( { "id": 123, "sp_back_price": 2.1 }, { "id": 456, "sp_back_price": 2.1 }, ) handler = TransformHandler() handler._set_items(items=items) WHEN("we calculate the compositional data") compositional_data = handler._get_compositional_data( price_name="sp_back_price") THEN("a list of dictionaries with the correct values is returned") assert compositional_data == [ { "id": 123, "compositional_probability": 0.5, "compositional_price": 2 }, { "id": 456, "compositional_probability": 0.5, "compositional_price": 2 }, ]
def test_number_number(): GIVEN("a number") number = 1 WHEN("we test if it is a number") true = is_a_number(number) THEN("it is") assert true
def test_post_order(mock_notify): GIVEN("a file, a directory and a mock mediator") directory = "./dev" file = "1.163093692.bz2" mediator = MockMediator() WHEN("we instantiate the handler and post a valid order") handler = HistoricalDownloadFileHandler(file=file, directory=directory) handler.set_mediator(mediator) runner_id = 2121212 orders = [{ "id": runner_id, "type": "BUY", "ex_price": 2.5, "size": 1000000 }] handler.post_order(orders) THEN("the correct data is passed to the mediator") args, kwargs = mock_notify.call_args assert args == () data = kwargs.get("data") assert data.get("response") == [{ "instruction": { "selectionId": runner_id }, "status": "SUCCESS" }] assert data.get("orders") == orders
def test_buy_metadata(required_variables): GIVEN("a dictionary with the correct information") item_data = __get_data() variables = [ "id", "removal_date", "sp_back_size", "ex_back_size", "sp_back_price", "ex_average_back_price", "ex_offered_back_price", ] required_variables.return_value = variables WHEN("we instantiate the item handler object") adapted_item_data = ItemAdapter(item_data).get_adapted_data() THEN("the object has all of the correct information") assert adapted_item_data.get("id") == __get_id(item_data) assert is_not_a_number(adapted_item_data.get("removal_date")) assert adapted_item_data.get("sp_back_size") == __calc_sp_back_size(item_data) assert adapted_item_data.get("ex_back_size") == __calc_ex_back_size(item_data) assert adapted_item_data.get("sp_back_price") == __get_sp_back_price(item_data) assert adapted_item_data.get( "ex_average_back_price" ) == __calc_ex_average_back_price(item_data) assert adapted_item_data.get( "ex_offered_back_price" ) == __get_ex_offered_back_price(item_data) assert len(adapted_item_data.keys()) == len(variables)
def test_valid_and_invalid_orders(): GIVEN("a market handler two valid orders and two invalid orders") market_handler = ExternalAPIMarketHandler(mediator=MockMediator(), environment="Dev", headers={}, market_id=123456) orders = [ { "id": 9999999, "size": 100, "ex_price": 2.0 }, { "id": 8888888, "type": "SELL", "size": 6.18, "ex_price": 75.0 }, { "id": 7777777, "type": "BUY", "size": 5, "ex_price": 12.6 }, { "id": 7777777, "type": "BUY", "size": 5, "ex_price": "THE BEST YOU HAVE" }, ] valid_orders = market_handler._validate_orders(orders=orders) THEN("the valid orders are returned") assert valid_orders == orders[1:3]
def test_handler(): GIVEN("a directory, an historical external api file and a handler") directory = "./data/29220705" file_name = "1.157190397.txt" file = HistoricalExternalAPIFileHander(directory=directory, file=file_name) WHEN("we get the file as a list") file_data = file.get_file_as_list() THEN("the data is a list") assert isinstance(file_data, list) THEN("the file has a record for every 5 seconds in the" + "4 minutes 27 seconds leading up to 33 seconds before the race") assert len(file_data) == round_down(((5 * 60) - 33) / 5) for record in file_data: THEN("each record in the file data has a process time") assert isinstance(record.get("process_time"), str) THEN("none of the records have marketInfo") assert record.get("marketInfo") is None WHEN("we get the market start time") market_start_time = file.get_market_start_time() THEN("the market_start_time is a string") assert isinstance(market_start_time, str) THEN("the market start time can be converted to an epoch") epoch = DateTime(market_start_time).get_epoch() assert epoch > 0
def test_nan(): GIVEN("a value that is not a number") nan = not_a_number() WHEN("we check if the value is not a number") true = is_not_a_number(nan) THEN("it is") assert true
def test_schedule_handler(): GIVEN("a schedule handler connected to the dev environment") dev_schedule_handler = ExternalAPIScheduleHandler(environment="Dev") WHEN("we get the schedule for market which start in the next 5 minutes") schedule = dev_schedule_handler.get_schedule("7", DateTime.utc_5_minutes_from_now()) THEN("a list is returned") assert isinstance(schedule, list) THEN("each item in the list is a dict refering to a market") for market in schedule: assert isinstance(market, dict) THEN("each market has an id which is a string") market_id = market.get("marketId") assert isinstance(market_id, str) THEN("each market has a name") assert isinstance(market.get("marketName"), str) THEN("each market is associated with an event which is stored as a dict") event = market.get("event") assert isinstance(event, dict) THEN("the event has an id which is a string") assert isinstance(event.get("id"), str) THEN("the event has a name which is a string") assert isinstance(event.get("name"), str) THEN("the event has a country code which is a string") assert isinstance(event.get("countryCode"), str)
def test_get_newline(): GIVEN("a newline") newline_str = "\n" WHEN("we get a newline") newline = get_newline() THEN("they are the same") assert newline == newline_str
def test_number_str(): GIVEN("a string") a_str = "this is a string and not a number" WHEN("we test if it is a number") true = is_a_number(a_str) THEN("it is not") assert not true
def test_item_adapter_interface(): GIVEN("the external api market interface") with raises(TypeError): WHEN( "a class inherits the interface but does not implement the appropriate method" ) class DoesNotImplement(ItemAdapterInterface): pass THEN("an error is thrown on instantiation") DoesNotImplement() WHEN( "a class inherits the interface and implements the appropriate method") class Implements(ItemAdapterInterface): def get_adapted_data(self): pass try: THEN("the class can be instantiated without error") Implements() except TypeError: fail("Unexpected TypeError")
def test_market_data_external_api_interface(): GIVEN("the external api market interface") with raises(TypeError): WHEN( "a class inherits the interface but does not implement the appropriate method" ) class DoesNotImplement(MarketDataRecordInterface): pass THEN("an error is thrown on instantiation") DoesNotImplement() WHEN( "a class inherits the interface and implements the appropriate method") class Implements(MarketDataRecordInterface): def convert(self): pass try: THEN("the class can be instantiated without error") Implements() except TypeError: fail("Unexpected TypeError")
def test_add_mixed_processed_orders(): GIVEN("a handler and a set of processed orders (2 valid, 1 invalid)") mediator = MockMediator() handler = OrdersHandler(mediator=mediator, bank=100000000000) processed_orders = [ { "id": 1234, "probability": 0.2, "type": "BUY", "ex_price": 9.1, "returns_price": 8.65, "min_size": 5, "size": 50000, "risk_percentage": 0.05, }, { "id": 5678, "probability": 0.26, "type": "SELL", "ex_price": 5, "returns_price": 4.75, "min_size": 5, "size": 10000, "risk_percentage": 0.01, }, {}, ] WHEN("we add the orders to the handler") handler.prevent_reorder(orders=processed_orders) existing_orders = handler.get_orders() THEN("the correct number of orders have been added to the handler") assert len(existing_orders) == 2 THEN("the correct order data has been added to the handler") assert existing_orders == processed_orders[0:2]
def test_number_nan(): GIVEN("a NaN value") nan = not_a_number() WHEN("we test if it is a number") true = is_a_number(nan) THEN("it is not") assert not true
def test_no_items(): GIVEN("a transform handler") handler = TransformHandler() WHEN("we call process with no data") transformed_data = handler.process() THEN("an empty dictionary is returned") assert not transformed_data
def test_get_account_status(): GIVEN("a schedule handler connected to the dev environment") schedule_handler = ExternalAPIScheduleHandler(environment="Dev") WHEN("we get the account status") account_status = schedule_handler.get_account_status() THEN("a dictionary is returned") assert isinstance(account_status, dict) THEN("the returned dict contains a bank variable which is a number greater than 0") bank = account_status.get("availableToBetBalance") assert isinstance(bank, float) assert bank > 0 THEN( "the returned dict contains a discount rate to be applied" + " which is a float greater than or equal to 0" ) discount_rate = account_status.get("discountRate") / 100 assert isinstance(discount_rate, float) assert discount_rate >= 0 THEN( "the returned dict contains a points value which is an int greater than or equal to 0" ) points = account_status.get("pointsBalance") assert isinstance(points, int) assert points >= 0