def historical(other_args: List[str], preset_loaded: str):
    """View historical price of stocks that meet preset

    Parameters
    ----------
    other_args : List[str]
        Command line arguments to be processed with argparse
    ticker : str
        Loaded preset filter
    """
    parser = argparse.ArgumentParser(
        add_help=False,
        prog="historical",
        description=
        """Historical price comparison between similar companies [Source: Yahoo Finance]
        """,
    )
    parser.add_argument(
        "--start",
        type=valid_date,
        default=datetime.datetime.now() - datetime.timedelta(days=6 * 30),
        dest="start",
        help=
        "The starting date (format YYYY-MM-DD) of the historical price to plot",
    )
    parser.add_argument(
        "-t",
        "--type",
        action="store",
        dest="type_candle",
        type=check_one_of_ohlca,
        default="a",  # in case it's adjusted close
        help=(
            "type of candles: o-open, h-high, l-low, c-close, a-adjusted close."
        ),
    )
    parser.add_argument(
        "-s",
        "--signal",
        action="store",
        dest="signal",
        type=str,
        default=None,
        help="Signal",
        choices=list(finviz_view.d_signals.keys()),
    )

    try:
        ns_parser = parse_known_args_and_warn(parser, other_args)
        if not ns_parser:
            return

        preset_filter = configparser.RawConfigParser()
        preset_filter.optionxform = str  # type: ignore
        preset_filter.read("gamestonk_terminal/screener/presets/" +
                           preset_loaded + ".ini")

        d_general = preset_filter["General"]
        d_filters = {
            **preset_filter["Descriptive"],
            **preset_filter["Fundamental"],
            **preset_filter["Technical"],
        }

        d_filters = {k: v for k, v in d_filters.items() if v}

        screen = ticker.Ticker()

        if ns_parser.signal:
            screen.set_filter(signal=finviz_view.d_signals[ns_parser.signal])
        else:
            if d_general["Signal"]:
                screen.set_filter(filters_dict=d_filters,
                                  signal=d_general["Signal"])
            else:
                screen.set_filter(filters_dict=d_filters)

        l_min = list()
        l_leg = list()
        plt.figure(figsize=plot_autoscale(), dpi=PLOT_DPI)

        l_stocks = screen.ScreenerView(verbose=0)

        if len(l_stocks) > 10:
            print(
                "\nThe limit of stocks to compare with are 10. Hence, 10 random similar stocks will be displayed.",
                "\nThe selected list will be:",
            )
            random.shuffle(l_stocks)
            l_stocks = sorted(l_stocks[:10])
            print(", ".join(l_stocks))

        while l_stocks:
            l_parsed_stocks = list()
            for symbol in l_stocks:
                try:
                    df_similar_stock = yf.download(
                        symbol,
                        start=datetime.datetime.strftime(
                            ns_parser.start, "%Y-%m-%d"),
                        progress=False,
                        threads=False,
                    )
                    if not df_similar_stock.empty:
                        plt.plot(
                            df_similar_stock.index,
                            df_similar_stock[d_candle_types[
                                ns_parser.type_candle]].values,
                        )
                        l_min.append(df_similar_stock.index[0])
                        l_leg.append(symbol)

                    l_parsed_stocks.append(symbol)
                except Exception as e:
                    print("")
                    print(e)
                    print(
                        "Disregard previous error, which is due to API Rate limits from Yahoo Finance."
                    )
                    print(
                        f"Because we like '{symbol}', and we won't leave without getting data from it."
                    )

            for parsed_stock in l_parsed_stocks:
                l_stocks.remove(parsed_stock)

        if ns_parser.signal:
            plt.title(
                f"Screener Historical Price using {finviz_view.d_signals[ns_parser.signal]} signal"
            )
        else:
            plt.title(
                f"Screener Historical Price using {preset_loaded} preset")

        plt.xlabel("Time")
        plt.ylabel("Share Price ($)")
        plt.legend(l_leg)
        plt.grid(b=True, which="major", color="#666666", linestyle="-")
        plt.minorticks_on()
        plt.grid(b=True,
                 which="minor",
                 color="#999999",
                 linestyle="-",
                 alpha=0.2)
        # ensures that the historical data starts from same datapoint
        plt.xlim([max(l_min), df_similar_stock.index[-1]])

        if gtff.USE_ION:
            plt.ion()

        plt.show()
        print("")
        return l_parsed_stocks

    except SystemExit:
        print("Similar companies need to be provided", "\n")
        return []
    except Exception as e:
        print(e, "\n")
        return []
