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_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_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
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_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_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_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_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_new(): GIVEN("a data container") data_container = DataContainer() WHEN("we call new") new_container = data_container.new() THEN("a data container is returned") assert type(new_container) is type(data_container) THEN("the new data container is a different instance") assert new_container is not data_container
def test_market_data_container_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(DataContainerInterface): pass THEN("an error is thrown on instantiation") DoesNotImplement() WHEN( "a class inherits the interface and implements the appropriate method") class Implements(DataContainerInterface): def new(self): pass def add_rows(self): pass def get_row_count(self): pass def get_column_count(self): pass def get_column(self): pass def get_last_column_entry(self): pass def has_column(self): pass def get_column_group_values(self): pass def get_index(self): pass def set_index(self): pass def set_column_group_name(self): pass try: THEN("the class can be instantiated without error") Implements() except TypeError: fail("Unexpected TypeError")
def test_make_copy(): GIVEN("a list with random contents") random_list = [45, 21, 333, 564, 75, 66, 459, 4, 78, 0] WHEN("we make a copy") different_l = make_copy(random_list) THEN("the lists are equal") assert lists_are_equal(random_list, different_l) WHEN("we remove the last item from the list's copy") last_item = different_l.pop() THEN("the lists are no longer equal") assert not lists_are_equal(random_list, different_l) assert last_item == random_list[-1]
def test_removed(required_variables): GIVEN("a dictionary representing a removed runner") item_data = __get_removed() required_variables.return_value = all_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 defaults applied") assert adapted_item_data.get("id") == __get_id(item_data) __test_ex_defaults(adapted_item_data=adapted_item_data) __test_sp_defaults(adapted_item_data=adapted_item_data, item_data=item_data) THEN("the object has a removal_date") assert adapted_item_data.get("removal_date") > 0
def test_system_single(mock_post_instructions, mock_call_exchange): GIVEN("a market handler and the directory and file name of a test file") directory = "./data/29184567" market_id = 1.156230797 file_name = f"{market_id}.txt" file = HistoricalExternalAPIFileHander(directory=directory, file=file_name) file_data = file.get_file_as_list() market_start_time = file.get_market_start_time() WHEN("we run the market handler for each record of the file") external_api = ExternalAPIMarketHandler(environment="Dev", headers={}, market_id=market_id) handler = MarketHandler( market_id=market_id, external_api=external_api, market_start_time=market_start_time, ) external_api.set_mediator(mediator=handler) mock_post_instructions.side_effect = __mark_orders_successful orders = [] fix_probability_ids = [] for record in file_data: mock_call_exchange.return_value = [record] with freeze_time(record.get("process_time"), tz_offset=11): handler.run() fix_probability_ids = handler.data._get_fixed_probability_ids() orders = handler.get_orders() if fix_probability_ids or orders: THEN( "the data handler will not provide data to the models for fixed prob items" ) ids_for_models = handler.data._get_ids_for_model_data() for probability_id in fix_probability_ids: assert probability_id not in ids_for_models THEN( "the data handler has fixed the probability of the correct item" ) for order in orders: assert order.get("id") in fix_probability_ids THEN("the fixed probabilities and orders have the same length") assert len(fix_probability_ids) == len(orders) THEN("an order has been made") assert orders != [] THEN("the id of the order is in the fix probability ids") for order in orders: assert order.get("id") in fix_probability_ids assert len(fix_probability_ids) == len(orders)
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_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_make_directory(): GIVEN("a path") path = "./test_make_directories" WHEN("we check if the path exists") exists = path_exists(path=path) THEN("it does not") assert exists is False WHEN("we make the directory and check if it now exists") returned_path = make_directory_if_required(path=path) exists = path_exists(path=path) THEN("it does") assert exists is True assert returned_path == path remove_directory(path)
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_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_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_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_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_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_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_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_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_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_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