def test_get_short_interest_volume(recorder):
    result_df, price_list = stockgrid_model.get_short_interest_volume(
        ticker="PM", )

    recorder.capture(result_df)
    recorder.capture(price_list)
Example #2
0
async def psi_command(ctx, arg=""):
    """Gets price vs short interest volume plot from GST and sends it

    Parameters
    -----------
    arg: str
        ticker, -h or help

    Returns
    -------
    discord message
        Sends a message containing an image of price vs short interest volume of
         a given ticker to the user
    """

    try:
        # Debug
        if cfg.DEBUG:
            print(f"!stocks.dps.psi {arg}")

        # Help
        if arg == "-h" or arg == "help":
            help_txt = "Plot price vs short interest volume. [Source: Stockgrid]\n"
            help_txt += "\nPossible arguments:\n"
            help_txt += "<TICKER> Stock ticker. REQUIRED!\n"
            embed = discord.Embed(
                title="Stocks: [Stockgrid] Price vs Short Interest Volume HELP",
                description=help_txt,
                colour=cfg.COLOR,
            )
            embed.set_author(
                name=cfg.AUTHOR_NAME,
                icon_url=cfg.AUTHOR_ICON_URL,
            )

        else:
            if arg == "":
                title = "ERROR Stocks: [SEC] Failure-to-deliver"
                embed = discord.Embed(title=title, colour=cfg.COLOR)
                embed.set_author(
                    name=cfg.AUTHOR_NAME,
                    icon_url=cfg.AUTHOR_ICON_URL,
                )
                embed.set_description("No ticker entered."
                                      "\nEnter a valid ticker, example: GME")
                await ctx.send(embed=embed)
                if cfg.DEBUG:
                    print("ERROR: No ticker entered")
                return

            # Parse argument
            ticker = arg.upper()

            plt.ion()
            title = "Stocks: [Stockgrid] Price vs Short Interest Volume " + ticker
            embed = discord.Embed(title=title, colour=cfg.COLOR)
            embed.set_author(
                name=cfg.AUTHOR_NAME,
                icon_url=cfg.AUTHOR_ICON_URL,
            )

            try:
                df, prices = stockgrid_model.get_short_interest_volume(ticker)
            except Exception as e:
                title = (
                    f"ERROR Stocks: [Stockgrid] Price vs Short Interest Volume {arg}"
                )
                embed = discord.Embed(title=title, colour=cfg.COLOR)
                embed.set_author(
                    name=cfg.AUTHOR_NAME,
                    icon_url=cfg.AUTHOR_ICON_URL,
                )
                embed.set_description(f"Ticker given: {arg}"
                                      "\nEnter a valid ticker, example: GME")
                await ctx.send(embed=embed)
                if cfg.DEBUG:
                    print(
                        f"POSSIBLE ERROR: Wrong ticker parameter entered\n{e}")
                return

            _, axes = plt.subplots(
                2,
                1,
                dpi=PLOT_DPI,
                gridspec_kw={"height_ratios": [2, 1]},
            )

            axes[0].bar(
                df["date"],
                df["total_volume"] / 1_000_000,
                width=timedelta(days=1),
                color="b",
                alpha=0.4,
                label="Total Volume",
            )
            axes[0].bar(
                df["date"],
                df["short_volume"] / 1_000_000,
                width=timedelta(days=1),
                color="r",
                alpha=0.4,
                label="Short Volume",
            )

            axes[0].set_ylabel("Volume (1M)")
            ax2 = axes[0].twinx()
            ax2.plot(df["date"].values,
                     prices[len(prices) - len(df):],
                     c="k",
                     label="Price")
            ax2.set_ylabel("Price ($)")

            lines, labels = axes[0].get_legend_handles_labels()
            lines2, labels2 = ax2.get_legend_handles_labels()
            ax2.legend(lines + lines2, labels + labels2, loc="upper left")

            axes[0].grid()
            axes[0].ticklabel_format(style="plain", axis="y")
            plt.title(f"Price vs Short Volume Interest for {ticker}")
            plt.gcf().autofmt_xdate()

            axes[1].plot(
                df["date"].values,
                100 * df["short_volume%"],
                c="green",
                label="Short Vol. %",
            )

            axes[1].set_ylabel("Short Vol. %")

            axes[1].grid(axis="y")
            lines, labels = axes[1].get_legend_handles_labels()
            axes[1].legend(lines, labels, loc="upper left")
            axes[1].set_ylim([0, 100])
            file_name = ticker + "_psi.png"
            plt.savefig(file_name)
            plt.close("all")
            uploaded_image = gst_imgur.upload_image(file_name,
                                                    title="something")
            image_link = uploaded_image.link
            embed.set_image(url=image_link)
            os.remove(file_name)

        await ctx.send(embed=embed)

    except Exception as e:
        title = "INTERNAL ERROR"
        embed = discord.Embed(title=title, colour=cfg.COLOR)
        embed.set_author(
            name=cfg.AUTHOR_NAME,
            icon_url=cfg.AUTHOR_ICON_URL,
        )
        embed.set_description(
            "Try updating the bot, make sure DEBUG is True in the config "
            "and restart it.\nIf the error still occurs open a issue at: "
            "https://github.com/GamestonkTerminal/GamestonkTerminal/issues"
            f"\n{e}")
        await ctx.send(embed=embed)
        if cfg.DEBUG:
            print(e)
