Esempio n. 1
0
def test_insert_row():
    df = pd.DataFrame(
        data={
            "col1": [1, 2],
            "col2": [3, 4]
        },
        index=["one", "two"],
    )
    result_df = dcf_model.insert_row(
        name="three",
        index="two",
        df=df,
        row_v=[5, 6],
    )

    expected_df = pd.DataFrame(
        data={
            "col1": [1, 2, 5],
            "col2": [3, 4, 6]
        },
        index=["one", "two", "three"],
    )

    assert not result_df.empty
    pd.testing.assert_frame_equal(result_df, expected_df)
Esempio n. 2
0
    def get_data(self, statement: str, row: int, header: bool):
        URL = f"https://stockanalysis.com/stocks/{self.ticker}/financials/"
        if statement == "BS":
            URL += "balance-sheet/"
            title = "Balance Sheet"
            ignores = dcf_model.non_gaap_bs
        if statement == "CF":
            URL += "cash-flow-statement/"
            title = "Cash Flows"
            ignores = dcf_model.non_gaap_cf
        if statement == "IS":
            title = "Income Statement"
            ignores = dcf_model.non_gaap_is

        r = requests.get(URL, headers=dcf_model.headers)

        if "404 - Page Not Found" in r.text:
            raise ValueError(
                "The ticker given is not in the stock analysis website.")
        soup = BeautifulSoup(r.content, "html.parser")

        table = soup.find(
            "table", attrs={"class": "FinancialTable_table_financial__1RhYq"})
        head = table.find("thead")
        columns = head.find_all("th")

        if self.years == []:
            self.years = [x.get_text().strip() for x in columns]
            self.len_data = len(self.years) - 1

        if self.rounding == 0:
            phrase = soup.find("div",
                               attrs={
                                   "class": "text-sm pb-1 text-gray-600"
                               }).get_text()
            if "thousand" in phrase:
                self.rounding = 1_000
            elif "millions" in phrase:
                self.rounding = 1_000_000
            elif "billions" in phrase:
                self.rounding = 1_000_000_000
            else:
                raise ValueError(
                    "Stock Analysis did not specify a proper rounding amount")

        body = table.find("tbody")
        rows = body.find_all("tr")

        all_data = [[x.get_text().strip() for x in y.find_all("td")]
                    for y in rows]

        df = pd.DataFrame(data=all_data)
        df = df.set_index(0)
        n = df.shape[1] - self.len_data
        if n > 0:
            df = df.iloc[:, :-n]
        df.columns = self.years[1:]

        for ignore in ignores:
            if ignore in df.index:
                df = df.drop([ignore])
        df = df[df.columns[::-1]]

        self.ws1[f"A{row}"] = title
        self.ws1[f"A{row}"].font = dcf_model.bold_font

        # Refactor in the future
        if statement == "IS":
            if "Revenue" in df.index:
                blank_list = ["0" for x in df.loc["Revenue"].to_list()]
            else:
                raise ValueError("Dataframe does not have key information.")
            for i, value in enumerate(dcf_model.gaap_is[1:]):
                df = dcf_model.insert_row(dcf_model.gaap_is[i + 1],
                                          dcf_model.gaap_is[i], df, blank_list)

        if statement == "BS":
            if "Cash & Equivalents" in df.index:
                blank_list = [
                    "0" for x in df.loc["Cash & Equivalents"].to_list()
                ]
            else:
                raise ValueError("Dataframe does not have key information.")
            for i, value in enumerate(dcf_model.gaap_bs[1:]):
                df = dcf_model.insert_row(dcf_model.gaap_bs[i + 1],
                                          dcf_model.gaap_bs[i], df, blank_list)

        if statement == "CF":
            if "Net Income" in df.index:
                blank_list = ["0" for x in df.loc["Net Income"].to_list()]
            else:
                raise ValueError("Dataframe does not have key information.")
            for i, value in enumerate(dcf_model.gaap_cf[1:]):
                df = dcf_model.insert_row(dcf_model.gaap_cf[i + 1],
                                          dcf_model.gaap_cf[i], df, blank_list)

        rowI = row + 1
        names = df.index.values.tolist()

        for name in names:
            self.ws1[f"A{rowI}"] = name
            if name in dcf_model.sum_rows:
                length = self.len_data + (self.len_pred
                                          if statement != "CF" else 0)
                for i in range(length):
                    if statement == "CF" and name == "Net Income":
                        pass
                    else:
                        self.ws1[
                            f"{dcf_model.letters[i+1]}{rowI}"].font = dcf_model.bold_font
                        self.ws1[
                            f"{dcf_model.letters[i+1]}{rowI}"].border = dcf_model.thin_border_top
            rowI += 1

        column = 1
        for key, value in df.iteritems():
            rowI = row
            if header:
                dcf_model.set_cell(
                    self.ws1,
                    f"{dcf_model.letters[column]}{rowI}",
                    float(key),
                    font=dcf_model.bold_font,
                )
            for item in value:
                rowI += 1
                m = 0 if item is None else float(item.replace(",", ""))
                dcf_model.set_cell(
                    self.ws1,
                    f"{dcf_model.letters[column]}{rowI}",
                    m,
                    num_form=dcf_model.fmt_acct,
                )
            column += 1

        return df
