From 73f043ef6b0f559ea18560e215efe1ba853cef64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Bartolom=C3=A9=20del=20Canto?= Date: Tue, 24 Sep 2019 13:26:31 +0200 Subject: [PATCH] closed #36 - indices functions for data retrieval added to investpy - tests/ updated in order to improve codecov by covering indices retrieval functions - tests/test_investpy.py functions splitted in order to be more clear - coversion to dict and json objects added to Data class - docs/ generated --- docs/_build/doctrees/environment.pickle | Bin 33806 -> 33806 bytes investpy/Data.py | 22 + investpy/__init__.py | 508 +++++++++++++++++++++++- investpy/etfs.py | 2 +- investpy/funds.py | 11 - tests/test_investpy.py | 250 +++++++++--- tests/test_investpy_errors.py | 361 ++++++++++++++++- 7 files changed, 1073 insertions(+), 81 deletions(-) diff --git a/docs/_build/doctrees/environment.pickle b/docs/_build/doctrees/environment.pickle index 48297800bd6b8b5962271b559eb9e6c0ca2d9fd0..1b07b27d60f70e56a94e78e61542a5040ff0ef86 100644 GIT binary patch delta 2139 zcmY*aZA?>F80M6(>VyfXS*TF37lDF&76>>|LFWjwK+8u#J}hvNduVSFGhk^8;D!158V=;^WV5oKR6u#6YgKCRO($%|AR9+7;Kh_}Z|a=-X2w)IQiK8Ia$ ziXNOo9M-EhsP{*QC-(a64hLV7Vp@AjGv2O=irTUDYVUYk)wUek7Ev2#%(NwQ(CkZHlPZZ^Tn;M4h~EqpcBjIz5H%jHoloU($|k5qY-#5p9U5H(Vjw z98n)7glJ<#T`av$EfIC8K@ZdVjl}j!rVWf4iNp+*8NI{`Co=j-GjiMVZFZl%z`ZXR z*acfN8o`#iB6^Bi;Bw}tq#X{en}2HrO|!KPf^ubA>g0>3VbP`;M%9igZ3{rGOs4;f=SK|g1}c7cA&fb9TXV8Gm` z3DF45d8%WKxlT=tF~?~QV;zh&GRBOi-Hb7lse>_QFg+X{gJ^-Kf>oql87Rmj@Mx<5 z?-gD|=_z_ZU{AHQ=+zT&x5NscY!*N&4S}Pi9Q3u7=$#w3mkLTrSqVXs1ah~a952u0 zLiwU%Lak2MnDU3DeSm672fU@l=-#_LOPVR_DMFJ z?-(bLwNt%qrqc;yWc0}N!P<821AI5|V<-Ev>j@7L4lF_SaXdb#Saxt=!NDR+4JsCydJWGDDi)UdXr2@t zSWK|UGJ=BzRu0z2unFLoqBIR{h0(zV9^5JVCuV6fm_ymsDSCT}`g@7Gvqb$Cr}nW` zOwr$$sGCdFttINOurl(-f5MWhyGztUSShmfCTUVlJT_@FB)biGma>H%a3?^wJ1(M9kOkcph_mkENHrGHhZ9k47&akhx^%FAcr`K@ z&O-cP*vL_ccSv5eDE#DDDD<$dYEL1e>?uQ>b?f0XPx2zW$C=i<9(AENk7E`b@Ur!= zS2+smIbUUNZX)zZ;DdCw^T#S u%J{x_h?aeKc)_Yvj>T)zSmIH!a~cQs930pQjYG52wSRRiu_)eyGvt4=ImI0S delta 2160 zcmY*aYitx%80~Cd%d1izjdtmaozix@^to-NYJrxAP19~4bj#MhmUc_$c6WBWyDgH6 zMFeEy0>y9BgwTNaix^FiQ4@`zNYa>4B4QNdlYmu$qJR(rCgAto=}yu==brP;+_~SJ zd+yAEeYyktbSK9QBe9a)<9s2bQkq4|;=@OgR$y91I( z=F%T}BDxc(PW6 zkMci5=_`07K)$6EuB<8MK81`=!`-4LNGK6ODxQF?6{V0?wF>?7!WXMWrKqGxK#~Y@ zho~Gb&EP^gU$#%Jj#cL>2UoSK)ko#`RPyBcJ^@@s5?Xs3))$NL`|1hYfC5X2a%D}L z0EhBLFjh`LW-Tpt42J7Ov?ue|8PB%BocbpCuUUkh^(Tc|rLf^o9m+(= z*>npW4(t_E)0HE_iRLEwV2cQ8wh6F1RX5^H$so5h!H2z~GSyNhAW2kK+DBA!y454V z^-2$>!wqMuM8({W?{cOpQIR`_RC2%5CBT$TZS+USWmsnCjVj-5*{uVoH3eREw816k zRcNah;fLOz+vt$j2s}VIPIXJEBZ{;_Zm!>h3IcFQOD#dRMSghe7U7klPdF?gY6xLGDeETNC8Y1i3Lm?n{u{ z66CG~xhX;PWNW`!Xn}Bl5#r z5HmccnGT2-U}f560JkR%nT+#Jc#@G#dJXWaCn=R85YpqnNBt}9#lMFn4>|n-{Eo6# zSmZSdt-P_F-UZO%jnmX(WMOX^;-t4wtHwg=Kmw|j0~W*#j{$ZJEJX$bnTVeZm^g~@ zF3FD;MV=fB`97Le;mb#qeI!_EUnM oP9PSo%BtabT?%C%6@9I7peN!$-)S6LmG&J=V+EVy-*rUzABefn>> investpy.get_index_recent_data(index='ibex 35', country='spain') + Open High Low Close Volume Currency + Date + 2019-08-26 12604.7 12646.3 12510.4 12621.3 4770000 EUR + 2019-08-27 12618.3 12723.3 12593.6 12683.8 8230000 EUR + 2019-08-28 12657.2 12697.2 12585.1 12642.5 7300000 EUR + 2019-08-29 12637.2 12806.6 12633.8 12806.6 5650000 EUR + 2019-08-30 12767.6 12905.9 12756.9 12821.6 6040000 EUR + + """ + + if not index: + raise ValueError("ERR#0047: index param is mandatory and should be a str.") + + if not isinstance(index, str): + raise ValueError("ERR#0047: index param is mandatory and should be a str.") + + if country is None: + raise ValueError("ERR#0039: country can not be None, it should be a str.") + + if country is not None and not isinstance(country, str): + raise ValueError("ERR#0025: specified country value not valid.") + + if not isinstance(as_json, bool): + raise ValueError("ERR#0002: as_json argument can just be True or False, bool type.") + + if order not in ['ascending', 'asc', 'descending', 'desc']: + raise ValueError("ERR#0003: order argument can just be ascending (asc) or descending (desc), str type.") + + if not isinstance(debug, bool): + raise ValueError("ERR#0033: debug argument can just be a boolean value, either True or False.") + + resource_package = __name__ + resource_path = '/'.join(('resources', 'indices', 'indices.csv')) + if pkg_resources.resource_exists(resource_package, resource_path): + indices = pd.read_csv(pkg_resources.resource_filename(resource_package, resource_path)) + else: + indices = ic.retrieve_indices() + + if indices is None: + raise IOError("ERR#0037: indices not found or unable to retrieve.") + + if unidecode.unidecode(country.lower()) not in get_index_countries(): + raise RuntimeError("ERR#0034: country " + country.lower() + " not found, check if it is correct.") + + indices = indices[indices['country'] == unidecode.unidecode(country.lower())] + + index = index.strip() + index = index.lower() + + if unidecode.unidecode(index) not in [unidecode.unidecode(value.lower()) for value in indices['name'].tolist()]: + raise RuntimeError("ERR#0045: index " + index + " not found, check if it is correct.") + + logging.basicConfig(level=logging.INFO) + logger = logging.getLogger(__name__) + + if debug is False: + logger.disabled = True + else: + logger.disabled = False + + logger.info('Searching introduced index on Investing.com') + + full_name = indices.loc[(indices['name'].str.lower() == index).idxmax(), 'full_name'] + id_ = indices.loc[(indices['name'].str.lower() == index).idxmax(), 'id'] + name = indices.loc[(indices['name'].str.lower() == index).idxmax(), 'name'] + + index_currency = indices.loc[(indices['name'].str.lower() == index).idxmax(), 'currency'] + + logger.info(str(index) + ' found on Investing.com') + + header = "Datos históricos " + full_name + + params = { + "curr_id": id_, + "smlID": str(randint(1000000, 99999999)), + "header": header, + "interval_sec": "Daily", + "sort_col": "date", + "sort_ord": "DESC", + "action": "historical_data" + } + + head = { + "User-Agent": user_agent.get_random(), + "X-Requested-With": "XMLHttpRequest", + "Accept": "text/html", + "Accept-Encoding": "gzip, deflate, br", + "Connection": "keep-alive", + } + + url = "https://es.investing.com/instruments/HistoricalDataAjax" + + logger.info('Request sent to Investing.com!') + + req = requests.post(url, headers=head, data=params) + + if req.status_code != 200: + raise ConnectionError("ERR#0015: error " + str(req.status_code) + ", try again later.") + + logger.info('Request to Investing.com data succeeded with code ' + str(req.status_code) + '!') + + root_ = fromstring(req.text) + path_ = root_.xpath(".//table[@id='curr_table']/tbody/tr") + result = list() + + if path_: + logger.info('Data parsing process starting...') + + for elements_ in path_: + info = [] + for nested_ in elements_.xpath(".//td"): + info.append(nested_.text_content()) + + if info[0] == 'No se encontraron resultados': + raise IndexError("ERR#0046: index information unavailable or not found.") + + index_date = datetime.datetime.strptime(info[0].replace('.', '-'), '%d-%m-%Y') + + index_close = float(info[1].replace('.', '').replace(',', '.')) + index_open = float(info[2].replace('.', '').replace(',', '.')) + index_high = float(info[3].replace('.', '').replace(',', '.')) + index_low = float(info[4].replace('.', '').replace(',', '.')) + + index_volume = 0 + + if info[5].__contains__('K'): + index_volume = int(float(info[5].replace('K', '').replace('.', '').replace(',', '.')) * 1000) + elif info[5].__contains__('M'): + index_volume = int(float(info[5].replace('M', '').replace('.', '').replace(',', '.')) * 1000000) + elif info[5].__contains__('B'): + index_volume = int(float(info[5].replace('B', '').replace('.', '').replace(',', '.')) * 1000000000) + + result.insert(len(result), Data(index_date, index_open, index_high, index_low, + index_close, index_volume, index_currency)) + + if order in ['ascending', 'asc']: + result = result[::-1] + elif order in ['descending', 'desc']: + result = result + + logger.info('Data parsing process finished...') + + if as_json is True: + json_ = {'name': name, + 'recent': + [value.index_as_json() for value in result] + } + + return json.dumps(json_, sort_keys=False) + elif as_json is False: + df = pd.DataFrame.from_records([value.index_to_dict() for value in result]) + df.set_index('Date', inplace=True) + + return df + + else: + raise RuntimeError("ERR#0004: data retrieval error while scraping.") + + +def get_index_historical_data(index, country, from_date, to_date, as_json=False, order='ascending', debug=False): + """ + This function retrieves historical data of the introduced `index` (from the specified country, note that both + index and country should match since if the introduced index is not listed in the indices of that country, the + function will raise an error). The retrieved historical data are the OHLC values plus the Volume and the Currency in + which those values are specified, from the introduced data range if valid. So on, the resulting data can it either be + stored in a :obj:`pandas.DataFrame` or in a :obj:`json` file. + + Args: + index (:obj:`str`): name of the index to retrieve recent historical data from. + country (:obj:`str`): name of the country from where the index is. + from_date (:obj:`str`): date as `str` formatted as `dd/mm/yyyy`, from where data is going to be retrieved. + to_date (:obj:`str`): date as `str` formatted as `dd/mm/yyyy`, until where data is going to be retrieved. + as_json (:obj:`bool`, optional): + optional argument to determine the format of the output data (:obj:`pandas.DataFrame` or :obj:`json`). + order (:obj:`str`, optional): + optional argument to define the order of the retrieved data (`ascending`, `asc` or `descending`, `desc`). + debug (:obj:`bool`, optional): + optional argument to either show or hide debug messages on log, `True` or `False`, respectively. + + Returns: + :obj:`pandas.DataFrame` or :obj:`json`: + The function returns either a :obj:`pandas.DataFrame` or a :obj:`json` file containing the retrieved + historical data from the specified index via argument. The dataset contains the open, high, low, close and + volume values for the selected index on market days, additionally the currency in which those values are + specified is returned. + + The returned data is case we use default arguments will look like:: + + Date || Open | High | Low | Close | Volume | Currency + -----||------------------------------------|---------- + xxxx || xxxx | xxxx | xxx | xxxxx | xxxxxx | xxxxxxxx + + but if we define `as_json=True`, then the output will be:: + + { + name: name, + historical: [ + { + date: dd/mm/yyyy, + open: x, + high: x, + low: x, + close: x, + volume: x, + currency: x + }, + ... + ] + } + + Raises: + ValueError: raised if there was an argument error. + IOError: raised if indices object/file was not found or unable to retrieve. + RuntimeError: raised if the introduced index does not match any of the indexed ones. + ConnectionError: raised if GET requests does not return 200 status code. + IndexError: raised if index information was unavailable or not found. + + Examples: + >>> investpy.get_index_historical_data(index='ibex 35', country='spain', from_date='01/01/2018', to_date='01/01/2019') + Open High Low Close Volume Currency + Date + 2018-01-02 15128.2 15136.7 14996.6 15096.8 10340000 EUR + 2018-01-03 15145.0 15186.9 15091.9 15106.9 12800000 EUR + 2018-01-04 15105.5 15368.7 15103.7 15368.7 17070000 EUR + 2018-01-05 15353.9 15407.5 15348.6 15398.9 11180000 EUR + 2018-01-08 15437.1 15448.7 15344.0 15373.3 12890000 EUR + + """ + + if not index: + raise ValueError("ERR#0047: index param is mandatory and should be a str.") + + if not isinstance(index, str): + raise ValueError("ERR#0047: index param is mandatory and should be a str.") + + if country is None: + raise ValueError("ERR#0039: country can not be None, it should be a str.") + + if country is not None and not isinstance(country, str): + raise ValueError("ERR#0025: specified country value not valid.") + + try: + datetime.datetime.strptime(from_date, '%d/%m/%Y') + except ValueError: + raise ValueError("ERR#0011: incorrect data format, it should be 'dd/mm/yyyy'.") + + try: + datetime.datetime.strptime(to_date, '%d/%m/%Y') + except ValueError: + raise ValueError("ERR#0011: incorrect data format, it should be 'dd/mm/yyyy'.") + + start_date = datetime.datetime.strptime(from_date, '%d/%m/%Y') + end_date = datetime.datetime.strptime(to_date, '%d/%m/%Y') + + if start_date >= end_date: + raise ValueError("ERR#0032: to_date should be greater than from_date, both formatted as 'dd/mm/yyyy'.") + + if not isinstance(as_json, bool): + raise ValueError("ERR#0002: as_json argument can just be True or False, bool type.") + + if order not in ['ascending', 'asc', 'descending', 'desc']: + raise ValueError("ERR#0003: order argument can just be ascending (asc) or descending (desc), str type.") + + if not isinstance(debug, bool): + raise ValueError("ERR#0033: debug argument can just be a boolean value, either True or False.") + + date_interval = { + 'intervals': [], + } + + flag = True + + while flag is True: + diff = end_date.year - start_date.year + + if diff > 20: + obj = { + 'start': start_date.strftime('%d/%m/%Y'), + 'end': start_date.replace(year=start_date.year + 20).strftime('%d/%m/%Y'), + } + + date_interval['intervals'].append(obj) + + start_date = start_date.replace(year=start_date.year + 20) + else: + obj = { + 'start': start_date.strftime('%d/%m/%Y'), + 'end': end_date.strftime('%d/%m/%Y'), + } + + date_interval['intervals'].append(obj) + + flag = False + + interval_limit = len(date_interval['intervals']) + interval_counter = 0 + + data_flag = False + + resource_package = __name__ + resource_path = '/'.join(('resources', 'indices', 'indices.csv')) + if pkg_resources.resource_exists(resource_package, resource_path): + indices = pd.read_csv(pkg_resources.resource_filename(resource_package, resource_path)) + else: + indices = ic.retrieve_indices() + + if indices is None: + raise IOError("ERR#0037: indices not found or unable to retrieve.") + + if unidecode.unidecode(country.lower()) not in get_index_countries(): + raise RuntimeError("ERR#0034: country " + country.lower() + " not found, check if it is correct.") + + indices = indices[indices['country'] == unidecode.unidecode(country.lower())] + + index = index.strip() + index = index.lower() + + if unidecode.unidecode(index) not in [unidecode.unidecode(value.lower()) for value in indices['name'].tolist()]: + raise RuntimeError("ERR#0045: index " + index + " not found, check if it is correct.") + + logging.basicConfig(level=logging.INFO) + logger = logging.getLogger(__name__) + + if debug is False: + logger.disabled = True + else: + logger.disabled = False + + logger.info('Searching introduced index on Investing.com') + + full_name = indices.loc[(indices['name'].str.lower() == index).idxmax(), 'full_name'] + id_ = indices.loc[(indices['name'].str.lower() == index).idxmax(), 'id'] + name = indices.loc[(indices['name'].str.lower() == index).idxmax(), 'name'] + + index_currency = indices.loc[(indices['name'].str.lower() == index).idxmax(), 'currency'] + + logger.info(str(index) + ' found on Investing.com') + + final = list() + + header = "Datos históricos " + full_name + + for index in range(len(date_interval['intervals'])): + interval_counter += 1 + + params = { + "curr_id": id_, + "smlID": str(randint(1000000, 99999999)), + "header": header, + "st_date": date_interval['intervals'][index]['start'], + "end_date": date_interval['intervals'][index]['end'], + "interval_sec": "Daily", + "sort_col": "date", + "sort_ord": "DESC", + "action": "historical_data" + } + + head = { + "User-Agent": user_agent.get_random(), + "X-Requested-With": "XMLHttpRequest", + "Accept": "text/html", + "Accept-Encoding": "gzip, deflate, br", + "Connection": "keep-alive", + } + + url = "https://es.investing.com/instruments/HistoricalDataAjax" + + logger.info('Request sent to Investing.com!') + + req = requests.post(url, headers=head, data=params) + + if req.status_code != 200: + raise ConnectionError("ERR#0015: error " + str(req.status_code) + ", try again later.") + + logger.info('Request to Investing.com data succeeded with code ' + str(req.status_code) + '!') + + if not req.text: + continue + + root_ = fromstring(req.text) + path_ = root_.xpath(".//table[@id='curr_table']/tbody/tr") + result = list() + + if path_: + logger.info('Data parsing process starting...') + + for elements_ in path_: + info = [] + for nested_ in elements_.xpath(".//td"): + info.append(nested_.text_content()) + + if info[0] == 'No se encontraron resultados': + if interval_counter < interval_limit: + data_flag = False + else: + raise IndexError("ERR#0046: index information unavailable or not found.") + else: + data_flag = True + + if data_flag is True: + index_date = datetime.datetime.strptime(info[0].replace('.', '-'), '%d-%m-%Y') + + index_close = float(info[1].replace('.', '').replace(',', '.')) + index_open = float(info[2].replace('.', '').replace(',', '.')) + index_high = float(info[3].replace('.', '').replace(',', '.')) + index_low = float(info[4].replace('.', '').replace(',', '.')) + + index_volume = 0 + + if info[5].__contains__('K'): + index_volume = int(float(info[5].replace('K', '').replace('.', '').replace(',', '.')) * 1000) + elif info[5].__contains__('M'): + index_volume = int(float(info[5].replace('M', '').replace('.', '').replace(',', '.')) * 1000000) + elif info[5].__contains__('B'): + index_volume = int(float(info[5].replace('B', '').replace('.', '').replace(',', '.')) * 1000000000) + + result.insert(len(result), Data(index_date, index_open, index_high, index_low, + index_close, index_volume, index_currency)) + if data_flag is True: + if order in ['ascending', 'asc']: + result = result[::-1] + elif order in ['descending', 'desc']: + result = result + + if as_json is True: + json_ = {'name': name, + 'historical': + [value.index_as_json() for value in result] + } + + final.append(json_) + elif as_json is False: + df = pd.DataFrame.from_records([value.index_to_dict() for value in result]) + df.set_index('Date', inplace=True) + + final.append(df) + + else: + raise RuntimeError("ERR#0004: data retrieval error while scraping.") + + logger.info('Data parsing process finished...') + + if as_json is True: + return json.dumps(final[0], sort_keys=False) + elif as_json is False: + return pd.concat(final) + + def search_indices(by, value): """ This function searches indices by the introduced value for the specified field. This means that this function @@ -2664,4 +3167,3 @@ def search_indices(by, value): search_result.reset_index(drop=True, inplace=True) return search_result - diff --git a/investpy/etfs.py b/investpy/etfs.py index e4de813b..5ba3f775 100644 --- a/investpy/etfs.py +++ b/investpy/etfs.py @@ -204,7 +204,7 @@ def etf_countries_as_list(): if pkg_resources.resource_exists(resource_package, resource_path): markets = pd.read_csv(pkg_resources.resource_filename(resource_package, resource_path)) else: - raise FileNotFoundError("ERR#0028: etf_countries file not found") + raise FileNotFoundError("ERR#0044: etf_countries file not found") return markets['country'].tolist() diff --git a/investpy/funds.py b/investpy/funds.py index d9344e9e..eb124544 100644 --- a/investpy/funds.py +++ b/investpy/funds.py @@ -57,10 +57,6 @@ def retrieve_funds(test_mode=False): results = list() - resource_package = __name__ - resource_path = '/'.join(('resources', 'funds', 'funds.csv')) - file = pkg_resources.resource_filename(resource_package, resource_path) - for country in countries['country'].tolist(): head = { "User-Agent": ua.get_random(), @@ -110,15 +106,8 @@ def retrieve_funds(test_mode=False): "currency": info['currency'] } - print(obj) - results.append(obj) - df = pd.DataFrame(results) - - if test_mode is False: - df.to_csv(file, index=False) - if test_mode is True: break diff --git a/tests/test_investpy.py b/tests/test_investpy.py index 07f9ce0b..fc044e6f 100644 --- a/tests/test_investpy.py +++ b/tests/test_investpy.py @@ -10,27 +10,38 @@ from investpy.equities import retrieve_equities, retrieve_equity_countries from investpy.funds import retrieve_funds, retrieve_fund_countries from investpy.etfs import retrieve_etfs +from investpy.indices import retrieve_indices, retrieve_index_countries def test_investpy(): """ - This function checks that main functions of investpy work properly. + This function checks that both the investpy's author and version are the correct ones. """ print(investpy.__author__, investpy.__version__) - for value in ['spain', None]: - investpy.get_equities(country=value) - investpy.get_equities_list(country=value) + +def test_investpy_equities(): + """ + This function checks that equity data retrieval functions listed in investpy work properly. + """ params = [ + { + 'country': 'spain', + }, { 'country': None, - 'columns': ['id', 'name'], - 'as_json': True }, + ] + + for param in params: + investpy.get_equities(country=param['country']) + investpy.get_equities_list(country=param['country']) + + params = [ { - 'country': 'spain', + 'country': None, 'columns': ['id', 'name'], 'as_json': True }, @@ -41,14 +52,19 @@ def test_investpy(): }, { 'country': 'spain', - 'columns': None, - 'as_json': False + 'columns': ['id', 'name'], + 'as_json': True }, { 'country': 'spain', 'columns': ['id', 'name'], 'as_json': False }, + { + 'country': 'spain', + 'columns': None, + 'as_json': False + }, ] for param in params: @@ -59,6 +75,11 @@ def test_investpy(): investpy.get_equity_countries() params = [ + { + 'as_json': True, + 'order': 'ascending', + 'debug': False + }, { 'as_json': False, 'order': 'ascending', @@ -69,11 +90,6 @@ def test_investpy(): 'order': 'descending', 'debug': False }, - { - 'as_json': True, - 'order': 'ascending', - 'debug': False - }, { 'as_json': False, 'order': 'descending', @@ -106,6 +122,12 @@ def test_investpy(): retrieve_equities(test_mode=True) retrieve_equity_countries(test_mode=True) + +def test_investpy_funds(): + """ + This function checks that fund data retrieval functions listed in investpy work properly. + """ + params = [ { 'country': 'spain', @@ -126,23 +148,23 @@ def test_investpy(): 'as_json': True }, { - 'country': 'spain', + 'country': None, 'columns': ['id', 'name'], - 'as_json': True + 'as_json': False }, { - 'country': None, + 'country': 'spain', 'columns': ['id', 'name'], - 'as_json': False + 'as_json': True }, { 'country': 'spain', - 'columns': None, + 'columns': ['id', 'name'], 'as_json': False }, { 'country': 'spain', - 'columns': ['id', 'name'], + 'columns': None, 'as_json': False }, ] @@ -152,25 +174,14 @@ def test_investpy(): columns=param['columns'], as_json=param['as_json']) + investpy.get_fund_countries() + params = [ { - 'fund': 'bbva multiactivo conservador pp', - 'country': 'spain', 'as_json': True, + 'order': 'ascending', + 'debug': False }, - { - 'fund': 'bbva multiactivo conservador pp', - 'country': 'spain', - 'as_json': False, - }, - ] - - for param in params: - investpy.get_fund_information(fund=param['fund'], - country=param['country'], - as_json=param['as_json']) - - params = [ { 'as_json': False, 'order': 'ascending', @@ -181,11 +192,6 @@ def test_investpy(): 'order': 'descending', 'debug': False }, - { - 'as_json': True, - 'order': 'ascending', - 'debug': False - }, { 'as_json': False, 'order': 'descending', @@ -208,29 +214,51 @@ def test_investpy(): order=param['order'], debug=param['debug']) - investpy.get_fund_countries() + params = [ + { + 'fund': 'bbva multiactivo conservador pp', + 'country': 'spain', + 'as_json': True, + }, + { + 'fund': 'bbva multiactivo conservador pp', + 'country': 'spain', + 'as_json': False, + }, + ] - investpy.get_funds() + for param in params: + investpy.get_fund_information(fund=param['fund'], + country=param['country'], + as_json=param['as_json']) investpy.search_funds(by='name', value='bbva') retrieve_funds(test_mode=True) retrieve_fund_countries(test_mode=True) - investpy.get_etf_countries() - for value in ['spain', None]: - investpy.get_etfs(country=value) - investpy.get_etfs_list(country=value) +def test_investpy_etfs(): + """ + This function checks that etf data retrieval functions listed in investpy work properly. + """ params = [ + { + 'country': 'spain', + }, { 'country': None, - 'columns': ['id', 'name'], - 'as_json': True }, + ] + + for param in params: + investpy.get_etfs(country=param['country']) + investpy.get_etfs_list(country=param['country']) + + params = [ { - 'country': 'spain', + 'country': None, 'columns': ['id', 'name'], 'as_json': True }, @@ -241,14 +269,19 @@ def test_investpy(): }, { 'country': 'spain', - 'columns': None, - 'as_json': False + 'columns': ['id', 'name'], + 'as_json': True }, { 'country': 'spain', 'columns': ['id', 'name'], 'as_json': False }, + { + 'country': 'spain', + 'columns': None, + 'as_json': False + }, ] for param in params: @@ -256,7 +289,14 @@ def test_investpy(): columns=param['columns'], as_json=param['as_json']) + investpy.get_etf_countries() + params = [ + { + 'as_json': True, + 'order': 'ascending', + 'debug': False + }, { 'as_json': False, 'order': 'ascending', @@ -267,11 +307,6 @@ def test_investpy(): 'order': 'descending', 'debug': False }, - { - 'as_json': True, - 'order': 'ascending', - 'debug': False - }, { 'as_json': False, 'order': 'descending', @@ -300,7 +335,7 @@ def test_investpy(): 'as_json': True, }, { - 'country': 'usa', + 'country': 'france', 'as_json': False, }, ] @@ -313,5 +348,106 @@ def test_investpy(): retrieve_etfs(test_mode=True) +def test_investpy_indices(): + """ + This function checks that index data retrieval functions listed in investpy work properly. + """ + + params = [ + { + 'country': 'spain', + }, + { + 'country': None, + }, + ] + + for param in params: + investpy.get_indices(country=param['country']) + investpy.get_indices_list(country=param['country']) + + params = [ + { + 'country': None, + 'columns': ['name', 'currency'], + 'as_json': True + }, + { + 'country': None, + 'columns': ['name', 'currency'], + 'as_json': False + }, + { + 'country': 'spain', + 'columns': ['name', 'currency'], + 'as_json': True + }, + { + 'country': 'spain', + 'columns': ['name', 'currency'], + 'as_json': False + }, + { + 'country': 'spain', + 'columns': None, + 'as_json': False + }, + ] + + for param in params: + investpy.get_indices_dict(country=param['country'], + columns=param['columns'], + as_json=param['as_json']) + + investpy.get_index_countries() + + params = [ + { + 'as_json': True, + 'order': 'ascending', + 'debug': False + }, + { + 'as_json': False, + 'order': 'ascending', + 'debug': True + }, + { + 'as_json': True, + 'order': 'descending', + 'debug': False + }, + { + 'as_json': False, + 'order': 'descending', + 'debug': False + }, + ] + + for param in params: + investpy.get_index_recent_data(index='ibex 35', + country='spain', + as_json=param['as_json'], + order=param['order'], + debug=param['debug']) + + investpy.get_index_historical_data(index='ibex 35', + country='spain', + from_date='01/01/2018', + to_date='01/01/2019', + as_json=param['as_json'], + order=param['order'], + debug=param['debug']) + + investpy.search_indices(by='name', value='ibex') + + retrieve_indices(test_mode=True) + retrieve_index_countries(test_mode=True) + + if __name__ == '__main__': test_investpy() + test_investpy_equities() + test_investpy_funds() + test_investpy_etfs() + test_investpy_indices() diff --git a/tests/test_investpy_errors.py b/tests/test_investpy_errors.py index f14a90aa..9abad80a 100644 --- a/tests/test_investpy_errors.py +++ b/tests/test_investpy_errors.py @@ -10,12 +10,14 @@ from investpy.equities import retrieve_equities, retrieve_equity_countries from investpy.funds import retrieve_funds, retrieve_fund_countries from investpy.etfs import retrieve_etfs +from investpy.indices import retrieve_indices, retrieve_index_countries + from investpy.user_agent import get_random, clear_file, delete_file -def test_equity_errors(): +def test_equities_errors(): """ - This function raises errors on equity functions + This function raises errors on equity retrieval functions """ try: @@ -396,9 +398,9 @@ def test_equity_errors(): pass -def test_fund_errors(): +def test_funds_errors(): """ - This function raises errors on fund functions + This function raises errors on fund retrieval functions """ try: @@ -786,9 +788,9 @@ def test_fund_errors(): pass -def test_etf_errors(): +def test_etfs_errors(): """ - This function raises errors on etf functions + This function raises errors on etf retrieval functions """ try: @@ -1150,6 +1152,346 @@ def test_etf_errors(): pass +def test_indices_errors(): + """ + This function raises errors on index retrieval functions + """ + + try: + retrieve_indices(test_mode=None) + except: + pass + + try: + retrieve_index_countries(test_mode=None) + except: + pass + + params = [ + { + 'country': ['error'] + }, + { + 'country': 'error' + }, + ] + + for param in params: + try: + investpy.get_indices(country=param['country']) + except: + pass + + try: + investpy.get_indices_list(country=param['country']) + except: + pass + + params = [ + { + 'country': ['error'], + 'columns': None, + 'as_json': False + }, + { + 'country': 'spain', + 'columns': None, + 'as_json': 'error' + }, + { + 'country': 'spain', + 'columns': 0, + 'as_json': True + }, + { + 'country': 'spain', + 'columns': ['error'], + 'as_json': False + }, + ] + + for param in params: + try: + investpy.get_indices_dict(country=param['country'], + columns=param['columns'], + as_json=param['as_json']) + except: + pass + + params = [ + { + 'index': None, + 'country': 'spain', + 'as_json': False, + 'order': 'ascending', + 'debug': True + }, + { + 'index': ['error'], + 'country': 'spain', + 'as_json': False, + 'order': 'ascending', + 'debug': True + }, + { + 'index': 'ibex 35', + 'country': None, + 'as_json': False, + 'order': 'ascending', + 'debug': True + }, + { + 'index': 'ibex 35', + 'country': 'error', + 'as_json': False, + 'order': 'ascending', + 'debug': True + }, + { + 'index': 'ibex 35', + 'country': 'netherlands', + 'as_json': False, + 'order': 'ascending', + 'debug': True + }, + { + 'index': 'ibex 35', + 'country': ['error'], + 'as_json': False, + 'order': 'ascending', + 'debug': True + }, + { + 'index': 'ibex 35', + 'country': 'spain', + 'as_json': 'error', + 'order': 'ascending', + 'debug': True + }, + { + 'index': 'ibex 35', + 'country': 'spain', + 'as_json': True, + 'order': 'error', + 'debug': True + }, + { + 'index': 'error', + 'country': 'spain', + 'as_json': True, + 'order': 'ascending', + 'debug': True + }, + { + 'index': ['error'], + 'country': 'spain', + 'as_json': True, + 'order': 'ascending', + 'debug': True + }, + { + 'index': 'ibex 35', + 'country': 'spain', + 'as_json': True, + 'order': 'ascending', + 'debug': 'error' + }, + ] + + for param in params: + try: + investpy.get_index_recent_data(index=param['index'], + country=param['country'], + as_json=param['as_json'], + order=param['order'], + debug=param['debug']) + except: + pass + + params = [ + { + 'index': None, + 'country': 'spain', + 'from_date': '01/01/2018', + 'to_date': '01/01/2019', + 'as_json': False, + 'order': 'ascending', + 'debug': True + }, + { + 'index': 'ibex 35', + 'country': 'error', + 'from_date': '01/01/2018', + 'to_date': '01/01/2019', + 'as_json': False, + 'order': 'ascending', + 'debug': True + }, + { + 'index': 'ibex 35', + 'country': 'netherlands', + 'from_date': '01/01/2018', + 'to_date': '01/01/2019', + 'as_json': False, + 'order': 'ascending', + 'debug': True + }, + { + 'index': 'ibex 35', + 'country': None, + 'from_date': '01/01/2018', + 'to_date': '01/01/2019', + 'as_json': False, + 'order': 'ascending', + 'debug': True + }, + { + 'index': 'ibex 35', + 'country': ['error'], + 'from_date': '01/01/2018', + 'to_date': '01/01/2019', + 'as_json': False, + 'order': 'ascending', + 'debug': True + }, + { + 'index': 'ibex 35', + 'country': 'spain', + 'from_date': '01/01/2018', + 'to_date': '01/01/2019', + 'as_json': 'error', + 'order': 'ascending', + 'debug': True + }, + { + 'index': 'ibex 35', + 'country': 'spain', + 'from_date': '01/01/2018', + 'to_date': '01/01/2019', + 'as_json': False, + 'order': 'error', + 'debug': True + }, + { + 'index': 'ibex 35', + 'country': 'spain', + 'from_date': 'error', + 'to_date': '01/01/2019', + 'as_json': False, + 'order': 'ascending', + 'debug': True + }, + { + 'index': 'ibex 35', + 'country': 'spain', + 'from_date': '01/01/2019', + 'to_date': 'error', + 'as_json': False, + 'order': 'ascending', + 'debug': True + }, + { + 'index': 'error', + 'country': 'spain', + 'from_date': '01/01/2018', + 'to_date': '01/01/2019', + 'as_json': False, + 'order': 'ascending', + 'debug': True + }, + { + 'index': ['error'], + 'country': 'spain', + 'from_date': '01/01/2018', + 'to_date': '01/01/2019', + 'as_json': False, + 'order': 'ascending', + 'debug': True + }, + { + 'index': 'ibex 35', + 'country': 'spain', + 'from_date': '01/01/1998', + 'to_date': '01/01/2019', + 'as_json': False, + 'order': 'ascending', + 'debug': True + }, + { + 'index': 'ibex 35', + 'country': 'spain', + 'from_date': '01/01/2019', + 'to_date': '01/01/1998', + 'as_json': False, + 'order': 'ascending', + 'debug': True + }, + { + 'index': 'ibex 35', + 'country': 'spain', + 'from_date': '01/01/1900', + 'to_date': '01/01/1950', + 'as_json': False, + 'order': 'ascending', + 'debug': True + }, + { + 'index': 'ibex 35', + 'country': 'spain', + 'from_date': '01/01/2019', + 'to_date': '01/03/2019', + 'as_json': True, + 'order': 'ascending', + 'debug': 'error' + }, + ] + + for param in params: + try: + investpy.get_index_historical_data(index=param['index'], + country=param['country'], + from_date=param['from_date'], + to_date=param['to_date'], + as_json=param['as_json'], + order=param['order'], + debug=param['debug']) + except: + pass + + params = [ + { + 'by': None, + 'value': 'ibex', + }, + { + 'by': ['error'], + 'value': 'ibex', + }, + { + 'by': 'error', + 'value': 'ibex', + }, + { + 'by': 'name', + 'value': None, + }, + { + 'by': 'name', + 'value': ['error'], + }, + { + 'by': 'name', + 'value': 'error', + }, + ] + + for param in params: + try: + investpy.search_indices(by=param['by'], value=param['value']) + except: + pass + + def test_user_agent_errors(): """ This function raises errors on user_agent functions @@ -1169,7 +1511,8 @@ def test_user_agent_errors(): if __name__ == '__main__': - test_equity_errors() - test_fund_errors() - test_etf_errors() + test_equities_errors() + test_funds_errors() + test_etfs_errors() + test_indices_errors() test_user_agent_errors()