Example #3
0
async def psi_command(ctx, ticker: str = ""):
    """Price vs short interest volume [Stockgrid]"""

    try:
        # Debug user input
        if cfg.DEBUG:
            logger.debug("!stocks.dps.psi %s", ticker)

        # Check for argument
        if ticker == "":
            raise Exception("Stock ticker is required")

        ticker = ticker.upper()

        stock = yf.download(ticker, progress=False)
        if stock.empty:
            raise Exception("Stock ticker is invalid")

        # Retrieve data
        df, prices = stockgrid_model.get_short_interest_volume(ticker)

        # Debug user output
        if cfg.DEBUG:
            logger.debug(df.to_string())

        # Output data
        title = f"Stocks: [Stockgrid] Price vs Short Interest Volume {ticker}"
        embed = disnake.Embed(title=title, colour=cfg.COLOR)
        embed.set_author(
            name=cfg.AUTHOR_NAME,
            icon_url=cfg.AUTHOR_ICON_URL,
        )
        plt.style.use("seaborn")
        _, axes = plt.subplots(
            2,
            1,
            figsize=plot_autoscale(),
            dpi=PLOT_DPI,
            gridspec_kw={"height_ratios": [2, 1]},
        )

        axes[0].bar(
            df["date"],
            df["total_volume"] / 1_000_000,
            width=timedelta(days=1),
            color="b",
            alpha=0.4,
            label="Total Volume",
        )
        axes[0].bar(
            df["date"],
            df["short_volume"] / 1_000_000,
            width=timedelta(days=1),
            color="r",
            alpha=0.4,
            label="Short Volume",
        )

        axes[0].set_ylabel("Volume (1M)")
        ax2 = axes[0].twinx()
        ax2.plot(
            df["date"].values,
            prices[len(prices) - len(df):],  # noqa: E203
            c="k",
            label="Price",
        )
        ax2.set_ylabel("Price ($)")

        lines, labels = axes[0].get_legend_handles_labels()
        lines2, labels2 = ax2.get_legend_handles_labels()
        ax2.legend(lines + lines2, labels + labels2, loc="upper left")

        axes[0].grid()
        axes[0].ticklabel_format(style="plain", axis="y")
        plt.title(f"Price vs Short Volume Interest for {ticker}")
        plt.gcf().autofmt_xdate()

        axes[1].plot(
            df["date"].values,
            100 * df["short_volume%"],
            c="green",
            label="Short Vol. %",
        )

        axes[1].set_ylabel("Short Vol. %")

        axes[1].grid(axis="y")
        lines, labels = axes[1].get_legend_handles_labels()
        axes[1].legend(lines, labels, loc="upper left")
        axes[1].set_ylim([0, 100])
        file_name = ticker + "_psi.png"
        plt.savefig(file_name)
        imagefile = file_name

        img = Image.open(imagefile)
        print(img.size)
        im_bg = Image.open(cfg.IMG_BG)
        h = img.height + 240
        w = img.width + 520

        img = img.resize((w, h), Image.ANTIALIAS)
        x1 = int(0.5 * im_bg.size[0]) - int(0.5 * img.size[0])
        y1 = int(0.5 * im_bg.size[1]) - int(0.5 * img.size[1])
        x2 = int(0.5 * im_bg.size[0]) + int(0.5 * img.size[0])
        y2 = int(0.5 * im_bg.size[1]) + int(0.5 * img.size[1])
        img = img.convert("RGB")
        im_bg.paste(img, box=(x1 - 5, y1, x2 - 5, y2))
        im_bg.save(imagefile, "PNG", quality=100)

        image = Image.open(imagefile)
        image = autocrop_image(image, 0)
        image.save(imagefile, "PNG", quality=100)
        plt.close("all")
        uploaded_image = gst_imgur.upload_image(file_name, title="something")
        image_link = uploaded_image.link
        embed.set_image(url=image_link)
        os.remove(file_name)

        await ctx.send(embed=embed)

    except Exception as e:
        embed = disnake.Embed(
            title=
            f"ERROR Stocks: [Stockgrid] Price vs Short Interest Volume {ticker}",
            colour=cfg.COLOR,
            description=e,
        )
        embed.set_author(
            name=cfg.AUTHOR_NAME,
            icon_url=cfg.AUTHOR_ICON_URL,
        )

        await ctx.send(embed=embed, delete_after=30.0)