Esempio n. 3
0
    def get_sister_data(self, statement: str, ticker: str) -> pd.DataFrame:
        URL = f"https://stockanalysis.com/stocks/{ticker}/financials/"
        if statement == "BS":
            URL += "balance-sheet/"
            ignores = dcf_model.non_gaap_bs
        if statement == "CF":
            URL += "cash-flow-statement/"
            ignores = dcf_model.non_gaap_cf
        if statement == "IS":
            ignores = dcf_model.non_gaap_is

        r = requests.get(URL, headers=dcf_model.headers)

        if "404 - Page Not Found" in r.text:
            # TODO: add better handling
            print("Unable to find requested sister ticker for ration analysis")
            raise ValueError("The ticker given is not in the stock analysis website.")
        soup = BeautifulSoup(r.content, "html.parser")

        table = soup.find(
            "table", attrs={"class": re.compile("^FinancialTable_table_financial__.*")}
        )
        head = table.find("thead")
        if head is None:
            raise ValueError("Incorrect website format")
        columns = head.find_all("th")

        if self.years == []:
            self.years = [x.get_text().strip() for x in columns]
            self.len_data = len(self.years) - 1

        if self.rounding == 0:
            phrase = soup.find(
                "div", attrs={"class": "text-sm pb-1 text-gray-600"}
            ).get_text()
            if "thousand" in phrase:
                self.rounding = 1_000
            elif "millions" in phrase:
                self.rounding = 1_000_000
            elif "billions" in phrase:
                self.rounding = 1_000_000_000
            else:
                raise ValueError(
                    "Stock Analysis did not specify a proper rounding amount"
                )

        body = table.find("tbody")
        rows = body.find_all("tr")

        all_data = [[x.get_text().strip() for x in y.find_all("td")] for y in rows]

        df = pd.DataFrame(data=all_data)
        df = df.set_index(0)
        n = df.shape[1] - self.len_data
        if n > 0:
            df = df.iloc[:, :-n]

        df.columns = self.years[1:]

        for ignore in ignores:
            if ignore in df.index:
                df = df.drop([ignore])
        df = df[df.columns[::-1]]

        if statement == "IS":
            vals = ["Revenue", dcf_model.gaap_is]
        elif statement == "BS":
            vals = ["Cash & Equivalents", dcf_model.gaap_bs]
        elif statement == "CF":
            vals = ["Net Income", dcf_model.gaap_cf]

        if vals[0] in df.index:
            blank_list = ["0" for _ in df.loc[vals[0]].to_list()]
        else:
            raise ValueError("Dataframe does not have key information.")
        for i, _ in enumerate(vals[1][1:]):
            df = dcf_model.insert_row(vals[1][i + 1], vals[1][i], df, blank_list)

        return df