def test_dividend(self): """ Test if it can correctly return the dividends in the correct order and format(parsed correctly) """ output1 = pd.DataFrame(columns=["Dividends"]) output1 = pd.DataFrame(data=[{ 'amount': 0.448, 'date': 1615987800 }, { 'amount': 0.442, 'date': 1608215400 }]) output1.set_index("date", inplace=True) output1.index = pd.to_datetime(output1.index, unit="s") output1.sort_index(inplace=True) #dividends.index = dividends.index.tz_localize(tz) output1.columns = ["Dividends"] #case1: when Data that contains two different dividends and contains no splits. result = utils.parse_actions(data1) self.assertNotEqual(result, None) #check if the returned result is None self.assertFalse( result[0].empty) #check if the returned dividents is not empty self.assertTrue( result[1].empty) #check if the returned splits returned is empty assert_frame_equal( result[0], output1 ) #check if the data frame returned match with expected output #case2: when data has no dividends and splits events result2 = utils.parse_actions(data2) self.assertTrue(result2[0].empty) self.assertTrue(result2[1].empty)
def test_split(self): """ Test if it can correctly parsr the data with splits. """ #mock dataframe containing a stock info with splits output = pd.DataFrame(data=[{ 'date': 1616482800, 'numerator': 1, 'denominator': 50, 'splitRatio': '1:50' }]) output.set_index("date", inplace=True) output.index = pd.to_datetime(output.index, unit="s") output.sort_index(inplace=True) output["Stock Splits"] = output["numerator"] / \ output["denominator"] output = output["Stock Splits"] #case3: data has only split event result = utils.parse_actions( data3) #call parse action function with the above data self.assertNotEqual(result, None) #Check if the result is None self.assertFalse(result[1].empty) #Check if the result contains splits self.assertTrue( result[0].empty) #Check if the result does not contain dividends assert_series_equal(result[1], output) #Check if the result matches the mock data
def test_dividend(self): """ Test if it can correctly return the dividends in the correct order and format(parsed correctly) """ #case1: when Data that contains two different dividends and contains no splits. result = utils.parse_actions(data1) self.assertNotEqual(result, None) #check if the returned result is None self.assertFalse( result[0].empty) #check if the returned dividents is not empty self.assertTrue( result[1].empty) #check if the returned splits returned is empty assert_frame_equal( result[0], output1 ) #check if the data frame returned match with expected output #case2: when data has no dividends and splits events result2 = utils.parse_actions(data2) self.assertTrue(result2[0].empty) self.assertTrue(result2[1].empty)
def test_emptyInput(self): """ Test if data can handle wrong input argument """ #output = pd.DataFrame(columns=["Dividends"]) #output = pd.DataFrame(data=[{'amount': 0.205, 'date': 1604673000}, {'amount': 0.205, 'date': 1612535400}]) output = pd.DataFrame(columns=["Dividends"]) output = pd.DataFrame(data=['']) output.index = pd.to_datetime(output.index, unit="s") result = utils.parse_actions(data5) self.assertTrue(result[0].empty) self.assertTrue(result[1].empty)
def test_wrongDate(self): """ Test the date beyond the electronic stock market was created """ output = pd.DataFrame(columns=["Dividends"]) output = pd.DataFrame(data=[{ 'amount': 0.205, 'date': 1604673000 }, { 'amount': 0.205, 'date': 3308400 }]) output.set_index("date", inplace=True) output.index = pd.to_datetime(output.index, unit="s") dividends, splits = utils.parse_actions(data6) self.assertEqual(dividends.index[1], output.index[1])
def test_dateTime(self): """ Test if date and time are in correct format """ output = pd.DataFrame(columns=["Dividends"]) output = pd.DataFrame(data=[{ 'amount': 0.205, 'date': 1604673000 }, { 'amount': 0.205, 'date': 1612535400 }]) output.set_index("date", inplace=True) output.index = pd.to_datetime(output.index, unit="s") dividends, splits = utils.parse_actions(data4) self.assertTrue(splits.empty) self.assertFalse(dividends.empty) self.assertEqual(dividends.index[0], output.index[0])
def history(self, period="1mo", interval="1d", start=None, end=None, prepost=False, actions=True, auto_adjust=True, back_adjust=False, proxy=None, rounding=False, tz=None, **kwargs): """ :Parameters: period : str Valid periods: 1d,5d,1mo,3mo,6mo,1y,2y,5y,10y,ytd,max Either Use period parameter or use start and end interval : str Valid intervals: 1m,2m,5m,15m,30m,60m,90m,1h,1d,5d,1wk,1mo,3mo Intraday data cannot extend last 60 days start: str Download start date string (YYYY-MM-DD) or _datetime. Default is 1900-01-01 end: str Download end date string (YYYY-MM-DD) or _datetime. Default is now prepost : bool Include Pre and Post market data in results? Default is False auto_adjust: bool Adjust all OHLC automatically? Default is True back_adjust: bool Back-adjusted data to mimic true historical prices proxy: str Optional. Proxy server URL scheme. Default is None rounding: bool Round values to 2 decimal places? Optional. Default is False = precision suggested by Yahoo! tz: str Optional timezone locale for dates. (default data is returned as non-localized dates) **kwargs: dict debug: bool Optional. If passed as False, will suppress error message printing to console. """ if start or period is None or period.lower() == "max": if start is None: start = -2208988800 elif isinstance(start, _datetime.datetime): start = int(_time.mktime(start.timetuple())) else: start = int( _time.mktime(_time.strptime(str(start), '%Y-%m-%d'))) if end is None: end = int(_time.time()) elif isinstance(end, _datetime.datetime): end = int(_time.mktime(end.timetuple())) else: end = int(_time.mktime(_time.strptime(str(end), '%Y-%m-%d'))) params = {"period1": start, "period2": end} else: period = period.lower() params = {"range": period} params["interval"] = interval.lower() params["includePrePost"] = prepost params["events"] = "div,splits" # 1) fix weired bug with Yahoo! - returning 60m for 30m bars if params["interval"] == "30m": params["interval"] = "15m" # setup proxy in requests format if proxy is not None: if isinstance(proxy, dict) and "https" in proxy: proxy = proxy["https"] proxy = {"https": proxy} # Getting data from json url = "{}/v8/finance/chart/{}".format(self._base_url, self.ticker) data = self.session.get(url=url, params=params, proxies=proxy) if "Will be right back" in data.text: raise RuntimeError("*** YAHOO! FINANCE IS CURRENTLY DOWN! ***\n" "Our engineers are working quickly to resolve " "the issue. Thank you for your patience.") data = data.json() # Work with errors debug_mode = True if "debug" in kwargs and isinstance(kwargs["debug"], bool): debug_mode = kwargs["debug"] err_msg = "No data found for this date range, symbol may be delisted" if "chart" in data and data["chart"]["error"]: err_msg = data["chart"]["error"]["description"] shared._DFS[self.ticker] = utils.empty_df() shared._ERRORS[self.ticker] = err_msg if "many" not in kwargs and debug_mode: print('- %s: %s' % (self.ticker, err_msg)) return shared._DFS[self.ticker] elif "chart" not in data or data["chart"]["result"] is None or \ not data["chart"]["result"]: shared._DFS[self.ticker] = utils.empty_df() shared._ERRORS[self.ticker] = err_msg if "many" not in kwargs and debug_mode: print('- %s: %s' % (self.ticker, err_msg)) return shared._DFS[self.ticker] # parse quotes try: quotes = utils.parse_quotes(data["chart"]["result"][0], tz) except Exception: shared._DFS[self.ticker] = utils.empty_df() shared._ERRORS[self.ticker] = err_msg if "many" not in kwargs and debug_mode: print('- %s: %s' % (self.ticker, err_msg)) return shared._DFS[self.ticker] # 2) fix weired bug with Yahoo! - returning 60m for 30m bars if interval.lower() == "30m": quotes2 = quotes.resample('30T') quotes = _pd.DataFrame(index=quotes2.last().index, data={ 'Open': quotes2['Open'].first(), 'High': quotes2['High'].max(), 'Low': quotes2['Low'].min(), 'Close': quotes2['Close'].last(), 'Adj Close': quotes2['Adj Close'].last(), 'Volume': quotes2['Volume'].sum() }) try: quotes['Dividends'] = quotes2['Dividends'].max() except Exception: pass try: quotes['Stock Splits'] = quotes2['Dividends'].max() except Exception: pass if auto_adjust: quotes = utils.auto_adjust(quotes) elif back_adjust: quotes = utils.back_adjust(quotes) if rounding: quotes = _np.round(quotes, data["chart"]["result"][0]["meta"]["priceHint"]) quotes['Volume'] = quotes['Volume'].fillna(0).astype(_np.int64) quotes.dropna(inplace=True) # actions dividends, splits = utils.parse_actions(data["chart"]["result"][0], tz) # combine df = _pd.concat([quotes, dividends, splits], axis=1, sort=True) df["Dividends"].fillna(0, inplace=True) df["Stock Splits"].fillna(0, inplace=True) # index eod/intraday df.index = df.index.tz_localize("UTC").tz_convert( data["chart"]["result"][0]["meta"]["exchangeTimezoneName"]) if params["interval"][-1] == "m": df.index.name = "Datetime" elif params["interval"] == "1h": pass else: df.index = _pd.to_datetime(df.index.date) if tz is not None: df.index = df.index.tz_localize(tz) df.index.name = "Date" self._history = df.copy() if not actions: df.drop(columns=["Dividends", "Stock Splits"], inplace=True) return df