Exemplo n.º 2
0
def historical(
    preset_loaded: str,
    limit: int = 10,
    start: datetime.datetime = datetime.datetime.now() -
    datetime.timedelta(days=6 * 30),
    type_candle: str = "a",
    normalize: bool = True,
    export: str = "",
    external_axes: Optional[List[plt.Axes]] = None,
) -> List[str]:
    """View historical price of stocks that meet preset

    Parameters
    ----------
    preset_loaded: str
        Preset loaded to filter for tickers
    limit: int
        Number of stocks to display
    start: datetime
        Start datetime to display historical data
    type_candle: str
        Type of candle to display
    normalize : bool
        Boolean to normalize all stock prices using MinMax
    export : str
        Export dataframe data to csv,json,xlsx file
    external_axes : Optional[List[plt.Axes]], optional
        External axes (1 axis is expected in the list), by default None"""
    screen = ticker.Ticker()
    if preset_loaded in finviz_model.d_signals:
        screen.set_filter(signal=finviz_model.d_signals[preset_loaded])

    else:
        preset_filter = configparser.RawConfigParser()
        preset_filter.optionxform = str  # type: ignore
        preset_filter.read(presets_path + preset_loaded + ".ini")

        d_general = preset_filter["General"]
        d_filters = {
            **preset_filter["Descriptive"],
            **preset_filter["Fundamental"],
            **preset_filter["Technical"],
        }

        d_filters = {k: v for k, v in d_filters.items() if v}

        if "Signal" in d_general and d_general["Signal"]:
            screen.set_filter(filters_dict=d_filters,
                              signal=d_general["Signal"])
        else:
            screen.set_filter(filters_dict=d_filters)

    l_stocks = screen.ScreenerView(verbose=0)
    limit_random_stocks = False

    if l_stocks:
        if len(l_stocks) > limit:
            random.shuffle(l_stocks)
            l_stocks = sorted(l_stocks[:limit])
            console.print(
                "\nThe limit of stocks to compare with are 10. Hence, 10 random similar stocks will be displayed.",
                f"\nThe selected list will be: {', '.join(l_stocks)}",
            )
            limit_random_stocks = True

        df_screener = yf.download(
            l_stocks, start=start, progress=False,
            threads=False)[d_candle_types[type_candle]][l_stocks]
        df_screener = df_screener[l_stocks]

        if np.any(df_screener.isna()):
            nan_tickers = df_screener.columns[
                df_screener.isna().sum() >= 1].to_list()
            console.print(
                f"NaN values found in: {', '.join(nan_tickers)}.  Replacing with zeros."
            )
            df_screener = df_screener.fillna(0)

        # 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]")
                # Return empty list to be compatible with the other return statement
                return []
            (ax, ) = external_axes

        # This puts everything on 0-1 scale for visualizing
        if normalize:
            mm_scale = MinMaxScaler()
            df_screener = pd.DataFrame(
                mm_scale.fit_transform(df_screener),
                columns=df_screener.columns,
                index=df_screener.index,
            )
        df_screener.plot(ax=ax)

        if limit_random_stocks:
            ax.set_title(
                f"Screener Historical Price with {preset_loaded}\non 10 random stocks"
            )
        else:
            ax.set_title(f"Screener Historical Price with {preset_loaded}")

        ax.set_ylabel(
            f"{['','Normalized'][normalize]} Share Price {['($)',''][normalize]}"
        )
        ax.legend()
        # ensures that the historical data starts from same datapoint
        ax.set_xlim([df_screener.index[0], df_screener.index[-1]])

        theme.style_primary_axis(ax)

        if not external_axes:
            theme.visualize_output()

        export_data(
            export,
            os.path.dirname(os.path.abspath(__file__)),
            "historical",
            df_screener,
        )

        return l_stocks

    console.print("No screener stocks found with this preset", "\n")
    return []
