예제 #1
0
 def update_runtime_choices(self):
     """Update runtime choices"""
     if session and gtff.USE_PROMPT_TOOLKIT:
         self.choices["industry"] = {
             i: None
             for i in financedatabase_model.get_industries(
                 country=self.country, sector=self.sector)
         }
         self.choices["sector"] = {
             s: None
             for s in financedatabase_model.get_sectors(
                 industry=self.industry, country=self.country)
         }
         self.choices["country"] = {
             c: None
             for c in financedatabase_model.get_countries(
                 industry=self.industry, sector=self.sector)
         }
         self.completer = NestedCompleter.from_nested_dict(self.choices)
예제 #2
0
    def call_industry(self, other_args: List[str]):
        """Process industry command"""
        parser = argparse.ArgumentParser(
            add_help=False,
            formatter_class=argparse.ArgumentDefaultsHelpFormatter,
            prog="industry",
            description=
            "See existing industries, or set industry if arg specified",
        )
        parser.add_argument(
            "-n",
            "--name",
            type=str,
            dest="name",
            nargs="+",
            help="industry to select",
        )
        if other_args and "-" not in other_args[0][0]:
            other_args.insert(0, "-n")
        ns_parser = parse_known_args_and_warn(parser, other_args)
        if ns_parser:
            possible_industries = financedatabase_model.get_industries(
                country=self.country,
                sector=self.sector,
            )
            if ns_parser.name:
                if " ".join(ns_parser.name) in possible_industries:
                    self.industry = " ".join(ns_parser.name)
                    # if we get the industry, then we also automatically know the sector
                    self.sector = financedatabase_model.get_sectors(
                        industry=self.industry)[0]
                    self.update_runtime_choices()
                else:
                    console.print(
                        f"Industry '{' '.join(ns_parser.name)}' does not exist."
                    )
                    similar_cmd = difflib.get_close_matches(
                        " ".join(ns_parser.name),
                        possible_industries,
                        n=1,
                        cutoff=0.75,
                    )
                    if similar_cmd:
                        console.print(f"Replacing by '{similar_cmd[0]}'")
                        self.industry = similar_cmd[0]
                        # if we get the industry, then we also automatically know the sector
                        self.sector = financedatabase_model.get_sectors(
                            industry=self.industry)[0]
                        self.update_runtime_choices()
                    else:
                        similar_cmd = difflib.get_close_matches(
                            " ".join(ns_parser.name),
                            possible_industries,
                            n=1,
                            cutoff=0.5,
                        )
                        if similar_cmd:
                            console.print(f"Did you mean '{similar_cmd[0]}'?")
            else:
                for industry in possible_industries:
                    console.print(industry)

            self.stocks_data = {}
            console.print("")
예제 #3
0
    def call_load(self, other_args: List[str]):
        """Process load command"""
        parser = argparse.ArgumentParser(
            add_help=False,
            formatter_class=argparse.ArgumentDefaultsHelpFormatter,
            prog="load",
            description=
            "Load stock ticker and alter the industry, sector, country and market cap "
            "accordingly for this ticker.",
        )
        parser.add_argument(
            "-t",
            "--ticker",
            action="store",
            dest="ticker",
            required="-h" not in other_args,
            help="Stock ticker",
        )
        if other_args and "-" not in other_args[0][0]:
            other_args.insert(0, "-t")
        ns_parser = parse_known_args_and_warn(parser, other_args)
        if ns_parser:
            df_stock_candidate = stocks_helper.load(ns_parser.ticker, )
            if not df_stock_candidate.empty:
                if "." in ns_parser.ticker:
                    self.ticker = ns_parser.ticker.upper().split(".")[0]
                else:
                    self.ticker = ns_parser.ticker.upper()

                data = yf.utils.get_json(
                    f"https://finance.yahoo.com/quote/{self.ticker}")

                if "summaryProfile" in data:
                    self.country = data["summaryProfile"]["country"]
                    if self.country not in financedatabase_model.get_countries(
                    ):
                        similar_cmd = difflib.get_close_matches(
                            self.country,
                            financedatabase_model.get_countries(),
                            n=1,
                            cutoff=0.7,
                        )
                        if similar_cmd:
                            self.country = similar_cmd[0]

                    self.sector = data["summaryProfile"]["sector"]
                    if self.sector not in financedatabase_model.get_sectors():
                        similar_cmd = difflib.get_close_matches(
                            self.sector,
                            financedatabase_model.get_sectors(),
                            n=1,
                            cutoff=0.7,
                        )
                        if similar_cmd:
                            self.sector = similar_cmd[0]

                    self.industry = data["summaryProfile"]["industry"]
                    if self.industry not in financedatabase_model.get_industries(
                    ):
                        similar_cmd = difflib.get_close_matches(
                            self.industry,
                            financedatabase_model.get_industries(),
                            n=1,
                            cutoff=0.7,
                        )
                        if similar_cmd:
                            self.industry = similar_cmd[0]

                if "price" in data:
                    mktcap = data["price"]["marketCap"]

                    if mktcap < 2_000_000_000:
                        self.mktcap = "Small"
                    elif mktcap > 10_000_000_000:
                        self.mktcap = "Large"
                    else:
                        self.mktcap = "Mid"

                self.stocks_data = {}
                self.update_runtime_choices()
