From 792bf93d9556ed036a7c35c64e3e988e0c65a89f Mon Sep 17 00:00:00 2001 From: Karolina Cynk Date: Tue, 9 May 2023 12:17:00 +0200 Subject: [PATCH] Added HAPI identifier type (#114) Added HAPI identifier type Added parser tests with ISIN --- .../bloomberg_beap_hapi_data_provider.py | 5 +- .../bloomberg_beap_hapi_parser.py | 33 ++++- .../bloomberg_beap_hapi_universe_provider.py | 41 +++++- .../test_bloomberg_beap_hapi_data_provider.py | 4 +- .../bloomberg_beap_hapi/test_parser.py | 134 +++++++++++++++--- 5 files changed, 184 insertions(+), 33 deletions(-) diff --git a/qf_lib/data_providers/bloomberg_beap_hapi/bloomberg_beap_hapi_data_provider.py b/qf_lib/data_providers/bloomberg_beap_hapi/bloomberg_beap_hapi_data_provider.py index 9ee996c1..a45abd45 100644 --- a/qf_lib/data_providers/bloomberg_beap_hapi/bloomberg_beap_hapi_data_provider.py +++ b/qf_lib/data_providers/bloomberg_beap_hapi/bloomberg_beap_hapi_data_provider.py @@ -297,7 +297,7 @@ def _get_futures_chain_dict(self, tickers: Union[BloombergFutureTicker, Sequence self._assert_is_connected() tickers, got_single_ticker = convert_to_list(tickers, BloombergFutureTicker) - expiration_date_fields, _ = convert_to_list(expiration_date_fields, ExpirationDateField) + expiration_date_fields, _ = convert_to_list(expiration_date_fields, str) active_ticker_string_to_future_ticker = { future_ticker.get_active_ticker(): future_ticker for future_ticker in tickers @@ -387,10 +387,9 @@ def get_current_values(self, tickers: Union[BloombergTicker, Sequence[BloombergT self.logger.info(f'universe_id: {universe_id} fields_list_id: {fields_list_id} request_id: {request_id}') out_path = self._download_response(request_id) - data_frame = self.parser.get_current_values(out_path, field_to_type) + data_frame = self.parser.get_current_values(out_path, field_to_type, tickers_str_to_obj) # to keep the order of tickers and fields we reindex the data frame - data_frame.index = [tickers_str_to_obj.get(x, BloombergTicker.from_string(x)) for x in data_frame.index] data_frame = data_frame.reindex(index=tickers, columns=fields) # squeeze unused dimensions diff --git a/qf_lib/data_providers/bloomberg_beap_hapi/bloomberg_beap_hapi_parser.py b/qf_lib/data_providers/bloomberg_beap_hapi/bloomberg_beap_hapi_parser.py index 6774869c..e9927cda 100644 --- a/qf_lib/data_providers/bloomberg_beap_hapi/bloomberg_beap_hapi_parser.py +++ b/qf_lib/data_providers/bloomberg_beap_hapi/bloomberg_beap_hapi_parser.py @@ -14,7 +14,7 @@ import gzip import re from io import StringIO -from typing import Tuple, List, Dict +from typing import Tuple, List, Dict, Optional from qf_lib.common.tickers.tickers import BloombergTicker from qf_lib.common.utils.logging.qf_parent_logger import qf_logger @@ -54,7 +54,8 @@ def __init__(self): self.logger = qf_logger.getChild(self.__class__.__name__) self.type_converter = BloombergDataLicenseTypeConverter() - def get_current_values(self, filepath: str, field_to_type: Dict[str, str]) -> QFDataFrame: + def get_current_values(self, filepath: str, field_to_type: Dict[str, str], + tickers_mapping: Optional[Dict[str, BloombergTicker]] = None) -> QFDataFrame: """ Method to parse hapi response and extract dates (e.g. FUT_NOTICE_FIRST, LAST_TRADEABLE_DT) for tickers @@ -64,19 +65,28 @@ def get_current_values(self, filepath: str, field_to_type: Dict[str, str]) -> QF The full filepath with downloaded response field_to_type: Dict[str, str] dictionary mapping requested, correct fields into their corresponding types + tickers_mapping: Optional[Dict[str, BloombergTicker]] + dictionary mapping string representations of tickers onto corresponding ticker objects Returns ------- QFDataFrame QFDataFrame with current values """ + tickers_mapping = tickers_mapping or {} + tickers_mapping = { + self._strip_identifier_name(ticker_str): ticker for ticker_str, ticker in tickers_mapping.items() + } column_names = ["Ticker", "Error code", "Num flds"] field_to_type = {**field_to_type, "Ticker": "String"} fields, content = self._get_fields_and_data_content(filepath, field_to_type, column_names, header_row=True) - return content.set_index("Ticker")[fields] + data_frame = content.set_index("Ticker")[fields] + data_frame.index = data_frame.index.map(lambda x: tickers_mapping.get(x, BloombergTicker.from_string(x))) + return data_frame - def get_history(self, filepath: str, field_to_type: Dict[str, str], tickers_mapping: Dict[str, BloombergTicker]) \ + def get_history(self, filepath: str, field_to_type: Dict[str, str], + tickers_mapping: Optional[Dict[str, BloombergTicker]] = None) \ -> QFDataArray: """ Method to parse hapi response and get history data @@ -87,7 +97,7 @@ def get_history(self, filepath: str, field_to_type: Dict[str, str], tickers_mapp The full filepath with downloaded response field_to_type: Dict[str, str] dictionary mapping requested, correct fields into their corresponding types - tickers_mapping: Dict[str, BloombergTicker] + tickers_mapping: Optional[Dict[str, BloombergTicker]] dictionary mapping string representations of tickers onto corresponding ticker objects Returns @@ -95,13 +105,17 @@ def get_history(self, filepath: str, field_to_type: Dict[str, str], tickers_mapp QFDataArray QFDataArray with history data """ + tickers_mapping = tickers_mapping or {} + tickers_mapping = { + self._strip_identifier_name(ticker_str): ticker for ticker_str, ticker in tickers_mapping.items() + } column_names = ["Ticker", "Error code", "Num flds", "Pricing Source", "Dates"] field_to_type = {**field_to_type, "Ticker": "String", "Error code": "String", "Num flds": "String", "Pricing Source": "String", "Dates": "Date"} fields, content = self._get_fields_and_data_content(filepath, field_to_type, column_names) tickers_dict = { - tickers_mapping[ticker]: df.set_index("Dates")[fields].dropna(how="all") + tickers_mapping.get(ticker, BloombergTicker.from_string(ticker)): df.set_index("Dates")[fields].dropna(how="all") for ticker, df in content.groupby(by="Ticker") } @@ -154,3 +168,10 @@ def _read_csv(content: str, column_names: List[str], delimiter: str = "|", heade records = [line for line in records if len(line) == len(column_names)] df = QFDataFrame.from_records(records, columns=column_names) return df.replace(r'^\s+$', np.nan, regex=True) + + def _strip_identifier_name(self, identifier: str) -> str: + """ + In case if the identifier contains identifiertype in its name (e.g. /bbgid/BBG000BDTBL9), remove the identifier + type and leave just the identifier name (in the given example - BBG000BDTBL9). + """ + return identifier.split("/")[-1] diff --git a/qf_lib/data_providers/bloomberg_beap_hapi/bloomberg_beap_hapi_universe_provider.py b/qf_lib/data_providers/bloomberg_beap_hapi/bloomberg_beap_hapi_universe_provider.py index f1115592..3306b33a 100644 --- a/qf_lib/data_providers/bloomberg_beap_hapi/bloomberg_beap_hapi_universe_provider.py +++ b/qf_lib/data_providers/bloomberg_beap_hapi/bloomberg_beap_hapi_universe_provider.py @@ -64,8 +64,13 @@ def get_universe_url(self, universe_id: str, tickers: Union[str, Sequence[str]], URL address of created hapi universe """ tickers, got_single_field = convert_to_list(tickers, str) - contains = [{'@type': 'Identifier', 'identifierType': 'TICKER', 'identifierValue': ticker} for ticker in - tickers] + tickers_and_types = [self._get_indentifier_and_type(ticker) for ticker in tickers] + contains = [{'@type': 'Identifier', 'identifierType': identifier_type, 'identifierValue': identifier} + for identifier_type, identifier in tickers_and_types if identifier] + if len(contains) == 0: + raise ValueError("No valid identifiers (tickers) were provided. Please refer to the logs and adjust your " + "data request accordingly.") + if fields_overrides: # noinspection PyTypeChecker contains[0]['fieldOverrides'] = [{ @@ -102,3 +107,35 @@ def get_universe_url(self, universe_id: str, tickers: Union[str, Sequence[str]], self.logger.info('Universe successfully created at %s', universe_url) return universe_url + + def _get_indentifier_and_type(self, ticker) -> Tuple[Optional[str], Optional[str]]: + blp_hapi_compatibility_mapping = { + "ticker": "TICKER", + "cusip": "CUSIP", + "buid": "BB_UNIQUE", + "bbgid": "BB_GLOBAL", + "isin": "ISIN", + "wpk": "WPK", + "sedol1": "SEDOL", + "common": "COMMON_NUMBER", + "cins": "CINS", + "cats": "CATS" + } + + ticker = f"/ticker/{ticker}" if ticker.count("/") == 0 else ticker + if ticker.count("/") != 2: + self.logger.error(f"Detected incorrect identifier: {ticker}. It will be removed from the data request.\n" + f"In order to provide an identifier, which is not a ticker, please use " + f"'/id_type/identifier' format, with id_type being one of the following: " + f"{blp_hapi_compatibility_mapping.values()}") + return None, None + + id_type, id = ticker.lstrip("/").split("/") + try: + return blp_hapi_compatibility_mapping[id_type.lower()], id + except KeyError: + self.logger.error( + f"Detected incorrect identifier type: {id_type.lower()}. The identifier will be removed from the " + f"data request.\n" + f"List of valid identifier types: {blp_hapi_compatibility_mapping.values()}") + return None, None diff --git a/qf_lib/tests/unit_tests/data_providers/bloomberg_beap_hapi/test_bloomberg_beap_hapi_data_provider.py b/qf_lib/tests/unit_tests/data_providers/bloomberg_beap_hapi/test_bloomberg_beap_hapi_data_provider.py index d234ce22..4f94f845 100644 --- a/qf_lib/tests/unit_tests/data_providers/bloomberg_beap_hapi/test_bloomberg_beap_hapi_data_provider.py +++ b/qf_lib/tests/unit_tests/data_providers/bloomberg_beap_hapi/test_bloomberg_beap_hapi_data_provider.py @@ -33,14 +33,14 @@ def test_get_tickers_universe__invalid_date(self): def test_get_tickers_universe__valid_ticker(self): self.data_provider.parser.get_current_values.return_value = QFDataFrame.from_records( - [("SPX Index", ["Member1", "Member2"]), ], columns=["Ticker", "INDX_MEMBERS"]).set_index("Ticker") + [(BloombergTicker("SPX Index"), ["Member1", "Member2"]), ], columns=["Ticker", "INDX_MEMBERS"]).set_index("Ticker") universe = self.data_provider.get_tickers_universe(BloombergTicker("SPX Index")) self.assertCountEqual(universe, [BloombergTicker("Member1 Equity"), BloombergTicker("Member2 Equity")]) def test_get_tickers_universe__invalid_ticker(self): self.data_provider.parser.get_current_values.return_value = QFDataFrame.from_records( - [("Invalid Index", []), ], columns=["Ticker", "INDX_MEMBERS"]).set_index("Ticker") + [(BloombergTicker("Invalid Index"), []), ], columns=["Ticker", "INDX_MEMBERS"]).set_index("Ticker") universe = self.data_provider.get_tickers_universe(BloombergTicker("Invalid Index")) self.assertCountEqual(universe, []) diff --git a/qf_lib/tests/unit_tests/data_providers/bloomberg_beap_hapi/test_parser.py b/qf_lib/tests/unit_tests/data_providers/bloomberg_beap_hapi/test_parser.py index b568ba0f..011e699b 100644 --- a/qf_lib/tests/unit_tests/data_providers/bloomberg_beap_hapi/test_parser.py +++ b/qf_lib/tests/unit_tests/data_providers/bloomberg_beap_hapi/test_parser.py @@ -69,6 +69,46 @@ def test_get_history_single_ticker_single_field_multiple_dates(self, mock): actual_data_array.dates.values] self.assertCountEqual(actual_datetime_strings, expected_datetime_strings) + @patch('qf_lib.data_providers.bloomberg_beap_hapi.bloomberg_beap_hapi_parser.gzip') + def test_get_history_single_isin_single_field_multiple_dates(self, mock): + mock.open.return_value = BytesIO(str.encode(dedent( + """ + START-OF-FILE + ... + START-OF-FIELDS + PX_LAST + END-OF-FIELDS + ... + START-OF-DATA + US78378X1072|0|1|EX|20210701|0.859| + US78378X1072|0|1|EX|20210702|0.8697| + US78378X1072|0|1|EX|20210706|0.874| + US78378X1072|0|1|EX|20210707|0.8763| + END-OF-DATA + ... + END-OF-FILE + """ + ))) + parser = BloombergBeapHapiParser() + actual_data_array = parser.get_history(Mock(), {"PX_LAST": "Price"}, + {"/isin/US78378X1072": BloombergTicker("/isin/US78378X1072")}) + + self.assertEqual(type(actual_data_array), QFDataArray) + self.assertEqual(actual_data_array.shape, (4, 1, 1)) + self.assertTrue(len(actual_data_array)) # not empty df + + expected_tickers_str_list = [BloombergTicker('/isin/US78378X1072')] + self.assertCountEqual(actual_data_array.tickers.values, expected_tickers_str_list) + + expected_fields_str_list = ['PX_LAST'] + self.assertCountEqual(actual_data_array.fields.values, expected_fields_str_list) + + # Compare string values of dates (to simplify the numpy.datetime64 comparison) + expected_datetime_strings = ['2021-07-01', '2021-07-02', '2021-07-06', '2021-07-07'] + actual_datetime_strings = [datetime_as_string(datetime64(dt), unit='D') for dt in + actual_data_array.dates.values] + self.assertCountEqual(actual_datetime_strings, expected_datetime_strings) + @patch('qf_lib.data_providers.bloomberg_beap_hapi.bloomberg_beap_hapi_parser.gzip') def test_get_history_single_ticker_single_field_empty_response(self, mock): mock.open.return_value = BytesIO(str.encode(dedent( @@ -154,9 +194,9 @@ def test_get_current_values_single_ticker_na_field(self, mock): self.assertEqual(df.shape, (1, 1)) - expected_active_tickers_str_list = ['STT US Equity'] + expected_active_tickers_str_list = BloombergTicker.from_string(['STT US Equity']) self.assertCountEqual(df.index.tolist(), expected_active_tickers_str_list) - self.assertEqual(df.loc['STT US Equity', 'RTG_SP_LT_FC_ISSUER_CREDIT'], None) + self.assertEqual(df.loc[BloombergTicker('STT US Equity'), 'RTG_SP_LT_FC_ISSUER_CREDIT'], None) @patch('qf_lib.data_providers.bloomberg_beap_hapi.bloomberg_beap_hapi_parser.gzip') def test_get_current_values_single_ticker_na_real_field(self, mock): @@ -180,9 +220,9 @@ def test_get_current_values_single_ticker_na_real_field(self, mock): self.assertEqual(df.shape, (1, 1)) - expected_active_tickers_str_list = ['SOME SW Equity'] + expected_active_tickers_str_list = BloombergTicker.from_string(['SOME SW Equity']) self.assertCountEqual(df.index.tolist(), expected_active_tickers_str_list) - self.assertTrue(isna(df.loc['SOME SW Equity', 'VOLATILITY_90D'])) + self.assertTrue(isna(df.loc[BloombergTicker('SOME SW Equity'), 'VOLATILITY_90D'])) @patch('qf_lib.data_providers.bloomberg_beap_hapi.bloomberg_beap_hapi_parser.gzip') def test_get_history_multiple_tickers_multiple_fields_multiple_dates(self, mock): @@ -232,6 +272,54 @@ def test_get_history_multiple_tickers_multiple_fields_multiple_dates(self, mock) actual_data_array.dates.values] self.assertCountEqual(actual_datetime_strings, expected_datetime_strings) + @patch('qf_lib.data_providers.bloomberg_beap_hapi.bloomberg_beap_hapi_parser.gzip') + def test_get_history_multiple_tickers_and_isins_multiple_fields_multiple_dates(self, mock): + mock.open.return_value = BytesIO(str.encode(dedent( + """ + START-OF-FILE + ... + START-OF-FIELDS + PX_OPEN + PX_HIGH + PX_LOW + PX_LAST + END-OF-FIELDS + ... + START-OF-DATA + US78378X1072|0|5|EX| | | | | | + CTA Comdty|0|5|EX|20210701|0.8505|0.8685|0.8492|0.859| + CTA Comdty|0|5|EX|20210702|0.86|0.8715|0.8587|0.8697| + CTA Comdty|0|5|EX|20210706|0.876|0.8889|0.8608|0.874| + CTA Comdty|0|5|EX|20210707|0.874|0.8795|0.8657|0.8763| + CTA Comdty|0|5|EX|20210708|0.8757|0.8763|0.863|0.8688| + END-OF-DATA + ... + END-OF-FILE + """ + ))) + parser = BloombergBeapHapiParser() + actual_data_array = parser.get_history(Mock(), {'PX_OPEN': "Price", 'PX_HIGH': "Price", 'PX_LOW': "Price", + 'PX_LAST': "Price"}, + {'/isin/US78378X1072': BloombergTicker("/isin/US78378X1072"), + 'CTA Comdty': BloombergTicker('CTA Comdty')}) + + self.assertEqual(type(actual_data_array), QFDataArray) + self.assertEqual(actual_data_array.shape, (5, 2, 4)) + self.assertTrue(len(actual_data_array)) + self.assertEqual(actual_data_array.dtype, float64) + + expected_tickers_str_list = ['/isin/US78378X1072', 'CTA Comdty'] + self.assertCountEqual(actual_data_array.tickers.values, BloombergTicker.from_string(expected_tickers_str_list)) + + expected_fields_str_list = ['PX_OPEN', 'PX_HIGH', 'PX_LOW', 'PX_LAST'] + self.assertCountEqual(actual_data_array.fields.values, expected_fields_str_list) + + # Compare string values of dates (to simplify the numpy.datetime64 comparison) + expected_datetime_strings = ['2021-07-01', '2021-07-02', '2021-07-06', '2021-07-07', '2021-07-08'] + actual_datetime_strings = [datetime_as_string(datetime64(dt), unit='D') for dt in + actual_data_array.dates.values] + self.assertCountEqual(actual_datetime_strings, expected_datetime_strings) + @patch('qf_lib.data_providers.bloomberg_beap_hapi.bloomberg_beap_hapi_parser.gzip') def test_get_history_single_ticker_multiple_fields_multiple_dates(self, mock): mock.open.return_value = BytesIO(str.encode(dedent( @@ -303,11 +391,11 @@ def test_get_chain_single_ticker_single_field_multiple_tickers(self, mock): self.assertEqual(type(df), QFDataFrame) self.assertEqual(df.shape, (1, 1)) - expected_active_tickers_str_list = ['RTYA Index'] + expected_active_tickers_str_list = BloombergTicker.from_string(['RTYA Index']) self.assertCountEqual(df.index.tolist(), expected_active_tickers_str_list) expected_tickers_str_list = ['RTYU17 Index', 'RTYZ17 Index', 'RTYH18 Index', 'RTYM18 Index', 'RTYU18 Index'] - self.assertCountEqual(df.loc['RTYA Index', 'FUT_CHAIN'], expected_tickers_str_list) + self.assertCountEqual(df.loc[BloombergTicker('RTYA Index'), 'FUT_CHAIN'], expected_tickers_str_list) @patch('qf_lib.data_providers.bloomberg_beap_hapi.bloomberg_beap_hapi_parser.gzip') def test_get_chain_multiple_tickers_single_field_multiple_tickers(self, mock): @@ -334,14 +422,14 @@ def test_get_chain_multiple_tickers_single_field_multiple_tickers(self, mock): self.assertEqual(type(df), QFDataFrame) self.assertEqual(df.shape, (2, 1)) - expected_active_tickers_str_list = ['CTA Index', 'RTYA Index'] + expected_active_tickers_str_list = BloombergTicker.from_string(['CTA Index', 'RTYA Index']) self.assertCountEqual(df.index.tolist(), expected_active_tickers_str_list) expected_tickers_str_list = ['RTYU17 Index', 'RTYZ17 Index', 'RTYH18 Index', 'RTYM18 Index', 'RTYU18 Index'] - self.assertCountEqual(df.loc['RTYA Index', 'FUT_CHAIN'], expected_tickers_str_list) + self.assertCountEqual(df.loc[BloombergTicker('RTYA Index'), 'FUT_CHAIN'], expected_tickers_str_list) expected_tickers_str_list = ['CTU17 Index', 'CTZ17 Index'] - self.assertCountEqual(df.loc['CTA Index', 'FUT_CHAIN'], expected_tickers_str_list) + self.assertCountEqual(df.loc[BloombergTicker('CTA Index'), 'FUT_CHAIN'], expected_tickers_str_list) @patch('qf_lib.data_providers.bloomberg_beap_hapi.bloomberg_beap_hapi_parser.gzip') def test_get_chain_multiple_tickers_single_field__correct_and_incorrect_ticker(self, mock): @@ -368,12 +456,12 @@ def test_get_chain_multiple_tickers_single_field__correct_and_incorrect_ticker(s self.assertEqual(type(df), QFDataFrame) self.assertEqual(df.shape, (2, 1)) - expected_active_tickers_str_list = ['RTASYA Index', 'RTYA Index'] + expected_active_tickers_str_list = BloombergTicker.from_string(['RTASYA Index', 'RTYA Index']) self.assertCountEqual(df.index.tolist(), expected_active_tickers_str_list) expected_tickers_str_list = ['RTYU17 Index', 'RTYZ17 Index', 'RTYH18 Index', 'RTYM18 Index', 'RTYU18 Index'] - self.assertCountEqual(df.loc['RTYA Index', 'FUT_CHAIN'], expected_tickers_str_list) - self.assertCountEqual(df.loc['RTASYA Index', 'FUT_CHAIN'], []) + self.assertCountEqual(df.loc[BloombergTicker('RTYA Index'), 'FUT_CHAIN'], expected_tickers_str_list) + self.assertCountEqual(df.loc[BloombergTicker('RTASYA Index'), 'FUT_CHAIN'], []) @patch('qf_lib.data_providers.bloomberg_beap_hapi.bloomberg_beap_hapi_parser.gzip') def test_get_chain_single_ticker_single_field__incorrect_ticker(self, mock): @@ -399,9 +487,9 @@ def test_get_chain_single_ticker_single_field__incorrect_ticker(self, mock): self.assertEqual(type(df), QFDataFrame) self.assertEqual(df.shape, (1, 1)) - expected_active_tickers_str_list = ['RTASYA Index'] + expected_active_tickers_str_list = BloombergTicker.from_string(['RTASYA Index']) self.assertCountEqual(df.index.tolist(), expected_active_tickers_str_list) - self.assertCountEqual(df.loc['RTASYA Index', 'FUT_CHAIN'], []) + self.assertCountEqual(df.loc[BloombergTicker('RTASYA Index'), 'FUT_CHAIN'], []) @patch('qf_lib.data_providers.bloomberg_beap_hapi.bloomberg_beap_hapi_parser.gzip') def test_get_dates_multiple_tickers_single_field(self, mock): @@ -432,7 +520,8 @@ def test_get_dates_multiple_tickers_single_field(self, mock): self.assertEqual(df.shape, (5, 1)) self.assertTrue(len(df)) - expected_tickers_str_list = ['RTYU17 Index', 'RTYZ17 Index', 'RTYH18 Index', 'RTYM18 Index', 'RTYU18 Index'] + expected_tickers_str_list = BloombergTicker.from_string( + ['RTYU17 Index', 'RTYZ17 Index', 'RTYH18 Index', 'RTYM18 Index', 'RTYU18 Index']) self.assertCountEqual(df.index.tolist(), expected_tickers_str_list) expected_field = ['FUT_NOTICE_FIRST'] @@ -473,7 +562,8 @@ def test_get_dates_multiple_tickers_multiple_fields(self, mock): self.assertEqual(df.shape, (5, 2)) self.assertTrue(len(df)) - expected_tickers_str_list = ['CTH4 Comdty', 'CTK4 Comdty', 'RTYU1 Index', 'RTYZ1 Index', 'RTYU2 Index'] + expected_tickers_str_list = BloombergTicker.from_string( + ['CTH4 Comdty', 'CTK4 Comdty', 'RTYU1 Index', 'RTYZ1 Index', 'RTYU2 Index']) self.assertCountEqual(df.index.tolist(), expected_tickers_str_list) expected_fields_list = ['FUT_NOTICE_FIRST', 'LAST_TRADEABLE_DT'] @@ -529,8 +619,10 @@ def test_get_current_values__multiple_tickers_multiple_fields(self, mock): """ ))) expected_df = QFDataFrame.from_dict({ - 'NAME': {'SPY US Equity': 'SPDR S&P 500 ETF TRUST', 'MSFT US Equity': 'MICROSOFT CORP'}, - 'PX_LAST': {'SPY US Equity': 67.83, 'MSFT US Equity': 39.67} + 'NAME': {BloombergTicker('SPY US Equity'): 'SPDR S&P 500 ETF TRUST', + BloombergTicker('MSFT US Equity'): 'MICROSOFT CORP'}, + 'PX_LAST': {BloombergTicker('SPY US Equity'): 67.83, + BloombergTicker('MSFT US Equity'): 39.67} }) parser = BloombergBeapHapiParser() df = parser.get_current_values(Mock(), {"NAME": "String", "PX_LAST": "Price"}) @@ -555,8 +647,10 @@ def test_get_current_values__multiple_tickers_multiple_fields__incorrect_ticker( """ ))) expected_df = QFDataFrame.from_dict({ - 'NAME': {'SPY US Equity': 'SPDR S&P 500 ETF TRUST', 'Incorrect Equity': None}, - 'PX_LAST': {'SPY US Equity': 68.32, 'Incorrect Equity': nan} + 'NAME': {BloombergTicker('SPY US Equity'): 'SPDR S&P 500 ETF TRUST', + BloombergTicker('Incorrect Equity'): None}, + 'PX_LAST': {BloombergTicker('SPY US Equity'): 68.32, + BloombergTicker('Incorrect Equity'): nan} }) expected_df['PX_LAST'] = expected_df['PX_LAST'].astype(float64) parser = BloombergBeapHapiParser()