Exemplo n.º 3
0
def historical(
    preset_loaded: str,
    limit: int = 10,
    start: datetime.datetime = datetime.datetime.now()
    - datetime.timedelta(days=6 * 30),
    type_candle: str = "a",
    normalize: bool = True,
    export: str = "",
) -> List[str]:
    """View historical price of stocks that meet preset

    Parameters
    ----------
    preset_loaded: str
        Preset loaded to filter for tickers
    limit: int
        Number of stocks to display
    start: datetime
        Start datetime to display historical data
    type_candle: str
        Type of candle to display
    normalize : bool
        Boolean to normalize all stock prices using MinMax
    export : str
        Export dataframe data to csv,json,xlsx file
    """
    screen = ticker.Ticker()
    if preset_loaded in finviz_model.d_signals:
        screen.set_filter(signal=finviz_model.d_signals[preset_loaded])

    else:
        preset_filter = configparser.RawConfigParser()
        preset_filter.optionxform = str  # type: ignore
        preset_filter.read(presets_path + preset_loaded + ".ini")

        d_general = preset_filter["General"]
        d_filters = {
            **preset_filter["Descriptive"],
            **preset_filter["Fundamental"],
            **preset_filter["Technical"],
        }

        d_filters = {k: v for k, v in d_filters.items() if v}

        if "Signal" in d_general and d_general["Signal"]:
            screen.set_filter(filters_dict=d_filters, signal=d_general["Signal"])
        else:
            screen.set_filter(filters_dict=d_filters)

    l_stocks = screen.ScreenerView(verbose=0)
    limit_random_stocks = False

    if l_stocks:
        if len(l_stocks) > limit:
            random.shuffle(l_stocks)
            l_stocks = sorted(l_stocks[:limit])
            console.print(
                "\nThe limit of stocks to compare with are 10. Hence, 10 random similar stocks will be displayed.",
                f"\nThe selected list will be: {', '.join(l_stocks)}",
            )
            limit_random_stocks = True

        df_screener = yf.download(l_stocks, start=start, progress=False, threads=False)[
            d_candle_types[type_candle]
        ][l_stocks]
        df_screener = df_screener[l_stocks]

        if np.any(df_screener.isna()):
            nan_tickers = df_screener.columns[df_screener.isna().sum() >= 1].to_list()
            console.print(
                f"NaN values found in: {', '.join(nan_tickers)}.  Replacing with zeros."
            )
            df_screener = df_screener.fillna(0)

        fig, ax = plt.subplots(figsize=plot_autoscale(), dpi=PLOT_DPI)
        # This puts everything on 0-1 scale for visualizing
        if normalize:
            mm_scale = MinMaxScaler()
            df_screener = pd.DataFrame(
                mm_scale.fit_transform(df_screener),
                columns=df_screener.columns,
                index=df_screener.index,
            )
        df_screener.plot(ax=ax)
        if limit_random_stocks:
            ax.set_title(
                f"Screener Historical Price using {preset_loaded} on 10 of those stocks"
            )
        else:
            ax.set_title(f"Screener Historical Price using {preset_loaded}")
        ax.set_xlabel("Time")
        ax.set_ylabel(
            f"{['','Normalized'][normalize]} Share Price {['($)',''][normalize]}"
        )
        ax.grid(b=True, which="major", color="#666666", linestyle="-")
        ax.legend(l_stocks, bbox_to_anchor=(1.04, 1), loc="upper left")
        # ensures that the historical data starts from same datapoint
        ax.set_xlim([df_screener.index[0], df_screener.index[-1]])
        plt.gcf().autofmt_xdate()
        fig.tight_layout()
        if gtff.USE_ION:
            plt.ion()

        plt.show()
        console.print("")
        export_data(
            export,
            os.path.dirname(os.path.abspath(__file__)),
            "historical",
            df_screener,
        )

        return l_stocks

    console.print("No screener stocks found with this preset", "\n")
    return []
