2023-11-26 21:15:11 +00:00
|
|
|
import yfinance as yf
|
2023-11-30 19:50:49 +00:00
|
|
|
import pandas as pd
|
2023-11-26 21:15:11 +00:00
|
|
|
|
|
|
|
|
|
|
|
class SimpleStockData:
|
2023-11-30 19:50:49 +00:00
|
|
|
def __init__(self, ticker_list: list, period_start: str, period_end: str, to_currency: str = ""):
|
|
|
|
"""
|
|
|
|
:param period_start:
|
|
|
|
start date (format YYYY-MM-DD)
|
|
|
|
:param period_end:
|
|
|
|
end date (format YYYY-MM-DD)
|
|
|
|
:param ticker_list:
|
2023-11-30 20:28:15 +00:00
|
|
|
list containing all stocks/exchange rates (yfinance considers both as "Tickers")
|
2023-11-30 19:50:49 +00:00
|
|
|
:param to_currency:
|
|
|
|
currency to convert rates to
|
|
|
|
"""
|
2023-11-26 21:15:11 +00:00
|
|
|
|
|
|
|
self.ticker_list = ticker_list
|
|
|
|
self.to_currency = to_currency
|
2023-11-30 19:50:49 +00:00
|
|
|
self._period_start = period_start
|
|
|
|
self._period_end = period_end
|
2023-11-26 21:15:11 +00:00
|
|
|
|
2023-11-30 20:28:15 +00:00
|
|
|
self._exchange_df = None # Mapping: time mapped to conversion factor, to get the right converted value per date
|
|
|
|
self._create_exchange_dataframe() # initialize self.exchange_df attribute
|
|
|
|
|
2023-11-30 19:50:49 +00:00
|
|
|
def _get_history(self, idx, interval="1d"):
|
2023-11-26 21:15:11 +00:00
|
|
|
"""
|
|
|
|
Function for internal use; Just a wrapper around the .history method of the yfinance Ticker class
|
|
|
|
:param idx:
|
|
|
|
the index of the share
|
|
|
|
:param interval:
|
|
|
|
granularity of data - valid values are 1m, 2m, 5m, 15m, 30m, 60m, 90m, 1h, 1d, 5d, 1wk, 1mo, 3mo
|
|
|
|
:return: pandas.DataFrame
|
|
|
|
"""
|
2023-11-30 19:50:49 +00:00
|
|
|
|
|
|
|
return yf.Ticker(self.ticker_list[idx]).history(interval=interval, start=self._period_start,
|
|
|
|
end=self._period_end)
|
|
|
|
|
2023-11-30 20:28:15 +00:00
|
|
|
def _create_exchange_dataframe(self):
|
2023-11-30 19:50:49 +00:00
|
|
|
"""
|
|
|
|
The class has two separate attributes, one to store the plain convert list
|
|
|
|
(_from_currency_list), and one containing the real mapping needed to convert.
|
|
|
|
The mapping is recreated by this function following the information in the
|
|
|
|
_from_currency_list.
|
|
|
|
return:
|
|
|
|
boolean
|
|
|
|
"""
|
|
|
|
|
2023-11-30 20:28:15 +00:00
|
|
|
# check if a to_currency is even given
|
|
|
|
if self.to_currency == "":
|
|
|
|
return False
|
|
|
|
|
|
|
|
# create the list of currencies based on all the stocks of the class
|
|
|
|
_from_currency_list = []
|
|
|
|
for i in range(len(self.ticker_list)): # to get all indexes; this adds an entry for each currency
|
|
|
|
add_currency = f"{self.get_info(i, 'currency')}{self.to_currency}=X" # Format: "fffttt=X" f=from, t=to
|
|
|
|
# for the case that FROM and TO are equal, just don't download the data (as conversion factor's 1)
|
|
|
|
if add_currency == f"{self.to_currency}{self.to_currency}=X":
|
|
|
|
pass
|
|
|
|
elif add_currency not in _from_currency_list: # add a new item if not already there
|
|
|
|
_from_currency_list.append(add_currency)
|
|
|
|
|
|
|
|
print(_from_currency_list)
|
2023-11-30 19:50:49 +00:00
|
|
|
|
|
|
|
# now the real process begins
|
2023-11-30 20:28:15 +00:00
|
|
|
tickers = yf.Tickers(" ".join(_from_currency_list)) # create a new Ticker instance with all wanted currencies
|
2023-11-30 19:50:49 +00:00
|
|
|
exchange_rates = []
|
|
|
|
for i in tickers.tickers: # get all the history of each currency conversion factors
|
2023-11-30 20:28:15 +00:00
|
|
|
# for simplicity: using the conversion factor of closing (.Close at the end)
|
|
|
|
exchange_rates.append(tickers.tickers[i].history(start=self._period_start, end=self._period_end).Close)
|
2023-11-30 19:50:49 +00:00
|
|
|
|
2023-11-30 20:28:15 +00:00
|
|
|
self._exchange_df = pd.DataFrame(exchange_rates).T # transpose the dataframe (imagine just switching rows and columns)
|
|
|
|
self._exchange_df.columns = _from_currency_list # set the right names for the columns in the dataframe
|
|
|
|
self._exchange_df[f"{self.to_currency}{self.to_currency}=X"] = 1.0 # for FROM and TO being equal: set factor to 1
|
2023-11-30 19:50:49 +00:00
|
|
|
|
|
|
|
return True
|
2023-11-26 21:15:11 +00:00
|
|
|
|
|
|
|
def get_info(self, idx, key=""):
|
|
|
|
"""
|
|
|
|
:param idx:
|
|
|
|
the index of the share
|
|
|
|
:param key:
|
|
|
|
OPTIONAL. gives which specific datum is wanted
|
|
|
|
:return:
|
|
|
|
"""
|
2023-11-30 19:50:49 +00:00
|
|
|
|
2023-11-26 21:15:11 +00:00
|
|
|
info = yf.Ticker(self.ticker_list[idx]).info
|
|
|
|
if key != "": # if just one specific information is wanted
|
|
|
|
return info[key]
|
|
|
|
return info
|
2023-11-30 19:50:49 +00:00
|
|
|
|
|
|
|
def get_history(self, idx, interval="1d"):
|
|
|
|
"""
|
|
|
|
Just a wrapper around the .history method of the yfinance Ticker class
|
|
|
|
:param idx:
|
|
|
|
the index of the share
|
|
|
|
:param interval:
|
|
|
|
granularity of data - valid values are 1m, 2m, 5m, 15m, 30m, 60m, 90m, 1h, 1d, 5d, 1wk, 1mo, 3mo
|
|
|
|
:return: pandas.DataFrame
|
|
|
|
"""
|
|
|
|
|
|
|
|
ret = self._get_history(idx, interval)
|
|
|
|
return ret
|