def short_interest_volume(
    ticker: str,
    num: int,
    raw: bool,
    export: str,
    external_axes: Optional[List[plt.Axes]] = None,
):
    """Plot price vs short interest volume. [Source: Stockgrid]

    Parameters
    ----------
    ticker : str
        Stock to plot for
    num : int
        Number of last open market days to show
    raw : bool
        Flag to print raw data instead
    export : str
        Export dataframe data to csv,json,xlsx file
    external_axes : Optional[List[plt.Axes]], optional
        External axes (3 axis is expected in the list), by default None

    """
    df, prices = stockgrid_model.get_short_interest_volume(ticker)

    if raw:
        df = df.sort_values(by="date", ascending=False)

        df["Short Vol. (1M)"] = df["short_volume"] / 1_000_000
        df["Short Vol. %"] = df["short_volume%"] * 100
        df["Short Exempt Vol. (1K)"] = df["short_exempt_volume"] / 1_000
        df["Total Vol. (1M)"] = df["total_volume"] / 1_000_000

        df = df[[
            "date",
            "Short Vol. (1M)",
            "Short Vol. %",
            "Short Exempt Vol. (1K)",
            "Total Vol. (1M)",
        ]]

        df.date = df.date.dt.date

        print_rich_table(
            df.iloc[:num],
            headers=list(df.columns),
            show_index=False,
            title="Price vs Short Volume",
        )
    else:

        # This plot has 3 axis
        if not external_axes:
            _, (ax, ax1) = plt.subplots(
                2,
                1,
                sharex=True,
                figsize=plot_autoscale(),
                dpi=PLOT_DPI,
                gridspec_kw={"height_ratios": [2, 1]},
            )
            ax2 = ax.twinx()
        else:
            if len(external_axes) != 3:
                logger.error("Expected list of three axis items.")
                console.print(
                    "[red]Expected list of three axis items./n[/red]")
                return
            (ax, ax1, ax2) = external_axes

        ax.bar(
            df["date"],
            df["total_volume"] / 1_000_000,
            width=timedelta(days=1),
            color=theme.up_color,
            label="Total Volume",
        )
        ax.bar(
            df["date"],
            df["short_volume"] / 1_000_000,
            width=timedelta(days=1),
            color=theme.down_color,
            label="Short Volume",
        )

        ax.set_ylabel("Volume (1M)")

        ax2.plot(
            df["date"].values,
            prices[len(prices) - len(df):],  # noqa: E203
            label="Price",
        )
        ax2.set_ylabel("Price ($)")

        lines, labels = ax.get_legend_handles_labels()
        lines2, labels2 = ax2.get_legend_handles_labels()
        ax2.legend(lines + lines2, labels + labels2, loc="upper left")

        ax.set_xlim(
            df["date"].values[max(0,
                                  len(df) - num)],
            df["date"].values[len(df) - 1],
        )

        ax.ticklabel_format(style="plain", axis="y")
        ax.set_title(f"Price vs Short Volume Interest for {ticker}")

        ax1.plot(
            df["date"].values,
            100 * df["short_volume%"],
            label="Short Vol. %",
        )

        ax1.set_xlim(
            df["date"].values[max(0,
                                  len(df) - num)],
            df["date"].values[len(df) - 1],
        )
        ax1.set_ylabel("Short Vol. %")

        lines, labels = ax1.get_legend_handles_labels()
        ax1.legend(lines, labels, loc="upper left")
        ax1.set_ylim([0, 100])

        theme.style_twin_axes(ax, ax2)
        theme.style_primary_axis(ax1)

        if not external_axes:
            theme.visualize_output()

    console.print("")

    export_data(
        export,
        os.path.dirname(os.path.abspath(__file__)),
        "shortint(stockgrid)",
        df,
    )