Exemplo n.º 4
0
async def historical_command(ctx, signal="", start=""):
    """Displays historical price comparison between similar companies [Yahoo Finance]"""
    try:

        # Debug user input
        if cfg.DEBUG:
            logger.debug("!stocks.scr.historical %s %s", signal, start)

        # Check for argument
        if signal == "" or signal not in list(so.d_signals_desc.keys):
            raise Exception("Invalid preset selected!")

        register_matplotlib_converters()

        screen = ticker.Ticker()

        if signal in finviz_model.d_signals:
            screen.set_filter(signal=finviz_model.d_signals[signal])

        else:
            preset_filter = configparser.RawConfigParser()
            preset_filter.optionxform = str  # type: ignore
            preset_filter.read(so.presets_path + signal + ".ini")

            d_general = preset_filter["General"]
            d_filters = {
                **preset_filter["Descriptive"],
                **preset_filter["Fundamental"],
                **preset_filter["Technical"],
            }

            d_filters = {k: v for k, v in d_filters.items() if v}

            if d_general["Signal"]:
                screen.set_filter(filters_dict=d_filters,
                                  signal=d_general["Signal"])
            else:
                screen.set_filter(filters_dict=d_filters)

        if start == "":
            start = datetime.now() - timedelta(days=365)
        else:
            start = datetime.strptime(start, cfg.DATE_FORMAT)

        # Output Data
        l_min = []
        l_leg = []
        l_stocks = screen.ScreenerView(verbose=0)

        if len(l_stocks) > 10:
            description = (
                "\nThe limit of stocks to compare with are 10. Hence, 10 random similar stocks will be displayed."
                "\nThe selected list will be: ")
            random.shuffle(l_stocks)
            l_stocks = sorted(l_stocks[:10])
            description = description + (", ".join(l_stocks))
            logger.debug(description)

        plt.figure(figsize=plot_autoscale(), dpi=PLOT_DPI)

        while l_stocks:
            l_parsed_stocks = []
            for symbol in l_stocks:
                try:
                    df_similar_stock = yf.download(
                        symbol,
                        start=datetime.strftime(start, "%Y-%m-%d"),
                        progress=False,
                        threads=False,
                    )
                    if not df_similar_stock.empty:
                        plt.plot(
                            df_similar_stock.index,
                            df_similar_stock["Adj Close"].values,
                        )
                        l_min.append(df_similar_stock.index[0])
                        l_leg.append(symbol)

                    l_parsed_stocks.append(symbol)
                except Exception as e:
                    error = (
                        f"{e}\nDisregard previous error, which is due to API Rate limits from Yahoo Finance. "
                        f"Because we like '{symbol}', and we won't leave without getting data from it."
                    )
                    embed = discord.Embed(
                        title=
                        "ERROR Stocks: [Yahoo Finance] Historical Screener",
                        colour=cfg.COLOR,
                        description=error,
                    )
                    embed.set_author(
                        name=cfg.AUTHOR_NAME,
                        icon_url=cfg.AUTHOR_ICON_URL,
                    )

                    await ctx.send(embed=embed)

            for parsed_stock in l_parsed_stocks:
                l_stocks.remove(parsed_stock)

        if signal:
            plt.title(
                f"Screener Historical Price using {finviz_model.d_signals[signal]} signal"
            )
        else:
            plt.title(f"Screener Historical Price using {signal} preset")

        plt.xlabel("Time")
        plt.ylabel("Share Price ($)")
        plt.legend(l_leg)
        plt.grid(b=True, which="major", color="#666666", linestyle="-")
        plt.minorticks_on()
        plt.grid(b=True,
                 which="minor",
                 color="#999999",
                 linestyle="-",
                 alpha=0.2)
        # ensures that the historical data starts from same datapoint
        plt.xlim([max(l_min), df_similar_stock.index[-1]])

        plt.savefig("scr_historical.png")
        uploaded_image = gst_imgur.upload_image("scr_historical.png",
                                                title="something")
        image_link = uploaded_image.link
        if cfg.DEBUG:
            logger.debug("Image URL: %s", image_link)
        title = "Stocks: [Yahoo Finance] Historical Screener"
        embed = discord.Embed(title=title,
                              description=description,
                              colour=cfg.COLOR)
        embed.set_author(
            name=cfg.AUTHOR_NAME,
            icon_url=cfg.AUTHOR_ICON_URL,
        )
        embed.set_image(url=image_link)
        os.remove("scr_historical.png")

        await ctx.send(embed=embed)

    except Exception as e:
        embed = discord.Embed(
            title="ERROR Stocks: [Yahoo Finance] Historical Screener",
            colour=cfg.COLOR,
            description=e,
        )
        embed.set_author(
            name=cfg.AUTHOR_NAME,
            icon_url=cfg.AUTHOR_ICON_URL,
        )

        await ctx.send(embed=embed)
