Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added support for etf extraction by symbol #427

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 54 additions & 29 deletions investpy/etfs.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,15 +157,19 @@ def get_etf_countries():
return etf_countries_as_list()


def get_etf_recent_data(etf, country, stock_exchange=None, as_json=False, order='ascending', interval='Daily'):
def get_etf_recent_data(etf, country, is_symbol=False, stock_exchange=None, as_json=False, order='ascending', interval='Daily'):
"""
This function retrieves recent historical data from the introduced `etf` from Investing
via Web Scraping. The resulting data can it either be stored in a :obj:`pandas.DataFrame` or in a
:obj:`json` file, with `ascending` or `descending` order.

Args:
etf (:obj:`str`): name of the etf to retrieve recent historical data from.
etf (:obj:`str`): name or symbol of the etf to retrieve recent historical data from.
country (:obj:`str`): name of the country from where the etf is.
is_symbol (:obj:`bool`, optional):
determine wether the etf is searched by its name or by its symbol.
stock_exchange (:obj:`str`, optional):
optional argument to filter the results by the stock exchange field.
as_json (:obj:`bool`, optional):
optional argument to determine the format of the output data (:obj:`pandas.DataFrame` or :obj:`json`).
order (:obj:`str`, optional):
Expand Down Expand Up @@ -236,6 +240,9 @@ def get_etf_recent_data(etf, country, stock_exchange=None, as_json=False, order=
if country is not None and not isinstance(country, str):
raise ValueError("ERR#0025: specified country value not valid.")

if not isinstance(is_symbol, bool):
raise ValueError("ERR#0139: is_symbol argument can just be True or False (default), bool type.")

if stock_exchange is not None and not isinstance(stock_exchange, str):
raise ValueError("ERR#0125: specified stock_exchange value is not valid, it should be a str.")

Expand Down Expand Up @@ -271,16 +278,18 @@ def get_etf_recent_data(etf, country, stock_exchange=None, as_json=False, order=
if country not in get_etf_countries():
raise RuntimeError("ERR#0034: country " + country + " not found, check if it is correct.")

etfs = etfs[etfs['country'].str.lower() == country]

etf = unidecode(etf.strip().lower())

def_exchange = etfs.loc[((etfs['name'].apply(unidecode).str.lower() == etf) & (etfs['def_stock_exchange'] == True)).idxmax()]

etfs = etfs[etfs['country'].str.lower() == country]
search_field = 'symbol' if is_symbol else 'name'

if etf not in list(etfs['name'].apply(unidecode).str.lower()):
def_exchange = etfs.loc[((etfs[search_field].apply(unidecode).str.lower() == etf) & (etfs['def_stock_exchange'] == True)).idxmax()]

if etf not in list(etfs[search_field].apply(unidecode).str.lower()):
raise RuntimeError("ERR#0019: etf " + etf + " not found, check if it is correct.")

etfs = etfs[etfs['name'].apply(unidecode).str.lower() == etf]
etfs = etfs[etfs[search_field].apply(unidecode).str.lower() == etf]

if def_exchange['country'] != country:
warnings.warn(
Expand All @@ -296,7 +305,7 @@ def get_etf_recent_data(etf, country, stock_exchange=None, as_json=False, order=

etf_exchange = etfs.loc[(etfs['stock_exchange'].str.lower() == stock_exchange.lower()).idxmax(), 'stock_exchange']
else:
found_etfs = etfs[etfs['name'].apply(unidecode).str.lower() == etf]
found_etfs = etfs[etfs[search_field].apply(unidecode).str.lower() == etf]

if len(found_etfs) > 1:
warnings.warn(
Expand All @@ -307,7 +316,7 @@ def get_etf_recent_data(etf, country, stock_exchange=None, as_json=False, order=

del found_etfs

etf_exchange = etfs.loc[(etfs['name'].apply(unidecode).str.lower() == etf).idxmax(), 'stock_exchange']
etf_exchange = etfs.loc[(etfs[search_field].apply(unidecode).str.lower() == etf).idxmax(), 'stock_exchange']
else:
if stock_exchange:
if stock_exchange.lower() not in etfs['stock_exchange'].str.lower():
Expand All @@ -325,11 +334,11 @@ def get_etf_recent_data(etf, country, stock_exchange=None, as_json=False, order=
else:
etf_exchange = def_exchange['stock_exchange']

symbol = etfs.loc[((etfs['name'].apply(unidecode).str.lower() == etf) & (etfs['stock_exchange'].str.lower() == etf_exchange.lower())).idxmax(), 'symbol']
id_ = etfs.loc[((etfs['name'].apply(unidecode).str.lower() == etf) & (etfs['stock_exchange'].str.lower() == etf_exchange.lower())).idxmax(), 'id']
name = etfs.loc[((etfs['name'].apply(unidecode).str.lower() == etf) & (etfs['stock_exchange'].str.lower() == etf_exchange.lower())).idxmax(), 'name']
symbol = etfs.loc[((etfs[search_field].apply(unidecode).str.lower() == etf) & (etfs['stock_exchange'].str.lower() == etf_exchange.lower())).idxmax(), 'symbol']
id_ = etfs.loc[((etfs[search_field].apply(unidecode).str.lower() == etf) & (etfs['stock_exchange'].str.lower() == etf_exchange.lower())).idxmax(), 'id']
name = etfs.loc[((etfs[search_field].apply(unidecode).str.lower() == etf) & (etfs['stock_exchange'].str.lower() == etf_exchange.lower())).idxmax(), search_field]

etf_currency = etfs.loc[((etfs['name'].apply(unidecode).str.lower() == etf) & (etfs['stock_exchange'].str.lower() == etf_exchange.lower())).idxmax(), 'currency']
etf_currency = etfs.loc[((etfs[search_field].apply(unidecode).str.lower() == etf) & (etfs['stock_exchange'].str.lower() == etf_exchange.lower())).idxmax(), 'currency']

header = symbol + ' Historical Data'

Expand Down Expand Up @@ -407,17 +416,21 @@ def get_etf_recent_data(etf, country, stock_exchange=None, as_json=False, order=
raise RuntimeError("ERR#0004: data retrieval error while scraping.")


def get_etf_historical_data(etf, country, from_date, to_date, stock_exchange=None, as_json=False, order='ascending', interval='Daily'):
def get_etf_historical_data(etf, country, from_date, to_date, is_symbol=False, stock_exchange=None, as_json=False, order='ascending', interval='Daily'):
"""
This function retrieves historical data from the introduced `etf` from Investing.com via Web Scraping on the
introduced date range. The resulting data can it either be stored in a :obj:`pandas.DataFrame` or in a
:obj:`json` object with `ascending` or `descending` order.