Example #5
0
def psi_command(ticker: str = ""):
    """Price vs short interest volume [Stockgrid]"""

    # Debug user input
    if cfg.DEBUG:
        logger.debug("dps-psi %s", ticker)

    # Check for argument
    if ticker == "":
        raise Exception("Stock ticker is required")

    ticker = ticker.upper()

    stock = yf.download(ticker, progress=False)
    if stock.empty:
        raise Exception("Stock ticker is invalid")

    # Retrieve data
    df, prices = stockgrid_model.get_short_interest_volume(ticker)

    # Debug user output
    if cfg.DEBUG:
        logger.debug(df.to_string())

    # Output data
    fig = make_subplots(
        rows=2,
        cols=1,
        shared_xaxes=True,
        vertical_spacing=0.06,
        row_width=[0.3, 0.6],
        specs=[[{
            "secondary_y": True
        }], [{
            "secondary_y": False
        }]],
    )
    fig.add_trace(
        go.Scatter(
            name=ticker,
            x=df["date"].values,
            y=prices[len(prices) - len(df):],
            line=dict(color="#fdc708", width=2),
            opacity=1,
            showlegend=False,
        ),
        row=1,
        col=1,
        secondary_y=False,
    )
    fig.add_trace(
        go.Bar(
            x=df["date"],
            y=df["total_volume"] / 1_000_000,
            name="Total Volume",
            yaxis="y2",
        ),
        row=1,
        col=1,
        secondary_y=True,
    )
    fig.add_trace(
        go.Bar(
            x=df["date"],
            y=df["short_volume"] / 1_000_000,
            name="Short Volume",
            yaxis="y2",
        ),
        row=1,
        col=1,
        secondary_y=True,
    )
    fig.add_trace(
        go.Scatter(
            name="Short Vol. %",
            x=df["date"].values,
            y=100 * df["short_volume%"],
            line=dict(width=2),
            opacity=1,
            showlegend=False,
        ),
        row=2,
        col=1,
        secondary_y=False,
    )
    fig.update_traces(hovertemplate="%{y:.2f}")
    fig.update_xaxes(showspikes=True, spikesnap="cursor", spikemode="across")
    fig.update_yaxes(showspikes=True, spikethickness=2)
    fig.update_layout(
        margin=dict(l=10, r=0, t=40, b=20),
        template=cfg.PLT_TA_STYLE_TEMPLATE,
        colorway=cfg.PLT_TA_COLORWAY,
        title=f"Price vs Short Volume Interest for {ticker}",
        title_x=0.45,
        yaxis_title="Stock Price ($)",
        yaxis2_title="FINRA Volume [M]",
        yaxis3_title="Short Vol. %",
        yaxis=dict(
            side="right",
            fixedrange=False,
            titlefont=dict(color="#fdc708"),
            tickfont=dict(color="#fdc708"),
            nticks=20,
        ),
        yaxis2=dict(
            side="left",
            fixedrange=False,
            anchor="x",
            overlaying="y",
            titlefont=dict(color="#d81aea"),
            tickfont=dict(color="#d81aea"),
            nticks=20,
        ),
        yaxis3=dict(
            fixedrange=False,
            titlefont=dict(color="#9467bd"),
            tickfont=dict(color="#9467bd"),
            nticks=20,
        ),
        xaxis=dict(
            rangeslider=dict(visible=False),
            type="date",
        ),
        dragmode="pan",
        legend=dict(orientation="h",
                    yanchor="bottom",
                    y=1.02,
                    xanchor="right",
                    x=1),
        hovermode="x unified",
        spikedistance=1000,
        hoverdistance=100,
    )
    config = dict({"scrollZoom": True})
    imagefile = "dps_psi.png"

    # Check if interactive settings are enabled
    plt_link = ""
    if cfg.INTERACTIVE:
        html_ran = helpers.uuid_get()
        fig.write_html(f"in/psi_{html_ran}.html", config=config)
        plt_link = f"[Interactive]({cfg.INTERACTIVE_URL}/psi_{html_ran}.html)"

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

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

    return {
        "title":
        f"Stocks: [Stockgrid] Price vs Short Interest Volume {ticker}",
        "description": plt_link,
        "imagefile": imagefile,
    }
