import yfinance as yf import pandas as pd class SimpleStockData: 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: list containing all stocks/exchange rates (yfinance considers both as "Tickers") :param to_currency: currency to convert rates to """ self.ticker_list = ticker_list self.to_currency = to_currency self._period_start = period_start self._period_end = period_end 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 def _get_history(self, idx, interval="1d"): """ 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 """ return yf.Ticker(self.ticker_list[idx]).history(interval=interval, start=self._period_start, end=self._period_end) def _create_exchange_dataframe(self): """ 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 """ # 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) # now the real process begins tickers = yf.Tickers(" ".join(_from_currency_list)) # create a new Ticker instance with all wanted currencies exchange_rates = [] for i in tickers.tickers: # get all the history of each currency conversion factors # 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) 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 return True def get_info(self, idx, key=""): """ :param idx: the index of the share :param key: OPTIONAL. gives which specific datum is wanted :return: """ info = yf.Ticker(self.ticker_list[idx]).info if key != "": # if just one specific information is wanted return info[key] return info 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