From 4704322928c05d19e985f0c09f85e1bb25809dad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Bartolom=C3=A9?= Date: Sat, 12 Jun 2021 09:31:33 +0000 Subject: [PATCH 01/23] fixed #339, defined flag to check if user limited search --- investpy/search.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/investpy/search.py b/investpy/search.py index 81866cf..e12cbd9 100644 --- a/investpy/search.py +++ b/investpy/search.py @@ -118,6 +118,8 @@ class instances which will contain the search results so that they can be easily total_results = None + user_limit = True if n_results is not None else False + while True: req = requests.post(url, headers=head, data=params) @@ -154,7 +156,7 @@ class instances which will contain the search results so that they can be easily country=country, tag=quote['link'], pair_type=pair_type, exchange=quote['exchange']) - if n_results == 1: return search_obj + if n_results == 1 and user_limit: return search_obj if search_obj not in search_results: search_results.append(search_obj) From cb90c77f38f19d13cf8f2ca5bfaf00487e557d60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Bartolom=C3=A9?= Date: Sat, 12 Jun 2021 09:35:12 +0000 Subject: [PATCH 02/23] set info on self while retrieving information (SearchObj) --- investpy/utils/search_obj.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/investpy/utils/search_obj.py b/investpy/utils/search_obj.py index fbc9756..5cce78f 100644 --- a/investpy/utils/search_obj.py +++ b/investpy/utils/search_obj.py @@ -201,7 +201,7 @@ def retrieve_information(self): root_ = fromstring(req.text) path_ = root_.xpath("//div[contains(@class, 'overviewDataTable')]/div") - info = dict() + self.info = dict() if not path_: raise RuntimeError("ERR#0004: data retrieval error while scraping.") @@ -215,14 +215,14 @@ def retrieve_information(self): value = float(element.getnext().text_content().replace(',', '')) if isinstance(value, float): if value.is_integer() is True: value = int(value) - info[title] = value if value != 'N/A' else None + self.info[title] = value if value != 'N/A' else None continue except: pass try: text = element.getnext().text_content().strip() text = datetime.strptime(text, "%m/%d/%Y").strftime("%d/%m/%Y") - info[title] = text if text != 'N/A' else None + self.info[title] = text if text != 'N/A' else None continue except: pass @@ -230,7 +230,7 @@ def retrieve_information(self): text = element.getnext().text_content().strip() if text.__contains__('1 = '): text = text.replace('1 = ', '') - info[title] = text if text != 'N/A' else None + self.info[title] = text if text != 'N/A' else None continue except: pass @@ -246,12 +246,11 @@ def retrieve_information(self): value = float(value.replace('T', '').replace(',', '')) * 1e12 if isinstance(value, float): if value.is_integer() is True: value = int(value) - info[title] = value if value != 'N/A' else None + self.info[title] = value if value != 'N/A' else None continue except: pass - self.info = info return self.info def _prepare_request(self, header): From 55425aec4a72262e1724e9ddd24b158c34beb502 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Bartolom=C3=A9?= Date: Sat, 12 Jun 2021 10:10:52 +0000 Subject: [PATCH 03/23] closed #375 for search_quotes, included change_pct but kept Close --- investpy/utils/search_obj.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/investpy/utils/search_obj.py b/investpy/utils/search_obj.py index 5cce78f..e0ee02f 100644 --- a/investpy/utils/search_obj.py +++ b/investpy/utils/search_obj.py @@ -321,10 +321,8 @@ def _calculate_intervals(self, from_date, to_date): return intervals def _data_retrieval(self, product, headers, params): - if product in ['stocks', 'etfs', 'indices', 'fxfutures', 'cryptos']: - has_volume = True - else: - has_volume = False + has_volume = True if product in ['stocks', 'etfs', 'indices', 'cryptos', 'commodities', 'fxfutures'] else False + has_change_pct = True # Every financial product has it url = "https://www.investing.com/instruments/HistoricalDataAjax" @@ -345,8 +343,8 @@ def _data_retrieval(self, product, headers, params): info = [] for nested_ in elements_.xpath(".//td"): - val = nested_.get('data-real-value') - if val is None and nested_.text_content() == 'No results found': + val = nested_.get('data-real-value') if nested_.get('data-real-value') is not None else nested_.text_content() + if val == 'No results found': raise IndexError("ERR#0033: information unavailable or not found.") info.append(val) @@ -358,7 +356,12 @@ def _data_retrieval(self, product, headers, params): 'Close': float(info[1].replace(',', '')) } - if has_volume is True: result['Volume'] = int(info[5]) + if has_volume and has_change_pct: + result['Volume'] = int(info[5]) + result['Change Pct'] = float(info[6].replace(',', '').replace('%', '')) + + if not has_volume and has_change_pct: + result['Change Pct'] = float(info[6].replace(',', '').replace('%', '')) results.append(result) From 50f9fb8984d13f9976045f91888e34213c889353 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Bartolom=C3=A9?= Date: Sat, 12 Jun 2021 10:15:27 +0000 Subject: [PATCH 04/23] closed #212, raised IndexError exception on 'No results found' for intervals --- investpy/utils/search_obj.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/investpy/utils/search_obj.py b/investpy/utils/search_obj.py index e0ee02f..6293917 100644 --- a/investpy/utils/search_obj.py +++ b/investpy/utils/search_obj.py @@ -152,7 +152,7 @@ def retrieve_historical_data(self, from_date, to_date): continue if len(self.data) < 1: - raise RuntimeError("ERR#0004: data retrieval error while scraping.") + raise IndexError("ERR#0033: information unavailable or not found.") else: headers, params = self._prepare_historical_request(header=header, from_date=from_date.strftime('%m/%d/%Y'), From 429e2b07f9e80fb1746f2f11df3ae9a22dd0e1b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Bartolom=C3=A9?= Date: Sat, 12 Jun 2021 10:24:14 +0000 Subject: [PATCH 05/23] fixed build & solved #375 (wrong index on change_pct) --- investpy/utils/search_obj.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/investpy/utils/search_obj.py b/investpy/utils/search_obj.py index 6293917..8c86268 100644 --- a/investpy/utils/search_obj.py +++ b/investpy/utils/search_obj.py @@ -361,7 +361,7 @@ def _data_retrieval(self, product, headers, params): result['Change Pct'] = float(info[6].replace(',', '').replace('%', '')) if not has_volume and has_change_pct: - result['Change Pct'] = float(info[6].replace(',', '').replace('%', '')) + result['Change Pct'] = float(info[5].replace(',', '').replace('%', '')) results.append(result) From 45cfaa67c45d5fb4172fb1ae2240e81bf26dd843 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Bartolom=C3=A9?= Date: Sat, 12 Jun 2021 10:57:36 +0000 Subject: [PATCH 06/23] retrieve_technical_indicators available in SearchObj (#374,#391,#392) --- investpy/utils/constant.py | 7 ++++ investpy/utils/search_obj.py | 72 ++++++++++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+) diff --git a/investpy/utils/constant.py b/investpy/utils/constant.py index 4eb1a20..dc4d63d 100644 --- a/investpy/utils/constant.py +++ b/investpy/utils/constant.py @@ -166,6 +166,13 @@ 'monthly': 'month' } +# https://www.investing.com/funds/vanguard-500-index-admiral-technical +FUNDS_INTERVAL_FILTERS = { + 'daily': 60*60*24, + 'weekly': 'week', + 'monthly': 'month' +} + USER_AGENTS = [ "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b3) Gecko/20090305 Firefox/3.1b3 GTB5", "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; ko; rv:1.9.1b2) Gecko/20081201 Firefox/3.1b2", diff --git a/investpy/utils/search_obj.py b/investpy/utils/search_obj.py index 8c86268..cbc44b5 100644 --- a/investpy/utils/search_obj.py +++ b/investpy/utils/search_obj.py @@ -12,6 +12,7 @@ from .data import Data from .extra import random_user_agent +from .constant import INTERVAL_FILTERS, FUNDS_INTERVAL_FILTERS class SearchObj(object): @@ -253,6 +254,77 @@ def retrieve_information(self): return self.info + def retrieve_technical_indicators(self, interval='daily'): + """Class method used to retrieve the information from the class instance of any financial product. + + This method retrieves the information from Investing.com of the financial product of the current class + instance, so it fills the `SearchObj.info` attribute with the retrieved :obj:`dict`. This method uses the + previously retrieved data from the `investpy.search_quotes(text, products, countries, n_results)` + function search results to build the request that it is going to be sent to Investing.com so to retrieve and + parse the information, since the product tag is required. + + Returns: + :obj:`dict` - info: + This method retrieves the information from the current class instance of a financial product + from Investing.com. This method both stores retrieved information in self.info attribute of the class + instance and it also returns it as a normal function will do. + + Raises: + ValueError: raised if any of the input parameters is not valid. + + """ + + if self.pair_type in []: + raise ValueError(f"Investing.com does not provide technical indicators for {self.pair_type}.") + + if self.pair_type != 'funds' and interval not in INTERVAL_FILTERS: + raise ValueError(f"Investing.com just provides the following intervals for {self.pair_type}' technical " \ + f"indicators: {', '.join(list(INTERVAL_FILTERS.keys()))}") + + if self.pair_type == 'funds' and interval not in FUNDS_INTERVAL_FILTERS: + raise ValueError("Investing.com just provides the following intervals for funds' technical " \ + f"indicators: {', '.join(list(FUNDS_INTERVAL_FILTERS.keys()))}") + + params = { + 'pairID': self.id_, + 'period': INTERVAL_FILTERS[interval], + 'viewType': 'normal' + } + + headers = { + "User-Agent": random_user_agent(), + "X-Requested-With": "XMLHttpRequest", + "Accept": "text/html", + "Accept-Encoding": "gzip, deflate", + "Connection": "keep-alive", + } + + url = "https://www.investing.com/instruments/Service/GetTechincalData" + + req = requests.post(url, headers=headers, data=params) + + if req.status_code != 200: + raise ConnectionError(f"ERR#0015: error {req.status_code}, try again later.") + + root_ = fromstring(req.text) + table_ = root_.xpath(".//table[contains(@class, 'technicalIndicatorsTbl')]/tbody/tr") + + if not table_: + raise RuntimeError("ERR#0004: data retrieval error while scraping.") + + self.technical_indicators = pd.DataFrame() + + for row in table_: + for value in row.xpath("td"): + if value.get('class').__contains__('symbol'): + self.technical_indicators = self.technical_indicators.append({ + 'indicator': value.text_content().strip(), + 'value': float(value.getnext().text_content().strip()), + 'signal': (value.getnext().getnext().text_content().strip().lower()).replace(' ', '_') + }, ignore_index=True) + + return self.technical_indicators + def _prepare_request(self, header): headers = { "User-Agent": random_user_agent(), From 970bbabd5ad691e765833678e1e551f0141f74ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Bartolom=C3=A9?= Date: Sat, 12 Jun 2021 11:03:53 +0000 Subject: [PATCH 07/23] included missing docstring tech indicators (#374,#391,#392) --- investpy/utils/search_obj.py | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/investpy/utils/search_obj.py b/investpy/utils/search_obj.py index cbc44b5..9ac89ae 100644 --- a/investpy/utils/search_obj.py +++ b/investpy/utils/search_obj.py @@ -101,15 +101,15 @@ def retrieve_historical_data(self, from_date, to_date): `investpy.search_quotes(text, products, countries, n_results)` function search results to build the request that it is going to be sent to Investing.com so to retrieve and parse the data. + Args: + from_date (:obj:`str`): date from which data will be retrieved, specified in dd/mm/yyyy format. + to_date (:obj:`str`): date until data will be retrieved, specified in dd/mm/yyyy format. + Returns: :obj:`pandas.DataFrame` - data: This method retrieves the historical data from the current class instance of a financial product from Investing.com. This method both stores retrieved data in self.data attribute of the class instance and it also returns it as a normal function will do. - - Args: - from_date (:obj:`str`): date from which data will be retrieved, specified in dd/mm/yyyy format. - to_date (:obj:`str`): date until data will be retrieved, specified in dd/mm/yyyy format. Raises: ValueError: raised if any of the introduced parameters was not valid or errored. @@ -255,22 +255,30 @@ def retrieve_information(self): return self.info def retrieve_technical_indicators(self, interval='daily'): - """Class method used to retrieve the information from the class instance of any financial product. + """Class method used to retrieve the technical indicators from the class instance of any financial product. - This method retrieves the information from Investing.com of the financial product of the current class - instance, so it fills the `SearchObj.info` attribute with the retrieved :obj:`dict`. This method uses the + This method retrieves the technical indicators from Investing.com for the financial product of the current + class instance, to later put in into the `SearchObj.technical_indicators` attribute. This method uses the previously retrieved data from the `investpy.search_quotes(text, products, countries, n_results)` function search results to build the request that it is going to be sent to Investing.com so to retrieve and - parse the information, since the product tag is required. + parse the technical indicators, since the product id is required. + + Args: + interval (:obj:`str`, optional): + time interval of the technical indicators' calculations, available values are: `5mins`, `15mins`, + `30mins`, `1hour`, `5hours`, `daily`, `weekly` and `monthly`. Note that for funds just the intervals: + `daily`, `weekly` and `monthly` are available. Returns: - :obj:`dict` - info: - This method retrieves the information from the current class instance of a financial product - from Investing.com. This method both stores retrieved information in self.info attribute of the class - instance and it also returns it as a normal function will do. + :obj:`pd.DataFrame` - technical_indicators: + This method retrieves the technical indicators from the current class instance of a financial product + from Investing.com. This method not just stores retrieved technical indicators table into self.technical_indicators + but it also returns it as a normal function will do. Raises: ValueError: raised if any of the input parameters is not valid. + ConnectionError: raised if connection to Investing.com could not be established. + RuntimeError: raised if there was any problem while retrieving the data from Investing.com. """ From 653ae5f7b11a91cf3026592d861bf82a3a442b07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Bartolom=C3=A9?= Date: Sat, 12 Jun 2021 11:11:49 +0000 Subject: [PATCH 08/23] included tests for retrieve_technical_indicators (#374,#391,#392) --- tests/test_investpy.py | 5 +++++ tests/test_investpy_errors.py | 17 +++++++++++++++-- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/tests/test_investpy.py b/tests/test_investpy.py index f1ae45b..43afc3a 100644 --- a/tests/test_investpy.py +++ b/tests/test_investpy.py @@ -1316,9 +1316,14 @@ def test_investpy_search(): print(result) assert result.retrieve_recent_data() is not None + for date in dates: assert result.retrieve_historical_data(from_date=date['from_date'], to_date=date['to_date']) is not None + assert result.retrieve_information() is not None + + assert result.retrieve_technical_indicators() is not None + def test_investpy_news(): """ diff --git a/tests/test_investpy_errors.py b/tests/test_investpy_errors.py index 0646142..fa693f5 100644 --- a/tests/test_investpy_errors.py +++ b/tests/test_investpy_errors.py @@ -3897,6 +3897,12 @@ def test_search_errors(): 'products': None, 'countries': ['error'], 'n_results': 10 + }, + { + 'text': 'bbva', + 'products': None, + 'countries': None, + 'n_results': 10 } ] @@ -3922,13 +3928,20 @@ def test_search_errors(): }, ] - for result in results: + for result in results[:1]: for date in dates: try: result.retrieve_historical_data(from_date=date['from_date'], to_date=date['to_date']) except: continue - break + + intervals = ['non_existing', '1min'] + for interval in intervals: + try: + result.pair_type = 'funds' + result.retrieve_technical_indicators(interval=interval) + except: + continue except: pass From dad85347ffc88cb8d4d84bd27dada8f28b88a33b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Bartolom=C3=A9?= Date: Sat, 12 Jun 2021 11:37:44 +0000 Subject: [PATCH 09/23] implemented retrieve_currency in SearchObj (#172,#181,#390) --- investpy/utils/search_obj.py | 43 ++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/investpy/utils/search_obj.py b/investpy/utils/search_obj.py index 9ac89ae..9a5ab16 100644 --- a/investpy/utils/search_obj.py +++ b/investpy/utils/search_obj.py @@ -333,6 +333,49 @@ class instance, to later put in into the `SearchObj.technical_indicators` attrib return self.technical_indicators + def retrieve_currency(self): + """Class method used to retrieve the default currency from the class instance of any financial product. + + This method retrieves the default currency from Investing.com of the financial product of the current class + instance. This method uses the data previously retrieved from the `investpy.search_quotes(text, products, countries, n_results)` + function search results to build the request that it is going to be sent to Investing.com so to retrieve and + parse the information, since the product tag is required. + + Returns: + :obj:`str` - default_currency: + This method retrieves the default currency from the current class instance of a financial product + from Investing.com. + + Raises: + ConnectionError: raised if connection to Investing.com could not be established. + RuntimeError: raised if there was any problem while retrieving the data from Investing.com. + + """ + + url = f"https://www.investing.com{self.tag}" + + headers = { + "User-Agent": random_user_agent(), + "X-Requested-With": "XMLHttpRequest", + "Accept": "text/html", + "Accept-Encoding": "gzip, deflate", + "Connection": "keep-alive", + } + + req = requests.get(url, headers=headers) + + if req.status_code != 200: + raise ConnectionError(f"ERR#0015: error {req.status_code}, try again later.") + + root_ = fromstring(req.text) + path_ = root_.xpath("//div[contains(@class, 'instrument-metadata_currency')]/span") + + if not path_: + raise RuntimeError("ERR#0004: data retrieval error while scraping.") + + self.default_currency = path_[-1].text_content().strip() + return self.default_currency + def _prepare_request(self, header): headers = { "User-Agent": random_user_agent(), From 654c3cbc4a8f16ff3857e089631862e737f82b95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Bartolom=C3=A9?= Date: Sat, 12 Jun 2021 11:42:50 +0000 Subject: [PATCH 10/23] SearchObj attr renamed info -> information & docstring updates --- investpy/search.py | 14 +++++++++----- investpy/utils/search_obj.py | 14 +++++++------- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/investpy/search.py b/investpy/search.py index e12cbd9..0e19ce8 100644 --- a/investpy/search.py +++ b/investpy/search.py @@ -14,11 +14,17 @@ def search_quotes(text, products=None, countries=None, n_results=None): """ This function will use the Investing.com search engine so to retrieve the search results of the introduced text. This function will create a :obj:`list` of :obj:`investpy.utils.search_obj.SearchObj` - class instances which will contain the search results so that they can be easily accessed and so + class instances, unless `n_results` is set to 1, where just a single :obj:`investpy.utils.search_obj.SearchObj` + will be returned. + + Those class instances will contain the search results so that they can be easily accessed and so to ease the data retrieval process since it can be done calling the methods `self.retrieve_recent_data()` or `self.retrieve_historical_data(from_date, to_date)` from each class instance, which will fill the historical - data attribute, `self.data`. The information of the financial product can also be retrieved using the - function `self.retrieve_information()`, that will also dump the information in the attribute `self.info`. + data attribute, `self.data`. Also the information of the financial product can be retrieved using the + function `self.retrieve_information()`, that will also dump the information in the attribute `self.information`; + the technical indicators can be retrieved using `self.retrieve_technical_indicators()` dumped in the attribute + `self.technical_indicators`; the default currency using `self.retrieve_currecy()` dumped in the attribute + `self.default_currency`. Args: text (:obj:`str`): text to search in Investing.com among all its indexed data. @@ -74,7 +80,6 @@ class instances which will contain the search results so that they can be easily condition = set(products).issubset(cst.PRODUCT_FILTERS.keys()) if condition is False: - # TODO: instead of printing the possible filters, reference the docs raise ValueError('ERR#0095: products filtering parameter possible values are: \"' + ', '.join(cst.PRODUCT_FILTERS.keys()) + '\".') products = [cst.PRODUCT_FILTERS[product] for product in products] @@ -89,7 +94,6 @@ class instances which will contain the search results so that they can be easily condition = set(countries).issubset(cst.COUNTRY_FILTERS.keys()) if condition is False: - # TODO: instead of printing the possible filters, reference the docs raise ValueError('ERR#0129: countries filtering parameter possible values are: \"' + ', '.join(cst.COUNTRY_FILTERS.keys()) + '\".') countries = [cst.COUNTRY_FILTERS[country] for country in countries] diff --git a/investpy/utils/search_obj.py b/investpy/utils/search_obj.py index 9a5ab16..81e5246 100644 --- a/investpy/utils/search_obj.py +++ b/investpy/utils/search_obj.py @@ -175,7 +175,7 @@ def retrieve_information(self): Returns: :obj:`dict` - info: This method retrieves the information from the current class instance of a financial product - from Investing.com. This method both stores retrieved information in self.info attribute of the class + from Investing.com. This method both stores retrieved information in self.information attribute of the class instance and it also returns it as a normal function will do. Raises: @@ -202,7 +202,7 @@ def retrieve_information(self): root_ = fromstring(req.text) path_ = root_.xpath("//div[contains(@class, 'overviewDataTable')]/div") - self.info = dict() + self.information = dict() if not path_: raise RuntimeError("ERR#0004: data retrieval error while scraping.") @@ -216,14 +216,14 @@ def retrieve_information(self): value = float(element.getnext().text_content().replace(',', '')) if isinstance(value, float): if value.is_integer() is True: value = int(value) - self.info[title] = value if value != 'N/A' else None + self.information[title] = value if value != 'N/A' else None continue except: pass try: text = element.getnext().text_content().strip() text = datetime.strptime(text, "%m/%d/%Y").strftime("%d/%m/%Y") - self.info[title] = text if text != 'N/A' else None + self.information[title] = text if text != 'N/A' else None continue except: pass @@ -231,7 +231,7 @@ def retrieve_information(self): text = element.getnext().text_content().strip() if text.__contains__('1 = '): text = text.replace('1 = ', '') - self.info[title] = text if text != 'N/A' else None + self.information[title] = text if text != 'N/A' else None continue except: pass @@ -247,12 +247,12 @@ def retrieve_information(self): value = float(value.replace('T', '').replace(',', '')) * 1e12 if isinstance(value, float): if value.is_integer() is True: value = int(value) - self.info[title] = value if value != 'N/A' else None + self.information[title] = value if value != 'N/A' else None continue except: pass - return self.info + return self.information def retrieve_technical_indicators(self, interval='daily'): """Class method used to retrieve the technical indicators from the class instance of any financial product. From cb0ee5a3e0706beb47f0a1fb98f744f862a8674b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Bartolom=C3=A9?= Date: Sat, 12 Jun 2021 12:26:24 +0000 Subject: [PATCH 11/23] solved #395, retrieve_information fixed & improved --- investpy/utils/search_obj.py | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/investpy/utils/search_obj.py b/investpy/utils/search_obj.py index 81e5246..429e02f 100644 --- a/investpy/utils/search_obj.py +++ b/investpy/utils/search_obj.py @@ -200,20 +200,18 @@ def retrieve_information(self): raise ConnectionError(f"ERR#0015: error {req.status_code}, try again later.") root_ = fromstring(req.text) - path_ = root_.xpath("//div[contains(@class, 'overviewDataTable')]/div") - - self.information = dict() + path_ = root_.xpath("//dl[@data-test='key-info']/div") if not path_: raise RuntimeError("ERR#0004: data retrieval error while scraping.") + + self.information = dict() for elements_ in path_: - element = elements_.xpath(".//span[@class='float_lang_base_1']")[0] - title = element.text_content().strip() - if title == "Day's Range": - title = 'Todays Range' + element = elements_.xpath(".//dd")[0] + title = element.get('data-test') try: - value = float(element.getnext().text_content().replace(',', '')) + value = float(element.text_content().replace(',', '')) if isinstance(value, float): if value.is_integer() is True: value = int(value) self.information[title] = value if value != 'N/A' else None @@ -221,14 +219,14 @@ def retrieve_information(self): except: pass try: - text = element.getnext().text_content().strip() - text = datetime.strptime(text, "%m/%d/%Y").strftime("%d/%m/%Y") + text = element.text_content().strip() + text = datetime.strptime(text, "%b %d, %Y").strftime("%d/%m/%Y") self.information[title] = text if text != 'N/A' else None continue except: pass try: - text = element.getnext().text_content().strip() + text = element.text_content().strip() if text.__contains__('1 = '): text = text.replace('1 = ', '') self.information[title] = text if text != 'N/A' else None @@ -236,7 +234,7 @@ def retrieve_information(self): except: pass try: - value = element.getnext().text_content().strip() + value = element.text_content().strip() if value.__contains__('K'): value = float(value.replace('K', '').replace(',', '')) * 1e3 elif value.__contains__('M'): From 4e0ef568661fc91bf10f8e44496c5e72b7d4f88f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Bartolom=C3=A9?= Date: Sat, 12 Jun 2021 13:06:00 +0000 Subject: [PATCH 12/23] add both scraping methods #395 & defined updated titles --- investpy/utils/constant.py | 58 ++++++++++++++++++++++++++++++++++-- investpy/utils/search_obj.py | 26 ++++++++++++---- 2 files changed, 76 insertions(+), 8 deletions(-) diff --git a/investpy/utils/constant.py b/investpy/utils/constant.py index dc4d63d..7200e39 100644 --- a/investpy/utils/constant.py +++ b/investpy/utils/constant.py @@ -1,6 +1,60 @@ # Copyright 2018-2021 Alvaro Bartolome, alvarobartt @ GitHub # See LICENSE for details. +# To be removed once Investing.com aligns financial products information +OUTDATED2UPDATED = { + 'Prev. Close': 'prevClose', + "Day's Range": 'dailyRange', + 'ROI (TTM)': 'roiTtm', + 'Revenue': 'revenue', + 'Open': 'open', + 'Price Open': 'priceOpen', + 'Price Range': 'priceRange', + 'Coupon': 'coupon', + '52 wk Range': 'weekRange', + 'EPS': 'eps', + 'Volume': 'volume', + 'Market Cap': 'marketCap', + 'Dividend (Yield)': 'dividend', + 'Average Vol. (3m)': 'avgVolume', + 'P/E Ratio': 'ratio', + 'Beta': 'beta', + 'Month': 'month', + '1-Year Change': 'oneYearReturn', + 'Madurity Date': 'madurityDate', + 'Shares Outstanding': 'sharesOutstanding', + 'Next Earnings Date': 'nextEarningDate', + 'Dividends (TTM)': 'dividednsTtm', + 'Total Assets': 'totalAssets', + 'Asset Class': 'assetClass', + 'Tick Size': 'tickSize', + 'Contract Size': 'contractSize', + 'Tick Value': 'tickValue', + 'Settlement': 'settlement', + 'Base Symbol': 'baseSymbol', + 'Settlement Day': 'settlementDay', + 'Settlement Type': 'settlementType', + 'Point Value': 'pointValue', + 'Last Rollover Day': 'lastRolloverDay', + 'Months': 'months', + 'Bid': 'bid', + 'Ask': 'ask', + 'Rating': 'rating', + 'Risk Rating': 'riskRating', + 'Issuer': 'issuer', + 'Inception Date': 'inceptionDate', + 'Min. Investment': 'minInvestment', + 'TTM Yield': 'ttmYield', + 'Turnover': 'turnover', + 'ROE': 'roe', + 'ROA': 'roa', + 'Expenses': 'expenses', + 'Category': 'category', + 'Leverage': 'leverage', + 'Strike Price': 'strikePrice', + 'Issue Amount': 'issueAmount' +} + FINANCIAL_SUMMARY_TYPES = { 'income_statement': 0, 'balance_sheet': 1, @@ -8,8 +62,8 @@ } FINANCIAL_SUMMARY_PERIODS = { - "annual": "Annual", - "quarterly": "Interim" + 'annual': 'Annual', + 'quarterly': 'Interim' } PRODUCT_FILTERS = { diff --git a/investpy/utils/search_obj.py b/investpy/utils/search_obj.py index 429e02f..0723a8e 100644 --- a/investpy/utils/search_obj.py +++ b/investpy/utils/search_obj.py @@ -12,7 +12,7 @@ from .data import Data from .extra import random_user_agent -from .constant import INTERVAL_FILTERS, FUNDS_INTERVAL_FILTERS +from .constant import INTERVAL_FILTERS, FUNDS_INTERVAL_FILTERS, OUTDATED2UPDATED class SearchObj(object): @@ -199,17 +199,30 @@ def retrieve_information(self): if req.status_code != 200: raise ConnectionError(f"ERR#0015: error {req.status_code}, try again later.") + # Just change this list once the update is included for all the other products + updated_for = ['stocks'] + outdated_for = ['etfs', 'commodities', 'currencies', 'funds', 'bonds', 'cryptos', 'certificates', 'indices', 'fxfutures'] + root_ = fromstring(req.text) - path_ = root_.xpath("//dl[@data-test='key-info']/div") + updated_path = root_.xpath("//dl[@data-test='key-info']/div") + outdated_path = root_.xpath("//div[contains(@class, 'overviewDataTable')]/div") - if not path_: + if not updated_path and not outdated_path: raise RuntimeError("ERR#0004: data retrieval error while scraping.") + investing_updated = True if updated_path else False + self.information = dict() for elements_ in path_: - element = elements_.xpath(".//dd")[0] - title = element.get('data-test') + if investing_updated: + element = elements_.xpath(".//dd")[0] + title = element.get('data-test') + else: + element = elements_.xpath(".//span[@class='float_lang_base_1']")[0] + title = element.text_content().strip() + title = OUTDATED2UPDATED[title] + element = element.getnext() try: value = float(element.text_content().replace(',', '')) if isinstance(value, float): @@ -220,7 +233,8 @@ def retrieve_information(self): pass try: text = element.text_content().strip() - text = datetime.strptime(text, "%b %d, %Y").strftime("%d/%m/%Y") + in_format = "%b %d, %Y" if investing_updated else "%m/%d/%Y" + text = datetime.strptime(text, in_format).strftime("%d/%m/%Y") self.information[title] = text if text != 'N/A' else None continue except: From 5213fcfd07b9aaf89176e925d611f6ca0e1e1c00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Bartolom=C3=A9?= Date: Sat, 12 Jun 2021 14:16:35 +0000 Subject: [PATCH 13/23] search_quotes fixed bug on empty results & ignored filters if None --- investpy/search.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/investpy/search.py b/investpy/search.py index 0e19ce8..6581c61 100644 --- a/investpy/search.py +++ b/investpy/search.py @@ -31,7 +31,7 @@ class instances, unless `n_results` is set to 1, where just a single :obj:`inves products (:obj:`list` of :obj:`str`, optional): list with the product type filter/s to be applied to search result quotes so that they match the filters. Possible products are: `indices`, `stocks`, `etfs`, `funds`, `commodities`, `currencies`, - `crypto`, `bonds`, `certificates` and `fxfutures`, by default this parameter is set to `None` which + `cryptos`, `bonds`, `certificates` and `fxfutures`, by default this parameter is set to `None` which means that no filter will be applied, and all product type quotes will be retrieved. countries (:obj:`list` of :obj:`str`, optional): list with the country name filter/s to be applied to search result quotes so that they match @@ -83,8 +83,6 @@ class instances, unless `n_results` is set to 1, where just a single :obj:`inves raise ValueError('ERR#0095: products filtering parameter possible values are: \"' + ', '.join(cst.PRODUCT_FILTERS.keys()) + '\".') products = [cst.PRODUCT_FILTERS[product] for product in products] - else: - products = list(cst.PRODUCT_FILTERS.values()) if countries: try: @@ -97,8 +95,6 @@ class instances, unless `n_results` is set to 1, where just a single :obj:`inves raise ValueError('ERR#0129: countries filtering parameter possible values are: \"' + ', '.join(cst.COUNTRY_FILTERS.keys()) + '\".') countries = [cst.COUNTRY_FILTERS[country] for country in countries] - else: - countries = list(cst.COUNTRY_FILTERS.values()) params = { 'search_text': text, @@ -143,7 +139,7 @@ class instances, unless `n_results` is set to 1, where just a single :obj:`inves for quote in data['quotes']: country, pair_type = quote['flag'], quote['pair_type'] - + if countries is not None: if quote['flag'] in countries: country = cst.FLAG_FILTERS[quote['flag']] @@ -168,6 +164,9 @@ class instances, unless `n_results` is set to 1, where just a single :obj:`inves if len(search_results) >= n_results or len(search_results) >= total_results or params['offset'] >= total_results: break + + if len(search_results) < 1: + raise RuntimeError("ERR#0093: no results found on Investing.com for the introduced query.") return search_results[:n_results] From 81cf29cd52cef99a6777311b039915dbbfbd632e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Bartolom=C3=A9?= Date: Sat, 12 Jun 2021 14:18:13 +0000 Subject: [PATCH 14/23] fixed retrieve_information, updated tests & defined updated constants (#395) --- investpy/utils/constant.py | 48 +++++++++++++++++++++--------------- investpy/utils/search_obj.py | 4 +-- tests/test_investpy.py | 10 ++++++++ 3 files changed, 40 insertions(+), 22 deletions(-) diff --git a/investpy/utils/constant.py b/investpy/utils/constant.py index 7200e39..a70a964 100644 --- a/investpy/utils/constant.py +++ b/investpy/utils/constant.py @@ -8,20 +8,25 @@ 'ROI (TTM)': 'roiTtm', 'Revenue': 'revenue', 'Open': 'open', + 'Price': 'price', 'Price Open': 'priceOpen', 'Price Range': 'priceRange', 'Coupon': 'coupon', + 'Coupon Frequency': 'couponFreq', + 'Next Coupon Date': 'nextCouponDate', '52 wk Range': 'weekRange', 'EPS': 'eps', 'Volume': 'volume', 'Market Cap': 'marketCap', 'Dividend (Yield)': 'dividend', + 'Dividend Yield': 'dividend', 'Average Vol. (3m)': 'avgVolume', 'P/E Ratio': 'ratio', 'Beta': 'beta', 'Month': 'month', + 'Duration': 'duration', '1-Year Change': 'oneYearReturn', - 'Madurity Date': 'madurityDate', + 'Maturity Date': 'maturityDate', 'Shares Outstanding': 'sharesOutstanding', 'Next Earnings Date': 'nextEarningDate', 'Dividends (TTM)': 'dividednsTtm', @@ -45,14 +50,17 @@ 'Inception Date': 'inceptionDate', 'Min. Investment': 'minInvestment', 'TTM Yield': 'ttmYield', + 'Yield': 'yield', 'Turnover': 'turnover', 'ROE': 'roe', 'ROA': 'roa', + 'Type': 'type', 'Expenses': 'expenses', 'Category': 'category', 'Leverage': 'leverage', 'Strike Price': 'strikePrice', - 'Issue Amount': 'issueAmount' + 'Issue Amount': 'issueAmount', + 'Issue Date': 'issueDate' } FINANCIAL_SUMMARY_TYPES = { @@ -67,28 +75,28 @@ } PRODUCT_FILTERS = { - 'indices': 'indice', - 'stocks': 'equities', - 'etfs': 'etf', - 'funds': 'fund', - 'commodities': 'commodity', - 'currencies': 'currency', - 'cryptos': 'crypto', - 'bonds': 'bond', - 'certificates': 'certificate', + 'indices': 'indice', + 'stocks': 'equities', + 'etfs': 'etf', + 'funds': 'fund', + 'commodities': 'commodity', + 'currencies': 'currency', + 'cryptos': 'crypto', + 'bonds': 'bond', + 'certificates': 'certificate', 'fxfutures': 'fxfuture' } PAIR_FILTERS = { - 'indice': 'indices', - 'equities': 'stocks', - 'etf': 'etfs', - 'fund': 'funds', - 'commodity': 'commodities', - 'currency': 'currencies', - 'crypto': 'cryptos', - 'bond': 'bonds', - 'certificate': 'certificates', + 'indice': 'indices', + 'equities': 'stocks', + 'etf': 'etfs', + 'fund': 'funds', + 'commodity': 'commodities', + 'currency': 'currencies', + 'crypto': 'cryptos', + 'bond': 'bonds', + 'certificate': 'certificates', 'fxfuture': 'fxfutures' } diff --git a/investpy/utils/search_obj.py b/investpy/utils/search_obj.py index 0723a8e..137ce2e 100644 --- a/investpy/utils/search_obj.py +++ b/investpy/utils/search_obj.py @@ -210,10 +210,10 @@ def retrieve_information(self): if not updated_path and not outdated_path: raise RuntimeError("ERR#0004: data retrieval error while scraping.") - investing_updated = True if updated_path else False + path_, investing_updated = (updated_path, True) if updated_path else (outdated_path, False) self.information = dict() - + for elements_ in path_: if investing_updated: element = elements_.xpath(".//dd")[0] diff --git a/tests/test_investpy.py b/tests/test_investpy.py index 43afc3a..132e6f9 100644 --- a/tests/test_investpy.py +++ b/tests/test_investpy.py @@ -1324,6 +1324,16 @@ def test_investpy_search(): assert result.retrieve_technical_indicators() is not None + financial_products = [ + ('stocks', 'apple'), ('etfs', 'apple'), ('commodities', 'apple'), ('currencies', 'usd'), ('funds', 'apple'), + ('bonds', 'apple'), ('cryptos', 'bitcoin'), ('certificates', 'apple'), ('indices', 'apple'), ('fxfutures', 'usd') + ] + + for product_type, product_name in financial_products: + search_result = investpy.search_quotes(text=product_name, products=[product_type], n_results=1) + + assert search_result.retrieve_information() is not None + def test_investpy_news(): """ From 9d5767dcd749a77143eea78fe55edd64579debdc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Bartolom=C3=A9?= Date: Sat, 12 Jun 2021 14:36:18 +0000 Subject: [PATCH 15/23] fixed search_quotes (#395,#390,#374,#391,#392) --- investpy/search.py | 50 +++++++++++++++++++++++++--------------------- 1 file changed, 27 insertions(+), 23 deletions(-) diff --git a/investpy/search.py b/investpy/search.py index 6581c61..b620432 100644 --- a/investpy/search.py +++ b/investpy/search.py @@ -5,9 +5,9 @@ from unidecode import unidecode -from .utils import constant as cst from .utils.search_obj import SearchObj from .utils.extra import random_user_agent +from .utils.constant import PRODUCT_FILTERS, COUNTRY_FILTERS, PAIR_FILTERS, FLAG_FILTERS def search_quotes(text, products=None, countries=None, n_results=None): @@ -78,11 +78,11 @@ class instances, unless `n_results` is set to 1, where just a single :obj:`inves except: raise ValueError("ERR#0130: the introduced products filter must be a list of str in order to be valid.") - condition = set(products).issubset(cst.PRODUCT_FILTERS.keys()) + condition = set(products).issubset(PRODUCT_FILTERS.keys()) if condition is False: - raise ValueError('ERR#0095: products filtering parameter possible values are: \"' + ', '.join(cst.PRODUCT_FILTERS.keys()) + '\".') + raise ValueError('ERR#0095: products filtering parameter possible values are: \"' + ', '.join(PRODUCT_FILTERS.keys()) + '\".') - products = [cst.PRODUCT_FILTERS[product] for product in products] + products = [PRODUCT_FILTERS[product] for product in products] if countries: try: @@ -90,11 +90,11 @@ class instances, unless `n_results` is set to 1, where just a single :obj:`inves except: raise ValueError("ERR#0131: the introduced countries filter must be a list of str in order to be valid.") - condition = set(countries).issubset(cst.COUNTRY_FILTERS.keys()) + condition = set(countries).issubset(COUNTRY_FILTERS.keys()) if condition is False: - raise ValueError('ERR#0129: countries filtering parameter possible values are: \"' + ', '.join(cst.COUNTRY_FILTERS.keys()) + '\".') + raise ValueError('ERR#0129: countries filtering parameter possible values are: \"' + ', '.join(COUNTRY_FILTERS.keys()) + '\".') - countries = [cst.COUNTRY_FILTERS[country] for country in countries] + countries = [COUNTRY_FILTERS[country] for country in countries] params = { 'search_text': text, @@ -104,7 +104,7 @@ class instances, unless `n_results` is set to 1, where just a single :obj:`inves 'offset': 0 } - head = { + headers = { "User-Agent": random_user_agent(), "X-Requested-With": "XMLHttpRequest", "Accept": "text/html", @@ -121,10 +121,10 @@ class instances, unless `n_results` is set to 1, where just a single :obj:`inves user_limit = True if n_results is not None else False while True: - req = requests.post(url, headers=head, data=params) + req = requests.post(url, headers=headers, data=params) if req.status_code != 200: - raise ConnectionError("ERR#0015: error " + str(req.status_code) + ", try again later.") + raise ConnectionError(f"ERR#0015: error {req.status_code}, try again later.") data = req.json() @@ -141,16 +141,18 @@ class instances, unless `n_results` is set to 1, where just a single :obj:`inves country, pair_type = quote['flag'], quote['pair_type'] if countries is not None: - if quote['flag'] in countries: - country = cst.FLAG_FILTERS[quote['flag']] - else: + if quote['flag'] not in countries: continue if products is not None: - if quote['pair_type'] in products: - pair_type = cst.PAIR_FILTERS[quote['pair_type']] - else: + if quote['pair_type'] not in products: continue + + pair_type = PAIR_FILTERS[quote['pair_type']] + + country = None + if pair_type not in ['cryptos', 'commodities']: + country = FLAG_FILTERS[quote['flag']] if quote['flag'] in FLAG_FILTERS else quote['flag'] search_obj = SearchObj(id_=quote['pairId'], name=quote['name'], symbol=quote['symbol'], country=country, tag=quote['link'], @@ -237,18 +239,17 @@ def search_events(text, importances=None, countries=None, n_results=None): country, pair_type = quote['flag'], quote['pair_type'] if importances is not None: - if quote['pair_type'] in importances: - print("TODO") - ## pair_type = cst.PAIR_FILTERS[quote['pair_type']] - else: + if quote['pair_type'] not in importances: continue if countries is not None: - if quote['flag'] in countries: - country = cst.FLAG_FILTERS[quote['flag']] - else: + if quote['flag'] not in countries: continue + print("TODO") + ## pair_type = PAIR_FILTERS[quote['pair_type']] + ## country = FLAG_FILTERS[quote['flag']] + search_event = SearchObj(id_=quote['pairId'], name=quote['name'], symbol=quote['symbol'], country=country, tag=quote['link'], pair_type=pair_type, exchange=quote['exchange']) @@ -262,4 +263,7 @@ def search_events(text, importances=None, countries=None, n_results=None): if len(search_results) >= n_results or len(search_results) >= total_results or params['offset'] >= total_results: break + if len(search_results) < 1: + raise RuntimeError("ERR#0093: no results found on Investing.com for the introduced query.") + return search_results[:n_results] From 3b3d963c35f7dc14613cacfc5eba02edcc50c479 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Bartolom=C3=A9?= Date: Sat, 12 Jun 2021 14:37:37 +0000 Subject: [PATCH 16/23] added retrieve_currency to tests #390 --- tests/test_investpy.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/test_investpy.py b/tests/test_investpy.py index 132e6f9..bdda819 100644 --- a/tests/test_investpy.py +++ b/tests/test_investpy.py @@ -1320,8 +1320,7 @@ def test_investpy_search(): for date in dates: assert result.retrieve_historical_data(from_date=date['from_date'], to_date=date['to_date']) is not None - assert result.retrieve_information() is not None - + assert result.retrieve_currency() is not None assert result.retrieve_technical_indicators() is not None financial_products = [ From 9c23587a4acc4b397324767ec3511e1020a85c3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Bartolom=C3=A9?= Date: Sat, 12 Jun 2021 14:47:44 +0000 Subject: [PATCH 17/23] temp fix due to Investing HTML inconsistency (#172,#181,#381,#390) --- investpy/utils/search_obj.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/investpy/utils/search_obj.py b/investpy/utils/search_obj.py index 137ce2e..bc161fc 100644 --- a/investpy/utils/search_obj.py +++ b/investpy/utils/search_obj.py @@ -364,6 +364,10 @@ def retrieve_currency(self): """ + # Temporary workaround to fix build + if self.pair_type != 'stocks': + return 'NOT_AVAILABLE_YET' + url = f"https://www.investing.com{self.tag}" headers = { From 659a27b2f2191e46f2e0d7c989b2a3de26e99125 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Bartolom=C3=A9?= Date: Sat, 12 Jun 2021 18:00:36 +0000 Subject: [PATCH 18/23] included timeout between pytest functions to avoid error 10054 --- tests/test_investpy.py | 40 ++++++++++++++++++++++------------- tests/test_investpy_errors.py | 39 ++++++++++++++++++++++------------ 2 files changed, 50 insertions(+), 29 deletions(-) diff --git a/tests/test_investpy.py b/tests/test_investpy.py index bdda819..44b682a 100644 --- a/tests/test_investpy.py +++ b/tests/test_investpy.py @@ -3,6 +3,8 @@ import pytest +import time + import investpy @@ -212,6 +214,8 @@ def test_investpy_stocks(): investpy.search_stocks(by='name', value='BBVA') + time.sleep(5) + def test_investpy_funds(): """ @@ -346,6 +350,8 @@ def test_investpy_funds(): investpy.search_funds(by='name', value='bbva') + time.sleep(5) + def test_investpy_etfs(): """ @@ -468,6 +474,8 @@ def test_investpy_etfs(): investpy.search_etfs(by='name', value='bbva') + time.sleep(5) + def test_investpy_indices(): """ @@ -590,6 +598,8 @@ def test_investpy_indices(): investpy.search_indices(by='name', value='ibex') + time.sleep(5) + def test_investpy_currency_crosses(): """ @@ -768,6 +778,8 @@ def test_investpy_currency_crosses(): investpy.search_currency_crosses(by='base', value='EUR') + time.sleep(5) + def test_investpy_bonds(): """ @@ -888,6 +900,8 @@ def test_investpy_bonds(): investpy.search_bonds(by='name', value='Spain') + time.sleep(5) + def test_investpy_commodities(): """ @@ -1014,6 +1028,8 @@ def test_investpy_commodities(): investpy.search_commodities(by='name', value='gold') + time.sleep(5) + def test_investpy_cryptos(): """ @@ -1120,6 +1136,8 @@ def test_investpy_cryptos(): investpy.search_cryptos(by='name', value='bitcoin') + time.sleep(5) + def test_investpy_certificates(): """ @@ -1246,6 +1264,8 @@ def test_investpy_certificates(): investpy.search_certificates(by='name', value='BNP') + time.sleep(5) + def test_investpy_search(): """ @@ -1333,6 +1353,8 @@ def test_investpy_search(): assert search_result.retrieve_information() is not None + time.sleep(5) + def test_investpy_news(): """ @@ -1369,6 +1391,8 @@ def test_investpy_news(): from_date=param['from_date'], to_date=param['to_date']) + time.sleep(5) + def test_investpy_technical(): """ @@ -1401,18 +1425,4 @@ def test_investpy_technical(): product_type=param['product_type'], interval=param['interval']) - -if __name__ == '__main__': - test_investpy() - test_investpy_stocks() - test_investpy_funds() - test_investpy_etfs() - test_investpy_indices() - test_investpy_currency_crosses() - test_investpy_bonds() - test_investpy_commodities() - test_investpy_cryptos() - test_investpy_certificates() - test_investpy_search() - test_investpy_news() - test_investpy_technical() + time.sleep(5) diff --git a/tests/test_investpy_errors.py b/tests/test_investpy_errors.py index fa693f5..c114d63 100644 --- a/tests/test_investpy_errors.py +++ b/tests/test_investpy_errors.py @@ -3,6 +3,8 @@ import pytest +import time + import investpy @@ -645,6 +647,8 @@ def test_stocks_errors(): except: pass + time.sleep(5) + def test_funds_errors(): """ @@ -1101,6 +1105,8 @@ def test_funds_errors(): investpy.search_funds(by=param['by'], value=param['value']) except: pass + + time.sleep(5) def test_etfs_errors(): @@ -1547,6 +1553,8 @@ def test_etfs_errors(): except: pass + time.sleep(5) + def test_indices_errors(): """ @@ -1992,6 +2000,8 @@ def test_indices_errors(): except: pass + time.sleep(5) + def test_currency_crosses_errors(): """ @@ -2377,6 +2387,8 @@ def test_currency_crosses_errors(): except: pass + time.sleep(5) + def test_bonds_errors(): """ @@ -2703,6 +2715,8 @@ def test_bonds_errors(): except: pass + time.sleep(5) + def test_commodities_errors(): """ @@ -3118,6 +3132,8 @@ def test_commodities_errors(): except: pass + time.sleep(5) + def test_crypto_errors(): """ @@ -3405,6 +3421,8 @@ def test_crypto_errors(): except: pass + time.sleep(5) + def test_certificate_errors(): """ @@ -3837,6 +3855,8 @@ def test_certificate_errors(): except: pass + time.sleep(5) + def test_search_errors(): """ @@ -3945,6 +3965,8 @@ def test_search_errors(): except: pass + time.sleep(5) + def test_news_errors(): """ @@ -4083,6 +4105,8 @@ def test_news_errors(): except: pass + time.sleep(5) + def test_technical_errors(): """ @@ -4189,17 +4213,4 @@ def test_technical_errors(): except: pass - -if __name__ == '__main__': - test_stocks_errors() - test_funds_errors() - test_etfs_errors() - test_indices_errors() - test_currency_crosses_errors() - test_bonds_errors() - test_commodities_errors() - test_crypto_errors() - test_certificate_errors() - test_search_errors() - test_technical_errors() - test_news_errors() + time.sleep(5) From fcf3c4e562737fc9205070b6cb598923844ea9c2 Mon Sep 17 00:00:00 2001 From: Alvaro Bartolome Date: Sat, 12 Jun 2021 20:22:50 +0200 Subject: [PATCH 19/23] removed pytest timeout & skipped python3.6 ci --- .github/workflows/run_tests.yml | 2 +- tests/test_investpy.py | 26 -------------------------- tests/test_investpy_errors.py | 26 -------------------------- 3 files changed, 1 insertion(+), 53 deletions(-) diff --git a/.github/workflows/run_tests.yml b/.github/workflows/run_tests.yml index b809ac1..4e02728 100644 --- a/.github/workflows/run_tests.yml +++ b/.github/workflows/run_tests.yml @@ -14,7 +14,7 @@ jobs: fail-fast: false matrix: os: [ubuntu-latest, windows-latest] - python-version: [3.6, 3.7, 3.8, 3.9] + python-version: [3.7, 3.8, 3.9] steps: - uses: actions/checkout@v2 diff --git a/tests/test_investpy.py b/tests/test_investpy.py index 44b682a..edc2bf4 100644 --- a/tests/test_investpy.py +++ b/tests/test_investpy.py @@ -3,8 +3,6 @@ import pytest -import time - import investpy @@ -214,8 +212,6 @@ def test_investpy_stocks(): investpy.search_stocks(by='name', value='BBVA') - time.sleep(5) - def test_investpy_funds(): """ @@ -350,8 +346,6 @@ def test_investpy_funds(): investpy.search_funds(by='name', value='bbva') - time.sleep(5) - def test_investpy_etfs(): """ @@ -474,8 +468,6 @@ def test_investpy_etfs(): investpy.search_etfs(by='name', value='bbva') - time.sleep(5) - def test_investpy_indices(): """ @@ -598,8 +590,6 @@ def test_investpy_indices(): investpy.search_indices(by='name', value='ibex') - time.sleep(5) - def test_investpy_currency_crosses(): """ @@ -778,8 +768,6 @@ def test_investpy_currency_crosses(): investpy.search_currency_crosses(by='base', value='EUR') - time.sleep(5) - def test_investpy_bonds(): """ @@ -900,8 +888,6 @@ def test_investpy_bonds(): investpy.search_bonds(by='name', value='Spain') - time.sleep(5) - def test_investpy_commodities(): """ @@ -1028,8 +1014,6 @@ def test_investpy_commodities(): investpy.search_commodities(by='name', value='gold') - time.sleep(5) - def test_investpy_cryptos(): """ @@ -1136,8 +1120,6 @@ def test_investpy_cryptos(): investpy.search_cryptos(by='name', value='bitcoin') - time.sleep(5) - def test_investpy_certificates(): """ @@ -1264,8 +1246,6 @@ def test_investpy_certificates(): investpy.search_certificates(by='name', value='BNP') - time.sleep(5) - def test_investpy_search(): """ @@ -1353,8 +1333,6 @@ def test_investpy_search(): assert search_result.retrieve_information() is not None - time.sleep(5) - def test_investpy_news(): """ @@ -1391,8 +1369,6 @@ def test_investpy_news(): from_date=param['from_date'], to_date=param['to_date']) - time.sleep(5) - def test_investpy_technical(): """ @@ -1424,5 +1400,3 @@ def test_investpy_technical(): country=param['country'], product_type=param['product_type'], interval=param['interval']) - - time.sleep(5) diff --git a/tests/test_investpy_errors.py b/tests/test_investpy_errors.py index c114d63..0d0b2f4 100644 --- a/tests/test_investpy_errors.py +++ b/tests/test_investpy_errors.py @@ -3,8 +3,6 @@ import pytest -import time - import investpy @@ -647,8 +645,6 @@ def test_stocks_errors(): except: pass - time.sleep(5) - def test_funds_errors(): """ @@ -1106,8 +1102,6 @@ def test_funds_errors(): except: pass - time.sleep(5) - def test_etfs_errors(): """ @@ -1553,8 +1547,6 @@ def test_etfs_errors(): except: pass - time.sleep(5) - def test_indices_errors(): """ @@ -2000,8 +1992,6 @@ def test_indices_errors(): except: pass - time.sleep(5) - def test_currency_crosses_errors(): """ @@ -2387,8 +2377,6 @@ def test_currency_crosses_errors(): except: pass - time.sleep(5) - def test_bonds_errors(): """ @@ -2715,8 +2703,6 @@ def test_bonds_errors(): except: pass - time.sleep(5) - def test_commodities_errors(): """ @@ -3132,8 +3118,6 @@ def test_commodities_errors(): except: pass - time.sleep(5) - def test_crypto_errors(): """ @@ -3421,8 +3405,6 @@ def test_crypto_errors(): except: pass - time.sleep(5) - def test_certificate_errors(): """ @@ -3855,8 +3837,6 @@ def test_certificate_errors(): except: pass - time.sleep(5) - def test_search_errors(): """ @@ -3965,8 +3945,6 @@ def test_search_errors(): except: pass - time.sleep(5) - def test_news_errors(): """ @@ -4105,8 +4083,6 @@ def test_news_errors(): except: pass - time.sleep(5) - def test_technical_errors(): """ @@ -4212,5 +4188,3 @@ def test_technical_errors(): interval=param['interval']) except: pass - - time.sleep(5) From a1cf1c01938ac228c5a5dbc4f4b05ba02bcc0f26 Mon Sep 17 00:00:00 2001 From: Alvaro Bartolome Date: Sun, 13 Jun 2021 12:04:57 +0200 Subject: [PATCH 20/23] fixed retrieve_currency for outdated products (#172,#181,#381,#390) --- investpy/utils/search_obj.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/investpy/utils/search_obj.py b/investpy/utils/search_obj.py index bc161fc..28d45d6 100644 --- a/investpy/utils/search_obj.py +++ b/investpy/utils/search_obj.py @@ -364,10 +364,6 @@ def retrieve_currency(self): """ - # Temporary workaround to fix build - if self.pair_type != 'stocks': - return 'NOT_AVAILABLE_YET' - url = f"https://www.investing.com{self.tag}" headers = { @@ -383,11 +379,18 @@ def retrieve_currency(self): if req.status_code != 200: raise ConnectionError(f"ERR#0015: error {req.status_code}, try again later.") + # Just change this list once the update is included for all the other products + updated_for = ['stocks'] + outdated_for = ['etfs', 'commodities', 'currencies', 'funds', 'bonds', 'cryptos', 'certificates', 'indices', 'fxfutures'] + root_ = fromstring(req.text) - path_ = root_.xpath("//div[contains(@class, 'instrument-metadata_currency')]/span") + updated_path = root_.xpath("//div[contains(@class, 'instrument-metadata_currency')]/span") + outdated_path = root_.xpath("//div[@id='quotes_summary_current_data']/div/div/div[contains(@class, 'bottom')]/span[@class='bold']") - if not path_: + if not updated_path and not outdated_path: raise RuntimeError("ERR#0004: data retrieval error while scraping.") + + path_, investing_updated = (updated_path, True) if updated_path else (outdated_path, False) self.default_currency = path_[-1].text_content().strip() return self.default_currency From 4ec7789241749b93f36ebd7dfb029c632d783ff6 Mon Sep 17 00:00:00 2001 From: Alvaro Bartolome Date: Sun, 13 Jun 2021 12:17:54 +0200 Subject: [PATCH 21/23] 1.0.6 -> 1.0.7, updated docs & detailed search_quotes example --- README.md | 101 ++++++++++++++++++++++------- docs/source/_info/installation.rst | 2 +- docs/source/conf.py | 2 +- investpy/__init__.py | 5 +- setup.py | 4 +- 5 files changed, 86 insertions(+), 28 deletions(-) diff --git a/README.md b/README.md index 9fafc9d..89009f0 100644 --- a/README.md +++ b/README.md @@ -51,6 +51,9 @@ some basic functionality will be sorted out with sample Python code blocks. Addi can be found under [examples/](https://github.com/alvarobartt/investpy/tree/master/examples) directory, which contains a collection of Jupyter Notebooks on how to use investpy and handle its data. +:pushpin: __Note that `investpy.search_quotes` is the only function that ensures that the data is updated and aligned 1:1 with +the data provided by Investing.com!__ + ### :chart_with_upwards_trend: Recent/Historical Data Retrieval investpy allows the user to **download both recent and historical data from any financial product indexed** @@ -79,7 +82,7 @@ Date To get to know all the available recent and historical data extraction functions provided by investpy, and also, parameter tuning, please read the docs. -### :mag: Search Data +### :mag: Search Live Data **Investing.com search engine is completely integrated** with investpy, which means that any available financial product (quote) can be easily found. The search function allows the user to tune the parameters @@ -90,34 +93,88 @@ presented in the following piece of code: ```python import investpy -search_results = investpy.search_quotes(text='apple', - products=['stocks'], - countries=['united states'], - n_results=10) +search_result = investpy.search_quotes(text='apple', products=['stocks'], + countries=['united states'], n_results=1) +print(search_result) +``` +```{r, engine='python', count_lines} +{"id_": 6408, "name": "Apple Inc", "symbol": "AAPL", "country": "united states", "tag": "/equities/apple-computer-inc", "pair_type": "stocks", "exchange": "NASDAQ"} + ``` -Retrieved search results will be a `list` of `investpy.utils.search_obj.SearchObj` class instances. To get to know -which are the available functions and attributes of the returned search results, please read the related +Retrieved search results will be a `list` of `investpy.utils.search_obj.SearchObj` class instances, unless +`n_results` is set to 1, when just a single `investpy.utils.search_obj.SearchObj` class instance will be returned. +To get to know which are the available functions and attributes of the returned search results, please read the related documentation at [Search Engine Documentation](https://investpy.readthedocs.io/search_api.html). So on, those -search results let the user retrieve both recent and historical data from that concrete product, its -information, etc., as presented in the piece of code below: +search results let the user retrieve both recent and historical data, its information, the technical indicators, +the default currency, etc., as presented in the piece of code below: + +```python +recent_data = search_result.retrieve_recent_data() +print(recent_data.head()) +``` +```{r, engine='python', count_lines} + Open High Low Close Volume Change Pct +Date +2021-05-13 124.58 126.15 124.26 124.97 105861000 1.79 +2021-05-14 126.25 127.89 125.85 127.45 81918000 1.98 +2021-05-17 126.82 126.93 125.17 126.27 74245000 -0.93 +2021-05-18 126.56 126.99 124.78 124.85 63343000 -1.12 +2021-05-19 123.16 124.92 122.86 124.69 92612000 -0.13 + +``` + +```python +historical_data = search_result.retrieve_historical_data(from_date='01/01/2019', to_date='01/01/2020') +print(historical_data.head()) +``` +```{r, engine='python', count_lines} + Open High Low Close Volume Change Pct +Date +2020-01-02 74.06 75.15 73.80 75.09 135647008 2.28 +2020-01-03 74.29 75.14 74.13 74.36 146536000 -0.97 +2020-01-06 73.45 74.99 73.19 74.95 118579000 0.80 +2020-01-07 74.96 75.22 74.37 74.60 111511000 -0.47 +2020-01-08 74.29 76.11 74.29 75.80 132364000 1.61 + +``` + +```python +information = search_result.retrieve_information() +print(information) +``` +```{r, engine='python', count_lines} +{'prevClose': 126.11, 'dailyRange': '126.1-127.44', 'revenue': 325410000000, 'open': 126.53, 'weekRange': '83.14-145.09', 'eps': 4.46, 'volume': 53522373, 'marketCap': 2130000000000, 'dividend': '0.88(0.70%)', 'avgVolume': 88858729, 'ratio': 28.58, 'beta': 1.2, 'oneYearReturn': '50.35%', 'sharesOutstanding': 16687631000, 'nextEarningDate': '03/08/2021'} + +``` + +```python +default_currency = search_result.retrieve_currency() +print(default_currency) +``` +```{r, engine='python', count_lines} +'USD' + +``` ```python - for search_result in search_results[:1]: - print(search_result) - search_result.retrieve_historical_data(from_date='01/01/2019', to_date='01/01/2020') - print(search_result.data.head()) +technical_indicators = search_result.retrieve_technical_indicators(interval='daily') +print(technical_indicators) ``` ```{r, engine='python', count_lines} -{"id_": 6408, "name": "Apple Inc", "symbol": "AAPL", "country": "united states", "tag": "apple-computer-inc", "pair_type": "stocks", "exchange": "NASDAQ"} - - Open High Low Close Volume -Date -2019-01-02 154.89 158.85 154.23 157.92 37039736 -2019-01-03 143.98 145.72 142.00 142.19 91312192 -2019-01-04 144.53 148.55 143.80 148.26 58607072 -2019-01-07 148.70 148.83 145.90 147.93 54777764 -2019-01-08 149.56 151.82 148.52 150.75 41025312 + indicator signal value +0 RSI(14) neutral 52.1610 +1 STOCH(9,6) buy 63.7110 +2 STOCHRSI(14) overbought 100.0000 +3 MACD(12,26) sell -0.6700 +4 ADX(14) neutral 21.4750 +5 Williams %R buy -20.9430 +6 CCI(14) buy 67.1057 +7 ATR(14) less_volatility 1.7871 +8 Highs/Lows(14) buy 0.4279 +9 Ultimate Oscillator sell 47.3620 +10 ROC buy 1.5150 +11 Bull/Bear Power(13) buy 1.3580 ``` diff --git a/docs/source/_info/installation.rst b/docs/source/_info/installation.rst index 61b5020..8dc3866 100644 --- a/docs/source/_info/installation.rst +++ b/docs/source/_info/installation.rst @@ -5,7 +5,7 @@ Installation .. note:: - After installing the package you are now available to use it! As investpy's latest release is 1.0.6 the installation is + After installing the package you are now available to use it! As investpy's latest release is 1.0.7 the installation is optimized for it. If you try installing another investpy release, some features may not work. First Installation diff --git a/docs/source/conf.py b/docs/source/conf.py index ff57c33..f2e036b 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -22,7 +22,7 @@ author = 'Alvaro Bartolome del Canto' # The full version, including alpha/beta/rc tags -release = '1.0.6' +release = '1.0.7' # -- General configuration --------------------------------------------------- diff --git a/investpy/__init__.py b/investpy/__init__.py index 051b14b..5c6eef6 100644 --- a/investpy/__init__.py +++ b/investpy/__init__.py @@ -2,7 +2,7 @@ # See LICENSE for details. __author__ = 'Alvaro Bartolome @ alvarobartt in GitHub' -__version__ = '1.0.6' +__version__ = '1.0.7' from .stocks import get_stocks, get_stocks_list, get_stocks_dict, get_stock_countries, get_stock_recent_data, \ get_stock_historical_data, get_stock_company_profile, get_stock_dividends, get_stock_information, get_stocks_overview, \ @@ -35,7 +35,8 @@ get_certificate_recent_data, get_certificate_historical_data, get_certificate_information, get_certificates_overview, \ search_certificates -from .search import search_quotes, search_events +from .search import search_quotes +# from .search import search_events from .news import economic_calendar diff --git a/setup.py b/setup.py index fc991a9..b6dfe3f 100644 --- a/setup.py +++ b/setup.py @@ -20,10 +20,10 @@ def requirements(filename): setup( name='investpy', - version='1.0.6', + version='1.0.7', packages=find_packages(), url='https://investpy.readthedocs.io/', - download_url='https://github.com/alvarobartt/investpy/archive/1.0.6.tar.gz', + download_url='https://github.com/alvarobartt/investpy/archive/1.0.7.tar.gz', license='MIT License', author='Alvaro Bartolome', author_email='alvarobdc@yahoo.com', From 05c99c92f7ec04fdbb54e838f42d0fb084c7798f Mon Sep 17 00:00:00 2001 From: Alvaro Bartolome Date: Sun, 13 Jun 2021 13:39:57 +0200 Subject: [PATCH 22/23] updated docs (using furo theme) & some improvements --- README.md | 8 +- docs/requirements.txt | 4 +- docs/source/_info/citation.md | 21 ++ docs/source/_info/contact_information.md | 10 + docs/source/_info/disclaimer.md | 11 +- docs/source/_info/faq.md | 17 +- docs/source/_info/funds.rst | 166 --------------- docs/source/_info/information.rst | 19 -- docs/source/_info/installation.md | 16 ++ docs/source/_info/installation.rst | 54 ----- docs/source/_info/introduction.md | 27 +++ docs/source/_info/introduction.rst | 61 ------ docs/source/_info/models.rst | 36 ---- docs/source/_info/related_projects.md | 13 ++ docs/source/_info/stocks.rst | 114 ----------- docs/source/_info/usage.md | 172 ++++++++++++++++ docs/source/_info/usage.rst | 250 ----------------------- docs/source/conf.py | 19 +- docs/source/index.rst | 17 +- 19 files changed, 296 insertions(+), 739 deletions(-) create mode 100644 docs/source/_info/citation.md create mode 100644 docs/source/_info/contact_information.md delete mode 100644 docs/source/_info/funds.rst delete mode 100644 docs/source/_info/information.rst create mode 100644 docs/source/_info/installation.md delete mode 100644 docs/source/_info/installation.rst create mode 100644 docs/source/_info/introduction.md delete mode 100644 docs/source/_info/introduction.rst delete mode 100644 docs/source/_info/models.rst create mode 100644 docs/source/_info/related_projects.md delete mode 100644 docs/source/_info/stocks.rst create mode 100644 docs/source/_info/usage.md delete mode 100644 docs/source/_info/usage.rst diff --git a/README.md b/README.md index 89009f0..9b50f26 100644 --- a/README.md +++ b/README.md @@ -5,8 +5,8 @@

