def test_get_stocks_data(mocker, recorder):
    target = "gamestonk_terminal.stocks.sector_industry_analysis.financedatabase_model.yf.utils.get_json"
    mocker.patch(target=target, return_value=YF_UTILS_GET_DICT)
    result = financedatabase_model.get_stocks_data(
        country="Georgia",
        sector="Industrials",
        industry="Conglomerates",
        marketcap="",
        exclude_exchanges=True,
    )
    recorder.capture(result)
def display_bars_financials(
    finance_key: str,
    finance_metric: str,
    country: str,
    sector: str,
    industry: str,
    marketcap: str = "",
    exclude_exchanges: bool = True,
    limit: int = 10,
    export: str = "",
    raw: bool = False,
    already_loaded_stocks_data: Dict = None,
):
    """Display financials bars comparing sectors, industry, analysis, countries, market cap and excluding exchanges.

    Parameters
    ----------
    finance_key: str
        Select finance key from Yahoo Finance(e.g. financialData, defaultKeyStatistics, summaryProfile)
    finance_metric: str
        Select finance metric from Yahoo Finance (e.g. operatingCashflow, revenueGrowth, ebitda, freeCashflow)
    country: str
        Search by country to find stocks matching the criteria.
    sector : str
        Search by sector to find stocks matching the criteria.
    industry : str
        Search by industry to find stocks matching the criteria.
    marketcap : str
        Select stocks based on the market cap.
    exclude_exchanges: bool
        When you wish to include different exchanges use this boolean.
    limit: int
        Limit amount of companies displayed
    export: str
        Format to export data as
    raw: bool
        Output all raw data
    already_loaded_stocks_data: Dict
        Dictionary of filtered stocks data that has been loaded before

    Returns
    -------
    dict
        Dictionary of filtered stocks data
    list
        List of tickers filtered
    """
    if already_loaded_stocks_data:
        stocks_data = already_loaded_stocks_data
    else:
        stocks_data = financedatabase_model.get_stocks_data(
            country, sector, industry, marketcap, exclude_exchanges)

    metric_data = {}
    for symbol in list(stocks_data.keys()):
        if finance_key in stocks_data[symbol] and "quoteType" in stocks_data[
                symbol]:
            stock_name = stocks_data[symbol]["quoteType"]["longName"]
            metric = (stocks_data[symbol][finance_key][finance_metric]
                      if stocks_data[symbol][finance_key] is not None
                      and finance_metric in stocks_data[symbol][finance_key]
                      else None)
            if metric and stock_name:
                metric_data[stock_name] = (metric, symbol)

    if len(metric_data) > 1:

        metric_data = dict(
            OrderedDict(
                sorted(metric_data.items(),
                       key=lambda t: t[1][0],
                       reverse=True)))

        company_names = list()
        company_metrics = list()
        company_tickers = list()
        for name, metric in metric_data.items():
            company_names.append(name)
            company_metrics.append(metric[0])
            company_tickers.append(metric[1])

        metric_finance_col = ("".join(
            " " + char if char.isupper() else char.strip()
            for char in finance_metric).strip().capitalize())

        df_all = pd.DataFrame({
            "Company": company_names,
            metric_finance_col: company_metrics
        })

        if len(df_all) > limit:
            console.print(
                f"Limiting the amount of companies displayed to {limit}.")

        company_name = np.array(company_names)[:limit]
        company_metric = np.array(company_metrics)[:limit]
        company_ticker = np.array(company_tickers)[:limit]

        df = df_all.head(limit)

        if raw:
            print_rich_table(df,
                             headers=list(df.columns),
                             show_index=False,
                             title="Bars Financials")
        else:
            plt.subplots(figsize=plot_autoscale(), dpi=PLOT_DPI)

            magnitude = 0
            while max(company_metric) > 1_000 or abs(
                    min(company_metric)) > 1_000:
                company_metric = np.divide(company_metric, 1_000)
                magnitude += 1

            # check if the value is a percentage
            if ((magnitude == 0) and all(company_metric >= 0)
                    and all(company_metric <= 1)):
                unit = "%"
                company_metric = company_metric * 100

            else:
                unit = " KMBTP"[magnitude]

            for name, metric, ticker in zip(company_name[::-1],
                                            company_metric[::-1],
                                            company_ticker[::-1]):
                if len(name.split(" ")) > 6 and len(name) > 40:
                    name = f'{" ".join(name.split(" ")[:4])}\n{" ".join(name.split(" ")[4:])}'
                plt.barh(name, metric, label=ticker)

            handles, _ = plt.gca().get_legend_handles_labels()
            plt.legend(reversed(handles),
                       reversed(company_ticker[::-1]),
                       loc="lower right")

            metric_title = ("".join(
                " " + char if char.isupper() else char.strip()
                for char in finance_metric).strip().capitalize())

            benchmark = np.median(company_metric)
            plt.axvline(x=benchmark, lw=3, ls="--", c="k")

            if unit != " ":
                units = f" [{unit}] "
            else:
                units = " "

            title = f"{metric_title.capitalize()}{units}with benchmark of {benchmark:.2f} {unit}\n"
            title += marketcap + " cap companies " if marketcap else "Companies "
            if industry:
                title += f"in {industry} industry\n"
            elif sector:
                title += f"in {sector} sector\n"

            if country:
                title += f"in {country}"
                title += " " if (industry or sector) else "\n"

            title += ("(excluding data from international exchanges)"
                      if exclude_exchanges else
                      "(including data from international exchanges)")

            plt.title(title)
            if gtff.USE_ION:
                plt.ion()
            plt.tight_layout()
            plt.show()

        export_data(
            export,
            os.path.dirname(os.path.abspath(__file__)),
            finance_metric,
            df_all,
        )

        if not export:
            console.print("")

        return stocks_data, company_tickers