def short_interest_volume(ticker: str, num: int, raw: bool, export: str):
    """Plot price vs short interest volume. [Source: Stockgrid]

    Parameters
    ----------
    ticker : str
        Stock to plot for
    num : int
        Number of last open market days to show
    raw : bool
        Flag to print raw data instead
    export : str
        Export dataframe data to csv,json,xlsx file
    """
    df, prices = stockgrid_model.get_short_interest_volume(ticker)

    if raw:
        df = df.sort_values(by="date", ascending=False)

        df["Short Vol. (1M)"] = df["short_volume"] / 1_000_000
        df["Short Vol. %"] = df["short_volume%"] * 100
        df["Short Exempt Vol. (1K)"] = df["short_exempt_volume"] / 1_000
        df["Total Vol. (1M)"] = df["total_volume"] / 1_000_000

        df = df[[
            "date",
            "Short Vol. (1M)",
            "Short Vol. %",
            "Short Exempt Vol. (1K)",
            "Total Vol. (1M)",
        ]]

        df.date = df.date.dt.date

        print(
            tabulate(
                df.iloc[:num],
                tablefmt="fancy_grid",
                floatfmt=".2f",
                headers=list(df.columns),
                showindex=False,
            ))
    else:
        _, axes = plt.subplots(
            2,
            1,
            figsize=(plot_autoscale()),
            dpi=PLOT_DPI,
            gridspec_kw={"height_ratios": [2, 1]},
        )

        axes[0].bar(
            df["date"],
            df["total_volume"] / 1_000_000,
            width=timedelta(days=1),
            color="b",
            alpha=0.4,
            label="Total Volume",
        )
        axes[0].bar(
            df["date"],
            df["short_volume"] / 1_000_000,
            width=timedelta(days=1),
            color="r",
            alpha=0.4,
            label="Short Volume",
        )

        axes[0].set_ylabel("Volume (1M)")
        ax2 = axes[0].twinx()
        ax2.plot(df["date"].values,
                 prices[len(prices) - len(df):],
                 c="k",
                 label="Price")
        ax2.set_ylabel("Price ($)")

        lines, labels = axes[0].get_legend_handles_labels()
        lines2, labels2 = ax2.get_legend_handles_labels()
        ax2.legend(lines + lines2, labels + labels2, loc="upper left")

        axes[0].set_xlim(
            df["date"].values[max(0,
                                  len(df) - num)],
            df["date"].values[len(df) - 1],
        )

        axes[0].grid()
        axes[0].ticklabel_format(style="plain", axis="y")
        plt.title(f"Price vs Short Volume Interest for {ticker}")
        plt.gcf().autofmt_xdate()

        axes[1].plot(
            df["date"].values,
            100 * df["short_volume%"],
            c="green",
            label="Short Vol. %",
        )

        axes[1].set_xlim(
            df["date"].values[max(0,
                                  len(df) - num)],
            df["date"].values[len(df) - 1],
        )
        axes[1].set_ylabel("Short Vol. %")

        axes[1].grid(axis="y")
        lines, labels = axes[1].get_legend_handles_labels()
        axes[1].legend(lines, labels, loc="upper left")
        axes[1].set_ylim([0, 100])

        if USE_ION:
            plt.ion()

        plt.show()
    print("")

    export_data(
        export,
        os.path.dirname(os.path.abspath(__file__)),
        "shortint(stockgrid)",
        df,
    )