Exemplo n.º 5
0
def historical_command(signal: str = "", start=""):
    """Displays historical price comparison between similar companies [Yahoo Finance]"""

    # Debug user input
    if imps.DEBUG:
        logger.debug("scr-historical %s %s", signal, start)

    # Check for argument
    if signal not in so.d_signals_desc:
        raise Exception("Invalid preset selected!")

    register_matplotlib_converters()

    screen = ticker.Ticker()

    if signal in finviz_model.d_signals:
        screen.set_filter(signal=finviz_model.d_signals[signal])

    else:
        preset_filter = configparser.RawConfigParser()
        preset_filter.optionxform = str  # type: ignore
        preset_filter.read(so.presets_path + signal + ".ini")

        d_general = preset_filter["General"]
        d_filters = {
            **preset_filter["Descriptive"],
            **preset_filter["Fundamental"],
            **preset_filter["Technical"],
        }

        d_filters = {k: v for k, v in d_filters.items() if v}

        if d_general["Signal"]:
            screen.set_filter(filters_dict=d_filters,
                              signal=d_general["Signal"])
        else:
            screen.set_filter(filters_dict=d_filters)

    if start == "":
        start = datetime.now() - timedelta(days=365)
    else:
        start = datetime.strptime(start, imps.DATE_FORMAT)

    # Output Data
    l_min = []
    l_leg = []
    l_stocks = screen.screener_view(verbose=0)

    if len(l_stocks) > 10:
        description = (
            "\nThe limit of stocks to compare with are 10. Hence, 10 random similar stocks will be displayed."
            "\nThe selected list will be: ")
        random.shuffle(l_stocks)
        l_stocks = sorted(l_stocks[:10])
        description = description + (", ".join(l_stocks))
        logger.debug(description)

    plt.figure(figsize=plot_autoscale(), dpi=PLOT_DPI)

    while l_stocks:
        l_parsed_stocks = []
        for symbol in l_stocks:
            try:
                df_similar_stock = yf.download(
                    symbol,
                    start=datetime.strftime(start, "%Y-%m-%d"),
                    progress=False,
                    threads=False,
                )
                if not df_similar_stock.empty:
                    plt.plot(
                        df_similar_stock.index,
                        df_similar_stock["Adj Close"].values,
                    )
                    l_min.append(df_similar_stock.index[0])
                    l_leg.append(symbol)

                l_parsed_stocks.append(symbol)
            except Exception as e:
                error = (
                    f"{e}\nDisregard previous error, which is due to API Rate limits from Yahoo Finance. "
                    f"Because we like '{symbol}', and we won't leave without getting data from it."
                )

                return {
                    "title":
                    "ERROR Stocks: [Yahoo Finance] Historical Screener",
                    "description": error,
                }

        for parsed_stock in l_parsed_stocks:
            l_stocks.remove(parsed_stock)

    if signal:
        plt.title(
            f"Screener Historical Price using {finviz_model.d_signals[signal]} signal"
        )
    else:
        plt.title(f"Screener Historical Price using {signal} preset")

    plt.xlabel("Time")
    plt.ylabel("Share Price ($)")
    plt.legend(l_leg)
    plt.grid(b=True, which="major", color="#666666", linestyle="-")
    plt.minorticks_on()
    plt.grid(b=True, which="minor", color="#999999", linestyle="-", alpha=0.2)
    # ensures that the historical data starts from same datapoint
    plt.xlim([max(l_min), df_similar_stock.index[-1]])
    imagefile = "scr_historical.png"

    dataBytesIO = io.BytesIO()
    plt.savefig(dataBytesIO)
    dataBytesIO.seek(0)
    plt.close("all")

    imagefile = imps.image_border(imagefile, base64=dataBytesIO)

    return {
        "title": "Stocks: [Yahoo Finance] Historical Screener",
        "description": description,
        "imagefile": imagefile,
    }