Esempio n. 3
0
def display_bars_financials(
    finance_key: str,
    finance_metric: str,
    country: str,
    sector: str,
    industry: str,
    marketcap: str = "",
    exclude_exchanges: bool = True,
    limit: int = 10,
    export: str = "",
    raw: bool = False,
    already_loaded_stocks_data: Dict = None,
    external_axes: Optional[List[plt.Axes]] = None,
):
    """Display financials bars comparing sectors, industry, analysis, countries, market cap and excluding exchanges.

    Parameters
    ----------
    finance_key: str
        Select finance key from Yahoo Finance(e.g. financialData, defaultKeyStatistics, summaryProfile)
    finance_metric: str
        Select finance metric from Yahoo Finance (e.g. operatingCashflow, revenueGrowth, ebitda, freeCashflow)
    country: str
        Search by country to find stocks matching the criteria.
    sector : str
        Search by sector to find stocks matching the criteria.
    industry : str
        Search by industry to find stocks matching the criteria.
    marketcap : str
        Select stocks based on the market cap.
    exclude_exchanges: bool
        When you wish to include different exchanges use this boolean.
    limit: int
        Limit amount of companies displayed
    export: str
        Format to export data as
    raw: bool
        Output all raw data
    already_loaded_stocks_data: Dict
        Dictionary of filtered stocks data that has been loaded before
    external_axes : Optional[List[plt.Axes]], optional
        External axes (1 axis is expected in the list), by default None

    Returns
    -------
    dict
        Dictionary of filtered stocks data
    list
        List of tickers filtered
    """
    if already_loaded_stocks_data:
        stocks_data = already_loaded_stocks_data
    else:
        stocks_data = financedatabase_model.get_stocks_data(
            country, sector, industry, marketcap, exclude_exchanges)

    metric_data = {}
    for symbol in list(stocks_data.keys()):
        if finance_key in stocks_data[symbol] and "quoteType" in stocks_data[
                symbol]:
            stock_name = stocks_data[symbol]["quoteType"]["longName"]
            metric = (stocks_data[symbol][finance_key][finance_metric]
                      if stocks_data[symbol][finance_key] is not None
                      and finance_metric in stocks_data[symbol][finance_key]
                      else None)
            if metric and stock_name:
                metric_data[stock_name] = (metric, symbol)

    if len(metric_data) > 1:

        metric_data = dict(
            OrderedDict(
                sorted(metric_data.items(),
                       key=lambda t: t[1][0],
                       reverse=True)))

        company_names = list()
        company_metrics = list()
        company_tickers = list()
        for name, metric in metric_data.items():
            company_names.append(name)
            company_metrics.append(metric[0])
            company_tickers.append(metric[1])

        metric_finance_col = ("".join(
            " " + char if char.isupper() else char.strip()
            for char in finance_metric).strip().capitalize())

        df_all = pd.DataFrame({
            "Company": company_names,
            metric_finance_col: company_metrics
        })

        if len(df_all) > limit:
            console.print(
                f"Limiting the amount of companies displayed to {limit}.")

        company_name = np.array(company_names)[:limit]
        company_metric = np.array(company_metrics)[:limit]
        company_ticker = np.array(company_tickers)[:limit]

        df = df_all.head(limit)

        if raw:
            print_rich_table(df,
                             headers=list(df.columns),
                             show_index=False,
                             title="Bars Financials")
        else:

            # This plot has 1 axis
            if not external_axes:
                _, ax = plt.subplots(figsize=plot_autoscale(), dpi=PLOT_DPI)
            else:
                if len(external_axes) != 1:
                    logger.error("Expected list of one axis item.")
                    console.print(
                        "[red]Expected list of one axis item./n[/red]")
                    # set returns statement to be compatible with others
                    return dict(), list()
                (ax, ) = external_axes

            magnitude = 0
            while max(company_metric) > 1_000 or abs(
                    min(company_metric)) > 1_000:
                company_metric = np.divide(company_metric, 1_000)
                magnitude += 1

            # check if the value is a percentage
            if ((magnitude == 0) and all(company_metric >= 0)
                    and all(company_metric <= 1)):
                unit = "%"
                company_metric = company_metric * 100

            else:
                unit = " KMBTP"[magnitude] if magnitude != 0 else ""

            colors = iter(theme.get_colors())
            for name, metric, ticker in zip(company_name[::-1],
                                            company_metric[::-1],
                                            company_ticker[::-1]):
                if len(name.split(" ")) > 6 and len(name) > 40:
                    name = f'{" ".join(name.split(" ")[:4])}\n{" ".join(name.split(" ")[4:])}'
                ax.barh(f"{name} ({ticker})",
                        metric,
                        label=ticker,
                        color=next(colors))

            metric_title = ("".join(
                " " + char if char.isupper() else char.strip()
                for char in finance_metric).strip().capitalize())

            benchmark = np.median(company_metric)
            ax.axvline(x=benchmark, lw=3, ls="--", c="grey")

            title = f"The {metric_title.title()} (benchmark: {benchmark:.2f}{unit}) of "
            title += marketcap + " cap companies " if marketcap else "Companies "
            if industry:
                title += f"in {industry} industry "
            elif sector:
                title += f"in {sector} sector "

            if country:
                title += f"in {country}"
                title += " " if (industry or sector) else ""

            title += ("(excl. data from international exchanges)"
                      if exclude_exchanges else
                      "(incl. data from international exchanges)")

            ax.set_title(title, wrap=True, fontsize=11)

            labels = ax.get_xticks().tolist()
            ax.set_xticks(labels)
            ax.set_xticklabels([f"{label}{unit}" for label in labels])

            theme.style_primary_axis(ax)

            if not external_axes:
                theme.visualize_output()

        export_data(
            export,
            os.path.dirname(os.path.abspath(__file__)),
            finance_metric,
            df_all,
        )

        return stocks_data, company_tickers