예제 #4
0
    def __init__(
        self,
        ticker: str,
        queue: List[str] = None,
    ):
        """Constructor"""
        super().__init__(queue)

        self.country = "United States"
        self.sector = "Financial Services"
        self.industry = "Financial Data & Stock Exchanges"
        self.mktcap = "Large"
        self.exclude_exchanges = True
        self.period = "Annual"

        self.ticker = ticker

        self.stocks_data: dict = {}
        self.tickers: List = list()
        self.currency: str = ""

        if ticker:
            data = yf.utils.get_json(
                f"https://finance.yahoo.com/quote/{ticker}")

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

        if session and gtff.USE_PROMPT_TOOLKIT:
            choices: dict = {c: {} for c in self.controller_choices}
            choices["mktcap"] = {c: None for c in self.mktcap_choices}
            choices["period"] = {c: None for c in self.period_choices}
            choices["clear"] = {c: None for c in self.clear_choices}
            choices["metric"] = {c: None for c in self.metric_choices}
            # This menu contains dynamic choices that may change during runtime
            self.choices = choices
            self.completer = NestedCompleter.from_nested_dict(choices)
def test_get_industries(country, recorder, sector):
    result = financedatabase_model.get_industries(country=country,
                                                  sector=sector)
    recorder.capture(result)
예제 #6
0
    def call_load(self, other_args: List[str]):
        """Process load command"""
        parser = argparse.ArgumentParser(
            add_help=False,
            formatter_class=argparse.ArgumentDefaultsHelpFormatter,
            prog="load",
            description=
            "Load stock ticker to perform analysis on. When the data source" +
            " is 'yf', an Indian ticker can be loaded by using '.NS' at the end,"
            + " e.g. 'SBIN.NS'. See available market in" +
            " https://help.yahoo.com/kb/exchanges-data-providers-yahoo-finance-sln2310.html.",
        )
        parser.add_argument(
            "-t",
            "--ticker",
            action="store",
            dest="ticker",
            required="-h" not in other_args,
            help="Stock ticker",
        )
        if other_args and "-" not in other_args[0][0]:
            other_args.insert(0, "-t")
        ns_parser = parse_known_args_and_warn(parser, other_args)
        if ns_parser:
            df_stock_candidate = stocks_helper.load(ns_parser.ticker, )
            if not df_stock_candidate.empty:
                if "." in ns_parser.ticker:
                    self.ticker = ns_parser.ticker.upper().split(".")[0]
                else:
                    self.ticker = ns_parser.ticker.upper()

                data = yf.utils.get_json(
                    f"https://finance.yahoo.com/quote/{self.ticker}")

                if "summaryProfile" in data:
                    self.country = data["summaryProfile"]["country"]
                    if self.country not in financedatabase_model.get_countries(
                    ):
                        similar_cmd = difflib.get_close_matches(
                            self.country,
                            financedatabase_model.get_countries(),
                            n=1,
                            cutoff=0.7,
                        )
                        if similar_cmd:
                            self.country = similar_cmd[0]

                    self.sector = data["summaryProfile"]["sector"]
                    if self.sector not in financedatabase_model.get_sectors():
                        similar_cmd = difflib.get_close_matches(
                            self.sector,
                            financedatabase_model.get_sectors(),
                            n=1,
                            cutoff=0.7,
                        )
                        if similar_cmd:
                            self.sector = similar_cmd[0]

                    self.industry = data["summaryProfile"]["industry"]
                    if self.industry not in financedatabase_model.get_industries(
                    ):
                        similar_cmd = difflib.get_close_matches(
                            self.industry,
                            financedatabase_model.get_industries(),
                            n=1,
                            cutoff=0.7,
                        )
                        if similar_cmd:
                            self.industry = similar_cmd[0]

                if "price" in data:
                    mktcap = data["price"]["marketCap"]

                    if mktcap < 2_000_000_000:
                        self.mktcap = "Small"
                    elif mktcap > 10_000_000_000:
                        self.mktcap = "Large"
                    else:
                        self.mktcap = "Mid"

                self.stocks_data = {}
                self.update_runtime_choices()