Example #7
0
async def psi_command(ctx, ticker=""):
    """Price vs short interest volume [Stockgrid]"""

    try:
        # Debug user input
        if cfg.DEBUG:
            print(f"\n!stocks.dps.psi {ticker}")

        # Check for argument
        if ticker == "":
            raise Exception("Stock ticker is required")

        ticker = ticker.upper()

        stock = yf.download(ticker, progress=False)
        if stock.empty:
            raise Exception("Stock ticker is invalid")

        # Retrieve data
        df, prices = stockgrid_model.get_short_interest_volume(ticker)

        # Debug user output
        if cfg.DEBUG:
            print(df.to_string())

        # Output data
        title = f"Stocks: [Stockgrid] Price vs Short Interest Volume {ticker}"
        embed = discord.Embed(title=title, colour=cfg.COLOR)
        embed.set_author(
            name=cfg.AUTHOR_NAME,
            icon_url=cfg.AUTHOR_ICON_URL,
        )

        _, axes = plt.subplots(
            2,
            1,
            dpi=PLOT_DPI,
            gridspec_kw={"height_ratios": [2, 1]},
        )

        axes[0].bar(
            df["date"],
            df["total_volume"] / 1_000_000,
            width=timedelta(days=1),
            color="b",
            alpha=0.4,
            label="Total Volume",
        )
        axes[0].bar(
            df["date"],
            df["short_volume"] / 1_000_000,
            width=timedelta(days=1),
            color="r",
            alpha=0.4,
            label="Short Volume",
        )

        axes[0].set_ylabel("Volume (1M)")
        ax2 = axes[0].twinx()
        ax2.plot(
            df["date"].values, prices[len(prices) - len(df) :], c="k", label="Price"
        )
        ax2.set_ylabel("Price ($)")

        lines, labels = axes[0].get_legend_handles_labels()
        lines2, labels2 = ax2.get_legend_handles_labels()
        ax2.legend(lines + lines2, labels + labels2, loc="upper left")

        axes[0].grid()
        axes[0].ticklabel_format(style="plain", axis="y")
        plt.title(f"Price vs Short Volume Interest for {ticker}")
        plt.gcf().autofmt_xdate()

        axes[1].plot(
            df["date"].values,
            100 * df["short_volume%"],
            c="green",
            label="Short Vol. %",
        )

        axes[1].set_ylabel("Short Vol. %")

        axes[1].grid(axis="y")
        lines, labels = axes[1].get_legend_handles_labels()
        axes[1].legend(lines, labels, loc="upper left")
        axes[1].set_ylim([0, 100])
        file_name = ticker + "_psi.png"
        plt.savefig(file_name)
        plt.close("all")
        uploaded_image = gst_imgur.upload_image(file_name, title="something")
        image_link = uploaded_image.link
        embed.set_image(url=image_link)
        os.remove(file_name)

        await ctx.send(embed=embed)

    except Exception as e:
        embed = discord.Embed(
            title=f"ERROR Stocks: [Stockgrid] Price vs Short Interest Volume {ticker}",
            colour=cfg.COLOR,
            description=e,
        )
        embed.set_author(
            name=cfg.AUTHOR_NAME,
            icon_url=cfg.AUTHOR_ICON_URL,
        )

        await ctx.send(embed=embed)