Esempio n. 1
0
    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)
Esempio n. 2
0
    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)
Esempio n. 4
0
    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)
Esempio n. 5
0
    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])
Esempio n. 6
0
    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])
Esempio n. 7
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