예제 #7
0
    def __init__(
        self,
        ticker: str,
        queue: List[str] = None,
    ):
        """Constructor"""
        self.sia_parser = argparse.ArgumentParser(add_help=False, prog="sia")
        self.sia_parser.add_argument(
            "cmd",
            choices=self.CHOICES,
        )

        self.completer: Union[None, NestedCompleter] = None

        if session and gtff.USE_PROMPT_TOOLKIT:
            self.choices: dict = {c: {} for c in self.CHOICES}
            self.choices["mktcap"] = {c: None for c in self.mktcap_choices}
            self.choices["clear"] = {c: None for c in self.clear_choices}
            self.choices["metric"] = {c: None for c in self.metric_choices}

        if queue:
            self.queue = queue
        else:
            self.queue = list()

        self.country = "United States"
        self.sector = "Financial Services"
        self.industry = "Financial Data & Stock Exchanges"
        self.mktcap = "Large"
        self.exclude_exhanges = True

        self.ticker = ticker

        self.stocks_data: dict = {}
        self.tickers: List = list()

        if ticker:
            data = yf.utils.get_json(
                f"https://finance.yahoo.com/quote/{ticker}")

            if "summaryProfile" in data:
                self.country = data["summaryProfile"]["country"]
                if self.country not in financedatabase_model.get_countries():
                    similar_cmd = difflib.get_close_matches(
                        self.country,
                        financedatabase_model.get_countries(),
                        n=1,
                        cutoff=0.7,
                    )
                    if similar_cmd:
                        self.country = similar_cmd[0]
                self.sector = data["summaryProfile"]["sector"]
                if self.sector not in financedatabase_model.get_sectors():
                    similar_cmd = difflib.get_close_matches(
                        self.sector,
                        financedatabase_model.get_sectors(),
                        n=1,
                        cutoff=0.7,
                    )
                    if similar_cmd:
                        self.sector = similar_cmd[0]
                self.industry = data["summaryProfile"]["industry"]
                if self.industry not in financedatabase_model.get_industries():
                    similar_cmd = difflib.get_close_matches(
                        self.industry,
                        financedatabase_model.get_industries(),
                        n=1,
                        cutoff=0.7,
                    )
                    if similar_cmd:
                        self.industry = similar_cmd[0]
            if "price" in data:
                mktcap = data["price"]["marketCap"]
                if mktcap < 2_000_000_000:
                    self.mktcap = "Small"
                elif mktcap > 10_000_000_000:
                    self.mktcap = "Large"
                else:
                    self.mktcap = "Mid"
예제 #8
0
def menu(
    ticker: str,
    queue: List[str] = None,
):
    """Sector and Industry Analysis Menu"""
    sia_controller = SectorIndustryAnalysisController(ticker, queue)
    an_input = "HELP_ME"

    while True:
        # There is a command in the queue
        if sia_controller.queue and len(sia_controller.queue) > 0:
            # If the command is quitting the menu we want to return in here
            if sia_controller.queue[0] in ("q", "..", "quit"):
                print("")
                if len(sia_controller.queue) > 1:
                    return sia_controller.queue[1:]
                return []

            # Consume 1 element from the queue
            an_input = sia_controller.queue[0]
            sia_controller.queue = sia_controller.queue[1:]

            # Print the current location because this was an instruction and we want user to know what was the action
            if an_input and an_input.split(
                    " ")[0] in sia_controller.CHOICES_COMMANDS:
                print(f"{get_flair()} /stocks/sia/ $ {an_input}")

        # Get input command from user
        else:
            # Display help menu when entering on this menu from a level above
            if an_input == "HELP_ME":
                sia_controller.print_help()

            # Get input from user using auto-completion
            if session and gtff.USE_PROMPT_TOOLKIT and sia_controller.choices:
                sia_controller.choices["industry"] = {
                    i: None
                    for i in financedatabase_model.get_industries(
                        country=sia_controller.country,
                        sector=sia_controller.sector)
                }
                sia_controller.choices["sector"] = {
                    s: None
                    for s in financedatabase_model.get_sectors(
                        industry=sia_controller.industry,
                        country=sia_controller.country)
                }
                sia_controller.choices["country"] = {
                    c: None
                    for c in financedatabase_model.get_countries(
                        industry=sia_controller.industry,
                        sector=sia_controller.sector)
                }
                completer = NestedCompleter.from_nested_dict(
                    sia_controller.choices)
                an_input = session.prompt(
                    f"{get_flair()} /stocks/sia/ $ ",
                    completer=completer,
                    search_ignore_case=True,
                )

            # Get input from user without auto-completion
            else:
                an_input = input(f"{get_flair()} /stocks/sia/ $ ")

        try:
            # Process the input command
            sia_controller.queue = sia_controller.switch(an_input)

        except SystemExit:
            print(
                f"\nThe command '{an_input}' doesn't exist on the /stocks/sia menu.",
                end="",
            )
            similar_cmd = difflib.get_close_matches(
                an_input.split(" ")[0] if " " in an_input else an_input,
                sia_controller.CHOICES,
                n=1,
                cutoff=0.7,
            )
            if similar_cmd:
                if " " in an_input:
                    candidate_input = (
                        f"{similar_cmd[0]} {' '.join(an_input.split(' ')[1:])}"
                    )
                    if candidate_input == an_input:
                        an_input = ""
                        sia_controller.queue = []
                        print("\n")
                        continue
                    an_input = candidate_input
                else:
                    an_input = similar_cmd[0]

                print(f" Replacing by '{an_input}'.")
                sia_controller.queue.insert(0, an_input)
            else:
                print("\n")
예제 #9
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,
        }