Financial Data Extraction from Investing.com with Python

investpy is a Python package to retrieve data from [Investing.com](https://www.investing.com/), which provides data retrieval -from up to: 39952 stocks, 82221 funds, 11403 ETFs, 2029 currency crosses, 7797 indices, 688 bonds, 66 commodities, 250 certificates, -and 2812 cryptocurrencies. +from up to 39952 stocks, 82221 funds, 11403 ETFs, 2029 currency crosses, 7797 indices, 688 bonds, 66 commodities, 250 certificates, +and 4697 cryptocurrencies. investpy allows the user to download both recent and historical data from all the financial products indexed at Investing.com. **It includes data from all over the world**, from countries such as United States, France, India, Spain, Russia, or Germany, @@ -188,7 +188,7 @@ consider it. As already presented previously, **historical data retrieval using investpy is really easy**. The piece of code presented below shows how to retrieve the past years of historical data from Bitcoin (BTC). -````python +```python import investpy data = investpy.get_crypto_historical_data(crypto='bitcoin', @@ -196,7 +196,7 @@ data = investpy.get_crypto_historical_data(crypto='bitcoin', to_date='01/01/2019') print(data.head()) -```` +``` ```{r, engine='python', count_lines} Open High Low Close Volume Currency Date diff --git a/docs/requirements.txt b/docs/requirements.txt index 52243b6..695cd15 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,3 +1,3 @@ sphinx==2.4.4 -sphinx_rtd_theme==0.4.3 -recommonmark==0.6.0 \ No newline at end of file +recommonmark==0.6.0 +furo==2021.4.11b34 \ No newline at end of file diff --git a/docs/source/_info/citation.md b/docs/source/_info/citation.md new file mode 100644 index 0000000..b25b415 --- /dev/null +++ b/docs/source/_info/citation.md @@ -0,0 +1,21 @@ +## ๐Ÿ“ Citation + +When citing this repository on your scientific publications please use the following **BibTeX** citation: + +```bibtex +@misc{investpy, + author = {Alvaro Bartolome del Canto}, + title = {investpy - Financial Data Extraction from Investing.com with Python}, + year = {2018-2021}, + publisher = {GitHub}, + journal = {GitHub Repository}, + howpublished = {\url{https://github.com/alvarobartt/investpy}}, +} +``` + +When citing this repository on any other social media, please use the following citation: + +``investpy - Financial Data Extraction from Investing.com with Python developed by Alvaro Bartolome del Canto`` + +You should also mention the source from where the data is retrieved, Investing.com; even though it's already +included in the package short description title. diff --git a/docs/source/_info/contact_information.md b/docs/source/_info/contact_information.md new file mode 100644 index 0000000..d410337 --- /dev/null +++ b/docs/source/_info/contact_information.md @@ -0,0 +1,10 @@ +## ๐Ÿ‘จโ€๐Ÿ’ป Contact Information + +You can contact me at any of my social network profiles: + +- ๐Ÿ’ผ LinkedIn: https://linkedin.com/in/alvarobartt +- ๐Ÿฆ Twitter: https://twitter.com/alvarobartt +- ๐Ÿ™ GitHub: https://github.com/alvarobartt + +Or via email at alvarobartt@yahoo.com, even though this last one is not recommended +as mentioned in the FAQs. diff --git a/docs/source/_info/disclaimer.md b/docs/source/_info/disclaimer.md index d5d9bd3..43bfda2 100644 --- a/docs/source/_info/disclaimer.md +++ b/docs/source/_info/disclaimer.md @@ -1,7 +1,8 @@ -# Disclaimer +## โš ๏ธ Disclaimer -This Python Package has been made for research purposes in order to fit a needs that Investing.com does not cover, -so this package works like an Application Programming Interface (API) of Investing.com developed in an altruistic way. +This Python package has been made for **research purposes** to fit the needs that Investing.com does not cover, +so this package works like an Application Programming Interface (API) of Investing.com developed in an **altruistic way**. -Conclude that this package is not related in any way with Investing.com or any dependant company, the only requirement -for developing this package was to mention the source where data is retrieved. \ No newline at end of file +Conclude that **investpy is not affiliated in any way to Investing.com or any dependant company**, the only +requirement specified by Investing.com to develop this package was to "mention the source where data is +retrieved from". diff --git a/docs/source/_info/faq.md b/docs/source/_info/faq.md index edf1197..2a83053 100644 --- a/docs/source/_info/faq.md +++ b/docs/source/_info/faq.md @@ -1,4 +1,4 @@ -# Frequent Asked Questions - FAQs +# โ“ Frequent Asked Questions - FAQs In this section the Frequent Asked Questions are answered, so please read this section before posting a question or openning an issue since duplicates will not be solved or will be referenced to this section. Also, if you think that there are more possible FAQs, consider openning an issue in GitHub so to notify it, since if we all contribute this section can be clear enough so to ease question answering. @@ -12,14 +12,13 @@ As it is known, investpy gathers and retrieves data from Investing.com which is ## I am having problems while installing the package. -If you followed the [Installation Guide](https://github.com/alvarobartt/investpy/blob/master/README.md#Installation), you should be able to use investpy without having any problem, anyways, if you are stuck on it, open an issue at investpy issues tab so to let the developers know which is your problem in order to solve it as soon as possible. If you were not able to complete the installation, please check that you are running Python 3.5 at least and that you are installing the latest version available, if you are still having problems, open an issue. +If you followed the [Installation Guide](https://github.com/alvarobartt/investpy/blob/master/README.md#Installation), you should be able to use investpy without having any problem, anyways, if you are stuck on it, open an issue at investpy issues tab so to let the developers know which is your problem in order to solve it as soon as possible. If you were not able to complete the installation, please check that you are running at least Python 3.6 and that you are installing the latest version available, if you are still having problems, open an issue. ## How do I contribute to investpy? -Currently I am not admitting any Pull Request since investpy is under development, and so to keep a clean structure, I will be developing new functionalities until code is clean enough to let newcome contributors help. Anyways, the most effective tool you have in order to contribute to investpy are **issues** where you can give me new ideas or some functionallity you would like to see implemented in investpy. You can also use issues in order to report bugs or problems so to help investpy's development and consistency. - -## How do I reference investpy? - -Since investpy is an open source Python package, whenever you use it, would be nice from you to mention or comment where does the data comes from. This way, investpy can be spread among more users which will consequently improve package usage since more users can contribute to it due to the increasing reach to newcome developers. A sample reference is presented below: - -`investpy - a Python package for Financial Data Extraction from Investing.com developed by รlvaro Bartolomรฉ del Canto, alvarobartt @ GitHub` +As this is an open-source project it is **open to contributions, bug reports, bug fixes, documentation improvements, +enhancements, and ideas**. There is an open tab of [issues](https://github.com/alvarobartt/investpy/issues) where +anyone can open new issues if needed or navigate through them to solve them or contribute to its solving. +Remember that issues are not threads to describe multiple problems, this does not mean that issues can not +be discussed, but so to keep structured project management, the same issue should not describe different +problems, just the main one and some nested/related errors that may be found. diff --git a/docs/source/_info/funds.rst b/docs/source/_info/funds.rst deleted file mode 100644 index 0a386f8..0000000 --- a/docs/source/_info/funds.rst +++ /dev/null @@ -1,166 +0,0 @@ -Funds -===== - -A fund is a pool of money that is allocated for a specific purpose. A fund can be established for any purpose -whatsoever, whether it is a city government setting aside money to build a new civic center, a college setting -aside money to award a scholarship, or an insurance company setting aside money to pay its customersโ€™ claims. - -A fund is a pool of money set aside for a specific purpose, those pools can are often invested and professionally -managed and some common types of funds include pension funds, insurance funds, foundations, and endowments. - -Individuals, businesses, and governments all use funds to set aside money. Individuals might establish an emergency -fund or rainy-day fund to pay for unforeseen expenses or a trust fund to set aside money for a specific person. - -Source: *Investopedia* - -Getting Started ---------------- - -To get started using `investpy `_ you first need to install it as described on -:ref:`installation-label`. Once you have it installed you can proceed to use it in order to retrieve data from -funds, after importing the package as it follows: - -.. code-block:: python - - import investpy - -Listing -^^^^^^^ - -`investpy `_ offers some listing functions that allow the user to get the general -information of the indexed funds on `Investing.com `_ as that information is already -stored on CSV files generated automatically on the package installation. - -The user can either retrieve the whole :obj:`pandas.DataFrame` containing all the information stored on the CSV file, a -:obj:`list` containing just the names of the funds, which are the input parameters for the data retrieval functions; or -as a :obj:`dict` with all the available fields of information from the funds. - -Also there is a param called ``country`` which by default is None, which means that the fund listing to be retrieved -will include all the available countries (indexed in Investing.com); on the contrary, if the param ``country`` is an -available country, the returned fund information will be filtered by country. - -.. tip:: - - To get a listing of all the available countries you can use the function ``investpy.get_fund_countries()`` which - will return a :obj:`list` containing all the available country names which have funds as indexed on Investing.com. - - -.. code-block:: python - - # Retrieve all available funds information as a pandas.DataFrame - funds_df = investpy.get_funds(country=None) - # Retrieve a listing of all the available fund names - funds_list = investpy.get_funds_list(country=None) - # Retrieve a dictionary with all the funds and all of their information fields - funds_dict = investpy.get_funds_dict(country=None) - - -.. note:: - - The funds :obj:`pandas.DataFrame` contains internal package information that is useless for users, but it is provided - anyways. - -Since the data retrieval functions need both the fund name and the country from where that fund is, there is a function -to do so in order to let the user know which are the available countries and, so on, the available funds in those -countries. The functions presented below: `investpy.get_funds`, `investpy.get_funds_list` and `investpy.get_funds_dict` -have one optional parameter which is the country name so to retrieve just the :obj:`pandas.DataFrame`, :obj:`list` or -:obj:`dict` from all the available funds from the introduced country, respectively. - -Anyways, before applying that filter, the use of the function `investpy.get_fund_countries` is proposed in order to -retrieve all the available countries which have funds. - -.. code-block:: python - - countries = investpy.get_fund_countries() - - # Check if a country is either or not in the list & then get all the available funds from that country - if 'spain' in countries: - funds = investpy.get_funds_list(country='spain') - -So on, every country listed on the previous listing can be used for filtering funds. Note that the country param is -needed in data retrieval functions since more than one fund can share the same name but not in the same country. - -Fund Search -^^^^^^^^^^^ - -Before proceeding with the data retrieval functions an additional function is presented, since sometimes the user does -not have all the information for the fund to retrieve information from, so on, there is a function which allows the user -to search for funds with the specified value for the specified column/field. This function will return a `pandas.DataFrame` -with all the results found if they were found, if not, a `RuntimeError` will be raised. - -Since the returned object is a `pandas.DataFrame` in the following example both the function usage and further data -handling is presented in order to let the user know hos to use the results of the search on the data retrieval functions -in order to make it more easy to use. Note that you can either select the value you are searching from the - -.. code-block:: python - - search_result = investpy.search_funds(by='name', value='bbva') - - # Get both name and country via pandas.DataFrame index - index = 0 - name = search_result.loc[index, 'name'] - country = search_result.loc[index, 'country'] - - # Get both name and country via unique field such as isin - isin = 'ES0113211835' - name = search_result.loc[(search_result['isin'].str == isin).idxmax(), 'name'] - country = search_result.loc[(search_result['isin'].str == isin).idxmax(), 'country'] - - # Or get it manually via printing the resulting pandas.DataFrame - print(search_results) - - -Recent & Historical Data -^^^^^^^^^^^^^^^^^^^^^^^^ - -The main functions of `investpy `_ are focused on historical data extraction, and in -this concrete case, fund historical data retrieval functions will be explained and sorted out. As the main functionality -of the package is to retrieve data from Investing.com and format it so to access it via Python functions, some functions -have been developed in order to retrieve both recent and historical data. - -As to explain its usage an example is proposed to explain how does historical data retrieval functions work:: - - # Retrieves last month's data of 'Bankia Cauto Pp', which is a fund from 'Spain', as a pandas.DataFrame - df = investpy.get_fund_recent_data(fund='Bankia Cauto Pp', country='spain') - - # Retrieves historical data of 'Bankia Cauto Pp', which is a fund from 'Spain', on the specified date range as a pandas.DataFrame - df = investpy.get_fund_historical_data(fund='Bankia Cauto Pp', country='spain', from_date='01/01/2018', to_date='01/01/2019') - -Both functions need some parameters, even though some of them are *optional*, which means that the function -does not need the user to specify them as they already have a default value. - -Both parameters ``fund`` and ``country`` are mandatory, since they are the ones that specify which information should be -retrieved from Investing.com. Take into consideration that both parameters should match, which means that the name of -the fund should be a fund from the specified country, so if the introduced fund is not found on the specified country, -an error will be raised. - -When retrieving recent data from a fund, we can additionally specify if we want the output as a json object or not, by -setting the parameter ``as_json`` as either True or False, respectively. We can also set the ``order`` we want the -returned object to have based on dates, where ascending goes from the very first date retrieved until now, and -descending goes the other way. - -Furthermore, when it comes to historical data retrieval, we also need to specify both ``from_date`` and ``to_date`` -values, as they are mandatory. Both date values are :obj:`str` formatted as *dd/mm/yyyy*. - -.. tip:: - - If you are not familiar with funds you can either retrieve a :obj:`list` of the ones available as provided by - investpy or check the listing in `Investing.com Funds `_. - -Fund Information -^^^^^^^^^^^^^^^^ - -As an extra feature, via `investpy `_ you can retrieve information insights for the -specified fund on the specified country. This information is the one related to the introduced fund as indexed by -Investing.com which will give the user a wider sight on that concrete fund since values such as risk, rating or category -are provided by Investing.com and, so on, by investpy. - -Its usage is pretty simple since just the `fund` and the `country` are mandatory parameters, but there is also an -additional parameter which is `as_json` that can be either True or False whether the information wants to be returned as -a :obj:`pandas.DataFrame` or a :obj:`json`. - -.. code-block:: python - - # Retrieve information from the introduced fund in the specified country - data = investpy.get_fund_information(fund='Bankia Cauto Pp', country='spain') - diff --git a/docs/source/_info/information.rst b/docs/source/_info/information.rst deleted file mode 100644 index b32c27a..0000000 --- a/docs/source/_info/information.rst +++ /dev/null @@ -1,19 +0,0 @@ -Additional Information -====================== - -As this is an open source project it is open to contributions, bug reports, bug fixes, documentation improvements, -enhancements and ideas. On Github you can find an open tab of `issues `_ -where you can contribute by opening new issues if needed or contribute to its solving. - -Additionally, you can triage issues on `investpy Code Triage `_ where -you can both open and solve issues so the package can grow and improve faster as the issues solve relevant bugs, -problems or needs of the package. - -Feel free to contact package administrator via `email `_. - - -.. note:: - For further information or any question feel free to contact me via `email `_ You can also - check my `Medium Publication `_, - where I upload posts related to Data Science and to `investpy `_ basics on - Web Scraping. \ No newline at end of file diff --git a/docs/source/_info/installation.md b/docs/source/_info/installation.md new file mode 100644 index 0000000..4029359 --- /dev/null +++ b/docs/source/_info/installation.md @@ -0,0 +1,16 @@ +## ๐Ÿ› ๏ธ Installation + +To get this package working you will need to **install it via pip** (with a Python 3.6 version or higher) on the terminal by typing: + +``` +$ pip install investpy +``` + +Additionally, **if you want to use the latest investpy version instead of the stable one, you can install it from source** with the following command: + +``` +$ pip install git+https://github.com/alvarobartt/investpy.git@master +``` + +**The master branch ensures the user that the most updated version will always be working and fully operative** so as not to wait until the +the stable release comes out (which eventually may take some time depending on the number of issues to solve). \ No newline at end of file diff --git a/docs/source/_info/installation.rst b/docs/source/_info/installation.rst deleted file mode 100644 index 8dc3866..0000000 --- a/docs/source/_info/installation.rst +++ /dev/null @@ -1,54 +0,0 @@ -.. _installation-label: - -Installation -============ - -.. note:: - - After installing the package you are now available to use it! As investpy's latest release is 1.0.7 the installation is - optimized for it. If you try installing another investpy release, some features may not work. - -First Installation ------------------- - -In order to get this package working you will need to install it on its last version. To install the package on either way -you will need to have a Python 3.x version installed and pip or conda, so you can install Python packages from PyPI and from Anaconda -Cloud, respectively. So, to install the latest release of `investpy `_, you can either do it: - -* via Python Package Indexer (PyPI):: - - $ python -m pip install investpy - -* via Anaconda Cloud:: - - $ conda install investpy - -* from GitHub via PyPI:: - - $ python -m pip install https://github.com/alvarobartt/investpy/archive/master.zip - - -Update Package --------------- - -If you already had `investpy `_ installed and you want to update it you can do it: - -* via PyPI:: - - $ python -m pip install --upgrade investpy - -* via Anaconda Cloud:: - - $ conda update investpy - -* from GitHub via PyPi:: - - $ python -m pip install --upgrade https://github.com/alvarobartt/investpy/archive/master.zip - -All the dependencies are already listed on the setup file of the package, but to sum them up, when installing -`investpy `_, it will install the following dependencies: - -* `pandas 0.25.1 `_ -* `requests 2.22.0 `_ -* `lxml 4.4.1 `_ -* `unidecode 1.1.1 `_ diff --git a/docs/source/_info/introduction.md b/docs/source/_info/introduction.md new file mode 100644 index 0000000..9f8b154 --- /dev/null +++ b/docs/source/_info/introduction.md @@ -0,0 +1,27 @@ +## ๐Ÿ“š Introduction + +investpy is a Python package to retrieve data from [Investing.com](https://www.investing.com/), which provides data retrieval +from up to 39952 stocks, 82221 funds, 11403 ETFs, 2029 currency crosses, 7797 indices, 688 bonds, 66 commodities, 250 certificates, +and 4697 cryptocurrencies. + +investpy allows the user to download both recent and historical data from all the financial products indexed at Investing.com. +**It includes data from all over the world**, from countries such as United States, France, India, Spain, Russia, or Germany, +amongst many others. + +investpy seeks to be one of the most complete Python packages when it comes to financial data extraction to stop relying +on public/private APIs since investpy is **FREE** and has **NO LIMITATIONS**. These are some of the features that currently lead +investpy to be one of the most consistent packages when it comes to financial data retrieval. + +--- + +### ๐Ÿ“ฆ Data Source + +[Investing.com](https://www.investing.com/) is the main data source from which investpy retrieves the data. Investing.com is a +global financial portal and Internet brand owned by Fusion Media Ltd. which provides news, analysis, streaming quotes, +charts, technical data and financial tools about the global financial markets. + +--- + +### ๐Ÿ’ป Getting Started + +TODO diff --git a/docs/source/_info/introduction.rst b/docs/source/_info/introduction.rst deleted file mode 100644 index 80083a2..0000000 --- a/docs/source/_info/introduction.rst +++ /dev/null @@ -1,61 +0,0 @@ -Introduction -============ - -investpy is a Python package developed in order to retrieve all the available historical data from stocks/stocks, -funds and ETFs from Investing.com. As Investing.com does not have any API to retrieve historical data, the main goal -of this package is to allow users retrieve information from all the available financial products. - -investpy came to life due to the need of covering the existing shortcomings in terms of real time data retrieval from -stocks of the companies that make up the Spanish Stock Market, until the date there was no other package that provided -a data extraction model for stocks from the Spanish Stock Market. - -As time passed by, a decision was made on how investpy could be improved, and as the package was expected to have a high -scalability and thus cover all the data possibilities offered by Investing.com to the public, investpy is now trying to -expand the data it retrieves to make it more useful. - -Along this document some relevant features of `investpy `_ are going to be -sorted out and its functions are going to be explained in order to clarify its use. - -Getting Started ---------------- - -.. note:: - In order to get started using `investpy `_ you will need to have it installed, so - if you do not have it already, check :ref:`installation-label`. - -Once you have `investpy `_ installed, you can now proceed to use the package. The -first step is importing it at the top of your Python file as:: - - import investpy - -Currently the main functions of `investpy `_ support historical data retrieval -of stocks, funds and ETFs from all around the world (as indexed in Investing.com). Additionally to -historical data retrieval, investpy also offers additional data retrieval related to the indexed financial products. - -In order to clarify this concepts, some investpy functions are going to be presented, even though all of them -are going to be properly explained and sorted out on their respective appendix in the documentation or in the API -Reference. For example, a block of code in order to get to test investpy usage is presented:: - - import investpy - - - # Retrieve all the available stocks as a Python list - stocks = investpy.get_stocks_list() - - # Retrieve the recent historical data (past month) of a stock as a pandas.DataFrame on ascending date order - df = investpy.get_stock_recent_data(stock='bbva', country='spain', as_json=False, order='ascending') - - # Retrieve the company profile of the introduced stock on english - profile = investpy.get_stock_company_profile(stock='bbva', country='spain', language='english') - - -Data Source ------------ - -`Investing.com `_ is the main data source from which investpy retrieves the data. Investing.com is a -global financial portal and Internet brand owned by Fusion Media Ltd. which provides news, analysis, streaming quotes, -charts, technical data and financial tools about the global financial markets. - -So as, the decision of choosing Investing.com as the data source is based on its reliability and also because it is one of -the few web pages that provide detailed data from spanish markets, as it was the main focus when determining to -develop the package as explained previously. \ No newline at end of file diff --git a/docs/source/_info/models.rst b/docs/source/_info/models.rst deleted file mode 100644 index 4cd5540..0000000 --- a/docs/source/_info/models.rst +++ /dev/null @@ -1,36 +0,0 @@ -Models -====== - -Data Model ----------- - -As the retrieved historical data is common to every financial product that investpy extracts data from, only a model -class has been created in order to store the day-a-day historical data. - -So in we define a model in where every value corresponds to each value of the OHLC (Open-High-Low-Close) nomenclature -(except on stocks, that it also includes the volume) and it looks like:: - - def __init__(self, date_, open_, high_, low_, close_, volume_, currency_): - self.date = date_ - self.open = open_ - self.high = high_ - self.low = low_ - self.close = close_ - self.volume = volume_ - self.currency_ = currency_ - - -As their names indicate, OHLC values refer to opening, highest, lowest and closing values of the market on a trading -day, respectively. And the volume value refers to the number of shares traded in a security day. - - -.. note:: - - The Data model is not usable as it is just a class used for the inner package, transparent to the user. It is used - in order to categorize each retrieved value from Investing.com and then to define its structure and, so on, the - structure that either the resulting pandas.DataFrame or JSON file will be based on. - -Search Model ------------- - -TODO \ No newline at end of file diff --git a/docs/source/_info/related_projects.md b/docs/source/_info/related_projects.md new file mode 100644 index 0000000..5822e16 --- /dev/null +++ b/docs/source/_info/related_projects.md @@ -0,0 +1,13 @@ +## ๐Ÿ—‚๏ธ Related projects + +Since investpy is intended to retrieve data from different financial products as indexed in Investing.com, +the **development of some support modules which implement an additional functionality based on investpy data**, +is presented. Note that **anyone can contribute to this section** by creating any package, module, or utility that +uses investpy. So on, the ones already created are going to be presented, since they are intended to be used +combined with investpy: + +- [pyrtfolio](https://github.com/alvarobartt/pyrtfolio/): is a Python package to generate stock portfolios. +- [trendet](https://github.com/alvarobartt/trendet/): is a Python package for trend detection on stock time-series data. + +If you developed an interesting/useful project based on investpy data, please open an issue to let me know to +include it in this section. diff --git a/docs/source/_info/stocks.rst b/docs/source/_info/stocks.rst deleted file mode 100644 index bf86ead..0000000 --- a/docs/source/_info/stocks.rst +++ /dev/null @@ -1,114 +0,0 @@ -Stocks/Equities -=============== - -A **stock** (also known as "shares" or "equities") is a type of security that signifies proportionate ownership in the -issuing corporation. This entitles the stockholder to that proportion of the corporation's assets and earnings. - -Stocks are bought and sold predominantly on stock exchanges, though there can be private sales as well, and are the -foundation of nearly every portfolio. These transactions have to conform to government regulations which are meant to -protect investors from fraudulent practices. Historically, they have outperformed most other investments over the long -run. These investments can be purchased from most online stock brokers. - -Source: *Investopedia* - -Getting Started ---------------- - -To get started using `investpy `_ you first need to install it as described on -:ref:`installation-label`. Once you have it installed you can proceed to use it in order to retrieve data from -stocks, after importing the package as it follows: - -.. code-block:: python - - import investpy - -Listing -^^^^^^^ - -`investpy `_ offers some listing functions that allow the user to get the general -information of the indexed stocks on `Investing.com `_ as that information is already -stored on CSV files generated automatically on the package installation. - -We can either retrieve the whole :obj:`pandas.DataFrame` containing all the information stored on the CSV file or a -:obj:`list` containing just the symbols of the stocks, which are the input parameters for the data retrieval functions. - -Also there is a param called ``country`` which by default is None, which means that the stock listing to be retrieved -will include all the available countries (indexed in Investing.com); on the contrary, if the param ``country`` is an -available country, the returned stock information will be filtered by country. - -.. tip:: - - To get a listing of all the available countries you can use the function ``investpy.get_stock_countries()`` which - will return a :obj:`list` containing all the available country names which have stocks as indexed on Investing.com. - - -.. code-block:: python - - # Retrieve all available stocks information as a pandas.DataFrame - stocks_df = investpy.get_stocks(country=None) - # Retrieve a listing of all the available stock symbols - stocks_list = investpy.get_stocks_list(country=None) - -Recent & Historical Data -^^^^^^^^^^^^^^^^^^^^^^^^ - -The main functions of `investpy `_ are focused on historical data extraction, -stocks in this case. As the main functionality of the package is to retrieve data from Investing.com, so on, -some functions have been developed in order to retrieve both recent and historical data. - -As to explain its usage an example is proposed to present historical data retrieval functions:: - - # Retrieves the recent data of BBVA (last month) a spanish stock, as a pandas.DataFrame on ascending order - df = investpy.get_stock_recent_data(stock='bbva', country='spain', as_json=False, order='ascending') - - # Retrieves the historical data of BBVA, a spanish stock, on the specified date range as a pandas.DataFrame on ascending order - df = investpy.get_stock_historical_data(stock='bbva', country='spain', from_date='01/01/2018', to_date='01/01/2019', as_json=False, order='ascending') - -As we already saw, both functions take some parameters, but some of them are *optional*, which means that the function -does not need the user to specify them as they already have a default value. - -Both parameters ``stock`` and ``country`` are mandatory, since they are the ones that specify which information should be -retrieved from Investing.com. Consider that both parameters should match, which means that the symbols of the stock should -be an stock from the specified country, if the stock is not found on the specified country, an error will be raised. - -When retrieving recent data from an stock, we can additionally specify if we want the output as a json object or not, by -setting the parameter ``as_json`` as either True or False, respectively. We can also set the ``order`` we want the -returned object to have based on dates, where ascending goes from the very first date retrieved until now, and -descending goes the other way. - -Furthermore, when it comes to historical data retrieval, we also need to specify both ``from_date`` and ``to_date`` -values, as they are mandatory. Both date values are :obj:`str` formatted as *dd/mm/yyyy*. - -.. tip:: - - If you are not familiar with stocks you can either retrieve a listing of the ones - available or check the one presented in `Investing.com Equities `_. - -Company Profile -^^^^^^^^^^^^^^^ - -As an extra feature, via `investpy `_ you can retrieve the company profile from a -company in order to either classify or analyse them based on the information these companies publicly provide, as it -is a self-made description of the company. - -.. code-block:: python - - investpy.get_stock_company_profile(stock='bbva', country='spain', language='english') - -As explained before, when it comes to data retrieval, both ``stock`` and ``country`` parameters are mandatory, and -should match; as the default value for the ``language`` of the retrieved company profile is *english* (as `Investing.com `_ -provides company profiles written in english), but besides that, the function -also retrieves the company profile on *spanish* from `Bolsa de Madrid `_, -which is the additional resource used along this package. - -.. warning:: - - This function is just available for spanish stocks, since `investpy `_ was - first created just for Spanish Stocks, Funds and ETFs retrieval. Future coverage for world stocks company - profiles is intended, but currently just the spanish ones are available. - -Samples -------- - -As the generated dataset has been uploaded to `Kaggle `_ -some kernels with samples on retrieved data usage have been created by the community. \ No newline at end of file diff --git a/docs/source/_info/usage.md b/docs/source/_info/usage.md new file mode 100644 index 0000000..e6a98af --- /dev/null +++ b/docs/source/_info/usage.md @@ -0,0 +1,172 @@ +## ๐Ÿ’ป Usage + +Even though some investpy usage examples are presented on the [docs](https://investpy.readthedocs.io/usage.html), +some basic functionality will be sorted out with sample Python code blocks. Additionally, more usage examples +can be found under [examples/](https://github.com/alvarobartt/investpy/tree/master/examples) directory, which +contains a collection of Jupyter Notebooks on how to use investpy and handle its data. + +๐Ÿ“Œ __Note that `investpy.search_quotes` is the only function that ensures that the data is updated and aligned 1:1 with +the data provided by Investing.com!__ + +### ๐Ÿ“ˆ Recent/Historical Data Retrieval + +investpy allows the user to **download both recent and historical data from any financial product indexed** +(stocks, funds, ETFs, currency crosses, certificates, bonds, commodities, indices, and cryptos). In +the example presented below, the historical data from the past years of a stock is retrieved. + +```python +import investpy + +df = investpy.get_stock_historical_data(stock='AAPL', + country='United States', + from_date='01/01/2010', + to_date='01/01/2020') +print(df.head()) +``` +``` + Open High Low Close Volume Currency +Date +2010-01-04 30.49 30.64 30.34 30.57 123432176 USD +2010-01-05 30.66 30.80 30.46 30.63 150476160 USD +2010-01-06 30.63 30.75 30.11 30.14 138039728 USD +2010-01-07 30.25 30.29 29.86 30.08 119282440 USD +2010-01-08 30.04 30.29 29.87 30.28 111969192 USD +``` + +To get to know all the available recent and historical data extraction functions provided by +investpy, and also, parameter tuning, please read the docs. + +### ๐Ÿ” Search Live Data + +**Investing.com search engine is completely integrated** with investpy, which means that any available +financial product (quote) can be easily found. The search function allows the user to tune the parameters +to adjust the search results to their needs, where both product types and countries from where the +products are, can be specified. **All the search functionality can be easily used**, for example, as +presented in the following piece of code: + +```python +import investpy + +search_result = investpy.search_quotes(text='apple', products=['stocks'], + countries=['united states'], n_results=1) +print(search_result) +``` +``` +{"id_": 6408, "name": "Apple Inc", "symbol": "AAPL", "country": "united states", "tag": "/equities/apple-computer-inc", "pair_type": "stocks", "exchange": "NASDAQ"} + +``` + +Retrieved search results will be a `list` of `investpy.utils.search_obj.SearchObj` class instances, unless +`n_results` is set to 1, when just a single `investpy.utils.search_obj.SearchObj` class instance will be returned. +To get to know which are the available functions and attributes of the returned search results, please read the related +documentation at [Search Engine Documentation](https://investpy.readthedocs.io/search_api.html). So on, those +search results let the user retrieve both recent and historical data, its information, the technical indicators, +the default currency, etc., as presented in the pieces of code below: + +#### โ—พ Recent Data + +```python +recent_data = search_result.retrieve_recent_data() +print(recent_data.head()) +``` +``` + Open High Low Close Volume Change Pct +Date +2021-05-13 124.58 126.15 124.26 124.97 105861000 1.79 +2021-05-14 126.25 127.89 125.85 127.45 81918000 1.98 +2021-05-17 126.82 126.93 125.17 126.27 74245000 -0.93 +2021-05-18 126.56 126.99 124.78 124.85 63343000 -1.12 +2021-05-19 123.16 124.92 122.86 124.69 92612000 -0.13 + +``` + +#### โ—พ Historical Data + +```python +historical_data = search_result.retrieve_historical_data(from_date='01/01/2019', to_date='01/01/2020') +print(historical_data.head()) +``` +``` + Open High Low Close Volume Change Pct +Date +2020-01-02 74.06 75.15 73.80 75.09 135647008 2.28 +2020-01-03 74.29 75.14 74.13 74.36 146536000 -0.97 +2020-01-06 73.45 74.99 73.19 74.95 118579000 0.80 +2020-01-07 74.96 75.22 74.37 74.60 111511000 -0.47 +2020-01-08 74.29 76.11 74.29 75.80 132364000 1.61 + +``` + +#### โ—พ Information + +```python +information = search_result.retrieve_information() +print(information) +``` +```json +{"prevClose": 126.11, "dailyRange": "126.1-127.44", "revenue": 325410000000, "open": 126.53, "weekRange": "83.14-145.09", "eps": 4.46, "volume": 53522373, "marketCap": 2130000000000, "dividend": "0.88(0.70%)", "avgVolume": 88858729, "ratio": 28.58, "beta": 1.2, "oneYearReturn": "50.35%", "sharesOutstanding": 16687631000, "nextEarningDate": "03/08/2021"} + +``` + +#### โ—พ Currency + +```python +default_currency = search_result.retrieve_currency() +print(default_currency) +``` +``` +'USD' + +``` + +#### โ—พ Technical Indicators + +```python +technical_indicators = search_result.retrieve_technical_indicators(interval="daily") +print(technical_indicators) +``` +``` + indicator signal value +0 RSI(14) neutral 52.1610 +1 STOCH(9,6) buy 63.7110 +2 STOCHRSI(14) overbought 100.0000 +3 MACD(12,26) sell -0.6700 +4 ADX(14) neutral 21.4750 +5 Williams %R buy -20.9430 +6 CCI(14) buy 67.1057 +7 ATR(14) less_volatility 1.7871 +8 Highs/Lows(14) buy 0.4279 +9 Ultimate Oscillator sell 47.3620 +10 ROC buy 1.5150 +11 Bull/Bear Power(13) buy 1.3580 + +``` + +### ๐Ÿ’ธ Crypto Currencies Data Retrieval + +Cryptocurrencies support has recently been included, to let the user retrieve data and information from any +available crypto at Investing.com. Please note that some cryptocurrencies do not have available data indexed +at Investing.com so that it can not be retrieved using investpy either, even though they are just a few, +consider it. + +As already presented previously, **historical data retrieval using investpy is really easy**. The piece of code +presented below shows how to retrieve the past years of historical data from Bitcoin (BTC). + +```python +import investpy + +data = investpy.get_crypto_historical_data(crypto='bitcoin', + from_date='01/01/2014', + to_date='01/01/2019') + +print(data.head()) +``` +``` + Open High Low Close Volume Currency +Date +2014-01-01 805.9 829.9 771.0 815.9 10757 USD +2014-01-02 815.9 886.2 810.5 856.9 12812 USD +2014-01-03 856.9 888.2 839.4 884.3 9709 USD +2014-01-04 884.3 932.2 848.3 924.7 14239 USD +2014-01-05 924.7 1029.9 911.4 1014.7 21374 USD +``` diff --git a/docs/source/_info/usage.rst b/docs/source/_info/usage.rst deleted file mode 100644 index b05139b..0000000 --- a/docs/source/_info/usage.rst +++ /dev/null @@ -1,250 +0,0 @@ -Usage -===== - -Along this document, the main `investpy `_ functions are going to be presented. So on, this is a tutorial -on how to use **investpy** to retrieve data from the financial products available, such as: stocks, funds, ETFs, indices and currency crosses, -retrieved from Investing.com. - -Recent/Historical Data Retrieval --------------------------------- - -The main functionallity of **investpy** is to retrieve historical data from the indexed financial products. So both recent and historical data -retrieval functions have been developed in order to retrieve data from the last month or from a concrete period of time, respectively. - -Stock Data Retrieval -^^^^^^^^^^^^^^^^^^^^ - -.. code-block:: python - - import investpy - - df = investpy.get_stock_recent_data(stock='bbva', - country='spain') - print(df.head()) - - Open High Low Close Volume Currency - Date - 2019-08-13 4.263 4.395 4.230 4.353 27250000 EUR - 2019-08-14 4.322 4.325 4.215 4.244 36890000 EUR - 2019-08-15 4.281 4.298 4.187 4.234 21340000 EUR - 2019-08-16 4.234 4.375 4.208 4.365 46080000 EUR - 2019-08-19 4.396 4.425 4.269 4.269 18950000 EUR - - -.. code-block:: python - - import investpy - - df = investpy.get_stock_historical_data(stock='AAPL', - country='United States', - from_date='01/01/2010', - to_date='01/01/2020') - print(df.head()) - - Open High Low Close Volume Currency - Date - 2010-01-04 30.49 30.64 30.34 30.57 123432176 USD - 2010-01-05 30.66 30.80 30.46 30.63 150476160 USD - 2010-01-06 30.63 30.75 30.11 30.14 138039728 USD - 2010-01-07 30.25 30.29 29.86 30.08 119282440 USD - 2010-01-08 30.04 30.29 29.87 30.28 111969192 USD - -Fund Data Retrieval -^^^^^^^^^^^^^^^^^^^ - -.. code-block:: python - - import investpy - - df = investpy.get_fund_recent_data(fund='bbva plan multiactivo moderado pp', - country='spain') - print(df.head()) - - Open High Low Close Currency - Date - 2019-08-13 1.110 1.110 1.110 1.110 EUR - 2019-08-16 1.109 1.109 1.109 1.109 EUR - 2019-08-19 1.114 1.114 1.114 1.114 EUR - 2019-08-20 1.112 1.112 1.112 1.112 EUR - 2019-08-21 1.115 1.115 1.115 1.115 EUR - -.. code-block:: python - - import investpy - - df = investpy.get_fund_historical_data(fund='bbva plan multiactivo moderado pp', - country='spain', - from_date='01/01/2010', - to_date='01/01/2019') - print(df.head()) - - Open High Low Close Currency - Date - 2018-02-15 1.105 1.105 1.105 1.105 EUR - 2018-02-16 1.113 1.113 1.113 1.113 EUR - 2018-02-17 1.113 1.113 1.113 1.113 EUR - 2018-02-18 1.113 1.113 1.113 1.113 EUR - 2018-02-19 1.111 1.111 1.111 1.111 EUR - -ETF Data Retrieval -^^^^^^^^^^^^^^^^^^ - -.. code-block:: python - - import investpy - - df = investpy.get_etf_recent_data(etf='bbva accion dj eurostoxx 50', - country='spain') - print(df.head()) - - Open High Low Close Currency - Date - 2019-08-13 33.115 33.780 32.985 33.585 EUR - 2019-08-14 33.335 33.335 32.880 32.905 EUR - 2019-08-15 32.790 32.925 32.455 32.845 EUR - 2019-08-16 33.115 33.200 33.115 33.305 EUR - 2019-08-19 33.605 33.735 33.490 33.685 EUR - -.. code-block:: python - - import investpy - - df = investpy.get_etf_historical_data(etf='bbva accion dj eurostoxx 50', - country='spain', - from_date='01/01/2018', - to_date='01/01/2019') - print(df.head()) - - Open High Low Close Currency - Date - 2011-12-07 23.70 23.70 23.70 23.62 EUR - 2011-12-08 23.53 23.60 23.15 23.04 EUR - 2011-12-09 23.36 23.60 23.36 23.62 EUR - 2011-12-12 23.15 23.26 23.00 22.88 EUR - 2011-12-13 22.88 22.88 22.88 22.80 EUR - -Index Data Retrieval -^^^^^^^^^^^^^^^^^^^^ - -.. code-block:: python - - import investpy - - df = investpy.get_index_recent_data(index='ibex 35', - country='spain') - print(df.head()) - - 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 - -.. code-block:: python - - import investpy - - df = investpy.get_index_historical_data(index='ibex 35', - country='spain', - from_date='01/01/2018', - to_date='01/01/2019') - print(df.head()) - - 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 - -Currency Crosses Data Retrieval -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -.. code-block:: python - - import investpy - - df = investpy.get_currency_cross_recent_data(currency_cross='EUR/USD') - print(df.head()) - - Open High Low Close Volume Currency - Date - 2019-08-27 1.1101 1.1116 1.1084 1.1091 0 USD - 2019-08-28 1.1090 1.1099 1.1072 1.1078 0 USD - 2019-08-29 1.1078 1.1093 1.1042 1.1057 0 USD - 2019-08-30 1.1058 1.1062 1.0963 1.0991 0 USD - 2019-09-02 1.0990 1.1000 1.0958 1.0968 0 USD - -.. code-block:: python - - import investpy - - df = investpy.get_currency_cross_historical_data(currency_cross='EUR/USD', - from_date='01/01/2018', - to_date='01/01/2019') - print(df.head()) - - Open High Low Close Volume Currency - Date - 2018-01-01 1.2003 1.2014 1.1995 1.2010 0 USD - 2018-01-02 1.2013 1.2084 1.2003 1.2059 0 USD - 2018-01-03 1.2058 1.2070 1.2001 1.2014 0 USD - 2018-01-04 1.2015 1.2090 1.2004 1.2068 0 USD - 2018-01-05 1.2068 1.2085 1.2021 1.2030 0 USD - -Additional Data ---------------- - -As Investing.com provides more data besides the historical one, some of that additional data can be fetched via investpy. -Currently, as the package is under-development, some additional functions have been created in order to retrieve more data -as indexed in Investing.com. - -Stock Company Profile Retrieval -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -.. code-block:: python - - import investpy - - company_profile = investpy.get_stock_company_profile(stock='bbva', - country='spain') - print(company_profile) - - { - "url": "https://www.investing.com/equities/bbva-company-profile", - "description": "Banco Bilbao Vizcaya Argentaria, S.A. (BBVA) is a diversified financial company engaged in retail banking ..." - } - -Fund Information Retrieval -^^^^^^^^^^^^^^^^^^^^^^^^^^ - -.. code-block:: python - - import investpy - - fund_information = investpy.get_fund_information(fund='bbva plan multiactivo moderado pp', - country='spain', - as_json=True) - print(fund_information) - - { - 'Fund Name': 'Bbva Plan Multiactivo Moderado Pp', - 'Rating': 4, - '1-Year Change': '-1,19%', - 'Previous Close': '1.103', - 'Risk Rating': 1, - 'TTM Yield': '0%', - 'ROE': '14,02%', - 'Issuer': 'BBVA Pensiones EGFP', - 'Turnover': None, - 'ROA': '4,97%', - 'Inception Date': '16/10/2012', - 'Total Assets': 1670000000, - 'Expenses': None, - 'Min Investment': 30, - 'Market Cap': 34820000000, - 'Category': 'Mixtos Euros Moderados PP' - } \ No newline at end of file diff --git a/docs/source/conf.py b/docs/source/conf.py index f2e036b..9a92c48 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -14,11 +14,10 @@ # import sys # sys.path.insert(0, os.path.abspath('.')) - # -- Project information ----------------------------------------------------- project = 'investpy' -copyright = '2020, Alvaro Bartolome del Canto' +copyright = '2021, Alvaro Bartolome del Canto' author = 'Alvaro Bartolome del Canto' # The full version, including alpha/beta/rc tags @@ -48,7 +47,6 @@ # The suffix(es) of source filenames. # You can specify multiple suffix as a list of string: -# source_suffix = ['.rst', '.md'] # source_suffix = '.rst' @@ -60,7 +58,7 @@ # # This is also used if you do content translation via gettext catalogs. # Usually you set "language" from the command line for these cases. -language = None +language = 'en' # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. @@ -68,23 +66,24 @@ exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] # The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' +pygments_style = 'friendly' # -- Options for HTML output ------------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. -import sphinx_rtd_theme -html_theme = 'sphinx_rtd_theme' +html_theme = 'furo' +html_title = "investpy" # Add any paths that contain custom themes here, relative to this directory. -html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] +# html_theme_path = [] # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. -# -# html_theme_options = {} +html_theme_options = { + "announcement": "investpy v1.0.7 has just been released! ๐Ÿ”ฅ", +} # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, diff --git a/docs/source/index.rst b/docs/source/index.rst index 929dd30..0825892 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -1,23 +1,22 @@ Welcome to investpy's documentation! ==================================== -.. image:: https://raw.githubusercontent.com/alvarobartt/investpy/master/docs/_static/logo.png +.. image:: _static/logo.png :align: center .. toctree:: :maxdepth: 3 :caption: Contents: - _info/introduction.rst - _info/installation.rst - _info/usage.rst - _info/models.rst - _info/stocks.rst - _info/funds.rst - api.rst - _info/information.md + _info/introduction.md + _info/installation.md + _info/usage.md + _info/related_projects.md + _info/contact_information.md + _info/citation.md _info/faq.md _info/disclaimer.md + api.rst Indices and tables From 159ec00ea3b53d5f07b450b5f1cf0fda7faab685 Mon Sep 17 00:00:00 2001 From: Alvaro Bartolome Date: Sun, 13 Jun 2021 13:46:40 +0200 Subject: [PATCH 23/23] minor changes & included github discussions ref in docs --- README.md | 12 +++++++++++- docs/source/_info/{faq.md => discussions.md} | 19 +++++++++++++++++-- docs/source/index.rst | 2 +- 3 files changed, 29 insertions(+), 4 deletions(-) rename docs/source/_info/{faq.md => discussions.md} (66%) diff --git a/README.md b/README.md index 9b50f26..68584e6 100644 --- a/README.md +++ b/README.md @@ -107,7 +107,9 @@ Retrieved search results will be a `list` of `investpy.utils.search_obj.SearchOb To get to know which are the available functions and attributes of the returned search results, please read the related documentation at [Search Engine Documentation](https://investpy.readthedocs.io/search_api.html). So on, those search results let the user retrieve both recent and historical data, its information, the technical indicators, -the default currency, etc., as presented in the piece of code below: +the default currency, etc., as presented in the pieces of code below: + +#### Recent Data ```python recent_data = search_result.retrieve_recent_data() @@ -124,6 +126,8 @@ Date ``` +#### Historical Data + ```python historical_data = search_result.retrieve_historical_data(from_date='01/01/2019', to_date='01/01/2020') print(historical_data.head()) @@ -139,6 +143,8 @@ Date ``` +#### Information + ```python information = search_result.retrieve_information() print(information) @@ -148,6 +154,8 @@ print(information) ``` +#### Currency + ```python default_currency = search_result.retrieve_currency() print(default_currency) @@ -157,6 +165,8 @@ print(default_currency) ``` +#### Technical Indicators + ```python technical_indicators = search_result.retrieve_technical_indicators(interval='daily') print(technical_indicators) diff --git a/docs/source/_info/faq.md b/docs/source/_info/discussions.md similarity index 66% rename from docs/source/_info/faq.md rename to docs/source/_info/discussions.md index 2a83053..69123a4 100644 --- a/docs/source/_info/faq.md +++ b/docs/source/_info/discussions.md @@ -1,6 +1,21 @@ -# โ“ Frequent Asked Questions - FAQs +# โ“ Discussions (Q&A, AMA) -In this section the Frequent Asked Questions are answered, so please read this section before posting a question or openning an issue since duplicates will not be solved or will be referenced to this section. Also, if you think that there are more possible FAQs, consider openning an issue in GitHub so to notify it, since if we all contribute this section can be clear enough so to ease question answering. +GitHub recently released a new feature named __GitHub Discussions__ (still in beta). GitHub Discussions is a +collaborative communication forum for the community around an open source project. + +Check the investpy GitHub Discussions page at [Discussions](https://github.com/alvarobartt/investpy/discussions), +and feel free to ask me (ar any developer) anything, share updates, have open-ended conversations, and follow along +on decisions affecting the community's way of working. + +:pushpin: __Note__. Usually I don't answer emails asking me questions about investpy, as we currently have the +GitHub Discussions tab, and I encourage you to use it. GitHub Discussions is the easiest way to contact me about +investpy, so that I don't answer the same stuff more than once via email, as anyone can see the opened/answered +discussions. + +Also, in this section some Frequent Asked Questions are answered, so please read this section before posting a +question or openning an issue since duplicates will not be solved or will be referenced to this section. Also, +if you think that there are more possible FAQs, consider openning an issue in GitHub so to notify it, since if we +all contribute this section can be clear enough so to ease question answering. ## Where can I find the reference of a function and its usage? diff --git a/docs/source/index.rst b/docs/source/index.rst index 0825892..3b43873 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -14,7 +14,7 @@ Welcome to investpy's documentation! _info/related_projects.md _info/contact_information.md _info/citation.md - _info/faq.md + _info/discussions.md _info/disclaimer.md api.rst