Args:
etf (:obj:`str`): name of the etf to retrieve recent historical data from.
etf (:obj:`str`): name or symbol of the etf to retrieve recent historical data from.
country (:obj:`str`): name of the country from where the etf is.
from_date (:obj:`str`): date as `str` formatted as `dd/mm/yyyy`, from where data is going to be retrieved.
to_date (:obj:`str`): date as `str` formatted as `dd/mm/yyyy`, until where data is going to be retrieved.
is_symbol (:obj:`bool`, optional):
determine wether the etf is searched by its name or by its symbol.
stock_exchange (:obj:`str`, optional):
optional argument to filter the results by the stock exchange field.
as_json (:obj:`bool`, optional):
to determine the format of the output data (:obj:`pandas.DataFrame` or :obj:`json`).
order (:obj:`str`, optional):
Expand Down Expand Up @@ -488,6 +501,9 @@ def get_etf_historical_data(etf, country, from_date, to_date, stock_exchange=Non
if country is not None and not isinstance(country, str):
raise ValueError("ERR#0025: specified country value not valid.")

if not isinstance(is_symbol, bool):
raise ValueError("ERR#0139: is_symbol argument can just be True or False (default), bool type.")

if stock_exchange is not None and not isinstance(stock_exchange, str):
raise ValueError("ERR#0125: specified stock_exchange value is not valid, it should be a str.")

Expand Down Expand Up @@ -574,14 +590,16 @@ def get_etf_historical_data(etf, country, from_date, to_date, stock_exchange=Non

etf = unidecode(etf.strip().lower())

def_exchange = etfs.loc[((etfs['name'].apply(unidecode).str.lower() == etf) & (etfs['def_stock_exchange'] == True)).idxmax()]
search_field = 'symbol' if is_symbol else 'name'

def_exchange = etfs.loc[((etfs[search_field].apply(unidecode).str.lower() == etf) & (etfs['def_stock_exchange'] == True)).idxmax()]

etfs = etfs[etfs['country'].str.lower() == country]

if etf not in list(etfs['name'].apply(unidecode).str.lower()):
if etf not in list(etfs[search_field].apply(unidecode).str.lower()):
raise RuntimeError("ERR#0019: etf " + etf + " not found, check if it is correct.")

etfs = etfs[etfs['name'].apply(unidecode).str.lower() == etf]
etfs = etfs[etfs[search_field].apply(unidecode).str.lower() == etf]

if def_exchange['country'] != country:
warnings.warn(
Expand All @@ -597,7 +615,7 @@ def get_etf_historical_data(etf, country, from_date, to_date, stock_exchange=Non

etf_exchange = etfs.loc[(etfs['stock_exchange'].str.lower() == stock_exchange.lower()).idxmax(), 'stock_exchange']
else:
found_etfs = etfs[etfs['name'].apply(unidecode).str.lower() == etf]
found_etfs = etfs[etfs[search_field].apply(unidecode).str.lower() == etf]

if len(found_etfs) > 1:
warnings.warn(
Expand All @@ -608,7 +626,7 @@ def get_etf_historical_data(etf, country, from_date, to_date, stock_exchange=Non

del found_etfs

etf_exchange = etfs.loc[(etfs['name'].apply(unidecode).str.lower() == etf).idxmax(), 'stock_exchange']
etf_exchange = etfs.loc[(etfs[search_field].apply(unidecode).str.lower() == etf).idxmax(), 'stock_exchange']
else:
if stock_exchange:
if stock_exchange.lower() not in etfs['stock_exchange'].str.lower():
Expand All @@ -626,11 +644,11 @@ def get_etf_historical_data(etf, country, from_date, to_date, stock_exchange=Non
else:
etf_exchange = def_exchange['stock_exchange']

symbol = etfs.loc[((etfs['name'].apply(unidecode).str.lower() == etf) & (etfs['stock_exchange'].str.lower() == etf_exchange.lower())).idxmax(), 'symbol']
id_ = etfs.loc[((etfs['name'].apply(unidecode).str.lower() == etf) & (etfs['stock_exchange'].str.lower() == etf_exchange.lower())).idxmax(), 'id']
name = etfs.loc[((etfs['name'].apply(unidecode).str.lower() == etf) & (etfs['stock_exchange'].str.lower() == etf_exchange.lower())).idxmax(), 'name']
symbol = etfs.loc[((etfs[search_field].apply(unidecode).str.lower() == etf) & (etfs['stock_exchange'].str.lower() == etf_exchange.lower())).idxmax(), 'symbol']
id_ = etfs.loc[((etfs[search_field].apply(unidecode).str.lower() == etf) & (etfs['stock_exchange'].str.lower() == etf_exchange.lower())).idxmax(), 'id']
name = etfs.loc[((etfs[search_field].apply(unidecode).str.lower() == etf) & (etfs['stock_exchange'].str.lower() == etf_exchange.lower())).idxmax(), search_field]

etf_currency = etfs.loc[((etfs['name'].apply(unidecode).str.lower() == etf) & (etfs['stock_exchange'].str.lower() == etf_exchange.lower())).idxmax(), 'currency']
etf_currency = etfs.loc[((etfs[search_field].apply(unidecode).str.lower() == etf) & (etfs['stock_exchange'].str.lower() == etf_exchange.lower())).idxmax(), 'currency']

final = list()

Expand Down Expand Up @@ -733,15 +751,17 @@ def get_etf_historical_data(etf, country, from_date, to_date, stock_exchange=Non
return pd.concat(final)


def get_etf_information(etf, country, as_json=False):
def get_etf_information(etf, country, is_symbol=False, as_json=False):
"""
This function retrieves fundamental financial information from the specified ETF. The retrieved
information from the ETF can be valuable as it is additional information that can be used combined
with OHLC values, so to determine financial insights from the company which holds the specified ETF.

Args:
etf (:obj:`str`): name of the ETF to retrieve recent historical data from.
etf (:obj:`str`): name or symbol of the ETF to retrieve recent historical data from.
country (:obj:`str`): name of the country from where the ETF is.
is_symbol (:obj:`bool`, optional):
determine wether the etf is searched by its name or by its symbol.
as_json (:obj:`bool`, optional):
optional argument to determine the format of the output data (:obj:`dict` or :obj:`json`).

Expand Down Expand Up @@ -793,6 +813,9 @@ def get_etf_information(etf, country, as_json=False):
if country is not None and not isinstance(country, str):
raise ValueError("ERR#0025: specified country value not valid.")

if not isinstance(is_symbol, bool):
raise ValueError("ERR#0139: is_symbol argument can just be True or False (default), bool type.")

if not isinstance(as_json, bool):
raise ValueError("ERR#0002: as_json argument can just be True or False, bool type.")

Expand All @@ -815,11 +838,13 @@ def get_etf_information(etf, country, as_json=False):

etf = unidecode(etf.strip().lower())

if etf not in list(etfs['name'].apply(unidecode).str.lower()):
search_field = 'symbol' if is_symbol else 'name'

if etf not in list(etfs[search_field].apply(unidecode).str.lower()):
raise RuntimeError("ERR#0019: etf " + etf + " not found, check if it is correct.")

name = etfs.loc[(etfs['name'].apply(unidecode).str.lower() == etf).idxmax(), 'name']
tag = etfs.loc[(etfs['name'].apply(unidecode).str.lower() == etf).idxmax(), 'tag']
name = etfs.loc[(etfs[search_field].apply(unidecode).str.lower() == etf).idxmax(), search_field]
tag = etfs.loc[(etfs[search_field].apply(unidecode).str.lower() == etf).idxmax(), 'tag']

url = "https://www.investing.com/etfs/" + tag

Expand Down
54 changes: 51 additions & 3 deletions tests/test_investpy.py
Original file line number Diff line number Diff line change
Expand Up @@ -402,32 +402,66 @@ def test_investpy_etfs():

params = [
{
'etf': 'bbva accion dj eurostoxx 50',
'is_symbol': False,
'as_json': True,
'order': 'ascending',
},
{
'etf': 'bbva accion dj eurostoxx 50',
'is_symbol': False,
'as_json': False,
'order': 'ascending',
},
{
'etf': 'bbva accion dj eurostoxx 50',
'is_symbol': False,
'as_json': True,
'order': 'descending',
},
{
'etf': 'bbva accion dj eurostoxx 50',
'is_symbol': False,
'as_json': False,
'order': 'descending',
},
{
'etf': 'bbvae',
'is_symbol': True,
'as_json': True,
'order': 'ascending',
},
{
'etf': 'bbvae',
'is_symbol': True,
'as_json': False,
'order': 'ascending',
},
{
'etf': 'bbvae',
'is_symbol': True,
'as_json': True,
'order': 'descending',
},
{
'etf': 'bbvae',
'is_symbol': True,
'as_json': False,
'order': 'descending',
},
]

for param in params:
investpy.get_etf_recent_data(etf='bbva accion dj eurostoxx 50',
investpy.get_etf_recent_data(etf=param['etf'],
country='spain',
is_symbol=param['is_symbol'],
as_json=param['as_json'],
order=param['order'],
interval='Daily')

investpy.get_etf_historical_data(etf='bbva accion dj eurostoxx 50',
investpy.get_etf_historical_data(etf=param['etf'],
country='spain',
is_symbol=param['is_symbol'],
from_date='01/01/2010',
to_date='01/01/2019',
as_json=param['as_json'],
Expand All @@ -437,18 +471,32 @@ def test_investpy_etfs():
params = [
{
'etf': 'bbva accion dj eurostoxx 50',
'is_symbol': False,
'country': 'spain',
'as_json': False
},
{
'etf': 'bbva accion dj eurostoxx 50',
'is_symbol': False,
'country': 'spain',
'as_json': True
},
{
'etf': 'bbvae',
'is_symbol': True,
'country': 'spain',
'as_json': False
},
{
'etf': 'bbvae',
'is_symbol': True,
'country': 'spain',
'as_json': True
}
]

for param in params:
investpy.get_etf_information(etf=param['etf'], country=param['country'], as_json=param['as_json'])
investpy.get_etf_information(etf=param['etf'], is_symbol=param['is_symbol'], country=param['country'], as_json=param['as_json'])

params = [
{
Expand Down
Loading