Esempio n. 4
0
def metric_command(
    finance_key: str,
    finance_metric: str,
    ticker: str = "",
):
    """Display financials bars comparing sectors, industry, analysis, countries, market cap and excluding exchanges.

    Parameters
    ----------
    finance_key: str
        Select finance key from Yahoo Finance(e.g. financialData, defaultKeyStatistics, summaryProfile)
    finance_metric: str
        Select finance metric from Yahoo Finance (e.g. operatingCashflow, revenueGrowth, ebitda, freeCashflow)
    ticker: str
        Company ticker to use as the basis.
    """
    logger.info("metrics")
    exclude_exchanges: bool = True
    limit: int = 10
    ticker = ticker.lower()
    if ticker:
        data = yfinance.utils.get_json(f"https://finance.yahoo.com/quote/{ticker}")

        if "summaryProfile" in data:
            country = data["summaryProfile"]["country"]
            if country not in financedatabase_model.get_countries():
                similar_cmd = difflib.get_close_matches(
                    country,
                    financedatabase_model.get_countries(),
                    n=1,
                    cutoff=0.7,
                )
                if similar_cmd:
                    country = similar_cmd[0]
            sector = data["summaryProfile"]["sector"]
            if sector not in financedatabase_model.get_sectors():
                similar_cmd = difflib.get_close_matches(
                    sector,
                    financedatabase_model.get_sectors(),
                    n=1,
                    cutoff=0.7,
                )
                if similar_cmd:
                    sector = similar_cmd[0]
            industry = data["summaryProfile"]["industry"]
            if industry not in financedatabase_model.get_industries():
                similar_cmd = difflib.get_close_matches(
                    industry,
                    financedatabase_model.get_industries(),
                    n=1,
                    cutoff=0.7,
                )
                if similar_cmd:
                    industry = similar_cmd[0]
            if "price" in data:
                mktcap = data["price"]["marketCap"]
                if mktcap < 2_000_000_000:
                    mktcap = "Small"
                elif mktcap > 10_000_000_000:
                    mktcap = "Large"
                else:
                    mktcap = "Mid"

    stocks_data = financedatabase_model.get_stocks_data(
        country, sector, industry, mktcap, exclude_exchanges
    )

    metric_data = {}
    for symbol in list(stocks_data.keys()):
        if finance_key in stocks_data[symbol] and "quoteType" in stocks_data[symbol]:
            stock_name = stocks_data[symbol]["quoteType"]["longName"]
            metric = (
                stocks_data[symbol][finance_key][finance_metric]
                if stocks_data[symbol][finance_key] is not None
                and finance_metric in stocks_data[symbol][finance_key]
                else None
            )
            if metric and stock_name:
                metric_data[stock_name] = (metric, symbol)

    if len(metric_data) > 1:

        metric_data = dict(
            OrderedDict(
                sorted(metric_data.items(), key=lambda t: t[1][0], reverse=True)
            )
        )

        company_names = list()
        company_metrics = list()
        company_tickers = list()
        for name, metric in metric_data.items():
            company_names.append(name)
            company_metrics.append(metric[0])
            company_tickers.append(metric[1])

        company_name = np.array(company_names)[:limit]
        company_metric = np.array(company_metrics)[:limit]
        company_ticker = np.array(company_tickers)[:limit]

        magnitude = 0
        while max(company_metric) > 1_000 or abs(min(company_metric)) > 1_000:
            company_metric = np.divide(company_metric, 1_000)
            magnitude += 1

        # check if the value is a percentage
        if (magnitude == 0) and all(company_metric >= 0) and all(company_metric <= 1):
            unit = "%"
            company_metric = company_metric * 100

        else:
            unit = " KMBTP"[magnitude]

        colors = [
            "#ffed00",
            "#ef7d00",
            "#e4003a",
            "#c13246",
            "#822661",
            "#48277c",
            "#005ca9",
            "#00aaff",
            "#9b30d9",
            "#af005f",
            "#5f00af",
            "#af87ff",
        ]

        fig = go.Figure()

        i = 0
        for name, metric, tickers in zip(
            company_name[::-1], company_metric[::-1], company_ticker[::-1]
        ):
            if len(name.split(" ")) > 6 and len(name) > 40:
                name = (
                    f'{" ".join(name.split(" ")[:4])}\n{" ".join(name.split(" ")[4:])}'
                )
            df_name = []
            df_metric = []
            df_tickers = []
            df_name.append(name)
            df_metric.append(metric)
            df_tickers.append(tickers)
            fig.add_trace(
                go.Bar(
                    name=tickers,
                    y=[name],
                    x=[metric],
                    orientation="h",
                    marker=dict(
                        color=colors[i],
                        line=dict(color="rgb(248, 248, 249)", width=1),
                    ),
                ),
            )
            i += 1

        metric_title = (
            "".join(
                " " + char if char.isupper() else char.strip()
                for char in finance_metric
            )
            .strip()
            .capitalize()
        )

        benchmark = np.median(company_metric)
        if unit != " ":
            units = f" [{unit}] "
        else:
            units = " "

        title = f"{metric_title.capitalize()}{units}with benchmark of {benchmark:.2f} {unit}<br>"
        title += mktcap + " cap companies " if mktcap else "Companies "
        if industry:
            title += f"in {industry} industry<br>"
        elif sector:
            title += f"in {sector} sector<br>"

        if country:
            title += f"in {country}"
            title += " " if (industry or sector) else "<br>"

        title += (
            "(excl. data from international exchanges)"
            if exclude_exchanges
            else "(incl. data from international exchanges)"
        )
        fig.add_vline(
            x=benchmark,
            fillcolor="grey",
            opacity=1,
            layer="below",
            line_width=3,
            line=dict(color="grey", dash="dash"),
        )
        if imps.PLT_WATERMARK:
            fig.add_layout_image(imps.PLT_WATERMARK)
        fig.update_layout(
            margin=dict(l=40, r=0, t=100, b=20),
            template=imps.PLT_CANDLE_STYLE_TEMPLATE,
            title=title,
            colorway=colors,
            font=imps.PLT_FONT,
            legend={"traceorder": "reversed"},
        )
        imagefile = "sia_metrics.png"

        # Check if interactive settings are enabled
        plt_link = ""
        if imps.INTERACTIVE:
            plt_link = imps.inter_chart(fig, imagefile, callback=False)

        fig.update_layout(
            width=800,
            height=500,
        )

        imagefile = imps.image_border(imagefile, fig=fig)

        return {
            "title": "Stocks - Sector and Industry Analysis",
            "description": plt_link,
            "imagefile": imagefile,
        }