Exemple #1
0
async def valuation_command(ctx, economy_group="sector"):
    """Valuation of sectors, industry, country [Finviz]"""

    d_economy_group = {
        "sector": "Sector",
        "industry": "Industry",
        "basic_materials": "Industry (Basic Materials)",
        "communication_services": "Industry (Communication Services)",
        "consumer_cyclical": "Industry (Consumer Cyclical)",
        "consumer_defensive": "Industry (Consumer Defensive)",
        "energy": "Industry (Energy)",
        "financial": "Industry (Financial)",
        "healthcare": "Industry (Healthcare)",
        "industrials": "Industry (Industrials)",
        "real_estate": "Industry (Real Estate)",
        "technology": "Industry (Technology)",
        "utilities": "Industry (Utilities)",
        "country": "Country (U.S. listed stocks only)",
        "capitalization": "Capitalization",
    }

    try:
        # Debug user input
        if cfg.DEBUG:
            logger.debug("!economy.valuation %s", economy_group)

        # Select default group
        if economy_group == "":
            if cfg.DEBUG:
                logger.debug("Use default economy_group: 'sector'")
            economy_group = "sector"

        # Check for argument
        possible_groups = list(d_economy_group.keys())

        if economy_group not in possible_groups:
            raise Exception(
                f"Select a valid group from {', '.join(possible_groups)}"  # nosec
            )

        group = d_economy_group[economy_group]

        # Retrieve data
        df_group = finviz_model.get_valuation_performance_data(group, "valuation")

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

        # Output data
        future_column_name = df_group["Name"]
        df_group = df_group.transpose()
        df_group.columns = future_column_name
        df_group.drop("Name")
        columns = []

        initial_str = "Page 0: Overview"
        i = 1
        for col_name in df_group.columns.values:
            initial_str += f"\nPage {i}: {col_name}"
            i += 1

        columns.append(
            discord.Embed(
                title=f"Economy: [Finviz] Valuation {group}",
                description=initial_str,
                colour=cfg.COLOR,
            ).set_author(
                name=cfg.AUTHOR_NAME,
                icon_url=cfg.AUTHOR_ICON_URL,
            )
        )
        for column in df_group.columns.values:
            columns.append(
                discord.Embed(
                    description="```" + df_group[column].fillna("").to_string() + "```",
                    colour=cfg.COLOR,
                ).set_author(
                    name=cfg.AUTHOR_NAME,
                    icon_url=cfg.AUTHOR_ICON_URL,
                )
            )

        await pagination(columns, ctx)

    except Exception as e:
        embed = discord.Embed(
            title="ERROR Economy: [Finviz] Valuation",
            colour=cfg.COLOR,
            description=e,
        )
        embed.set_author(
            name=cfg.AUTHOR_NAME,
            icon_url=cfg.AUTHOR_ICON_URL,
        )

        await ctx.send(embed=embed)
Exemple #2
0
async def vol_command(
    ctx,
    ticker: str = None,
    expiry: str = "",
    min_sp: float = None,
    max_sp: float = None,
):
    """Options VOL"""

    try:

        # Debug
        if cfg.DEBUG:
            logger.debug("!stocks.opt.vol %s %s %s %s", ticker, expiry, min_sp, max_sp)

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

        dates = yfinance_model.option_expirations(ticker)

        if not dates:
            raise Exception("Stock ticker is invalid")

        options = yfinance_model.get_option_chain(ticker, expiry)
        current_price = yfinance_model.get_price(ticker)

        if min_sp is None:
            min_strike = 0.75 * current_price
        else:
            min_strike = min_sp

        if max_sp is None:
            max_strike = 1.25 * current_price
        else:
            max_strike = max_sp

        calls = options.calls
        puts = options.puts
        call_v = calls.set_index("strike")["volume"] / 1000
        put_v = puts.set_index("strike")["volume"] / 1000
        plt.style.use("seaborn")
        fig, ax = plt.subplots(figsize=plot_autoscale(), dpi=cfp.PLOT_DPI)

        put_v.plot(
            x="strike",
            y="volume",
            label="Puts",
            ax=ax,
            marker="o",
            ls="-",
            c="r",
        )
        call_v.plot(
            x="strike",
            y="volume",
            label="Calls",
            ax=ax,
            marker="o",
            ls="-",
            c="g",
        )
        ax.axvline(
            current_price, lw=2, c="k", ls="--", label="Current Price", alpha=0.7
        )
        ax.grid("on")
        ax.set_xlabel("Strike Price")
        ax.set_ylabel("Volume (1k) ")
        ax.set_xlim(min_strike, max_strike)

        ax.set_title(f"Volume for {ticker.upper()} expiring {expiry}")
        plt.legend(loc=0)
        fig.tight_layout(pad=1)

        imagefile = "opt_vol.png"
        plt.savefig("opt_vol.png")
        image = discord.File(imagefile)

        if cfg.DEBUG:
            logger.debug("Image: %s", imagefile)
        title = f"Volume for {ticker.upper()} expiring {expiry}"
        embed = discord.Embed(title=title, colour=cfg.COLOR)
        embed.set_image(url="attachment://opt_vol.png")
        embed.set_author(
            name=cfg.AUTHOR_NAME,
            icon_url=cfg.AUTHOR_ICON_URL,
        )
        os.remove("opt_vol.png")

        await ctx.send(embed=embed, file=image)

    except Exception as e:
        embed = discord.Embed(
            title="ERROR Options: Volume",
            colour=cfg.COLOR,
            description=e,
        )
        embed.set_author(
            name=cfg.AUTHOR_NAME,
            icon_url=cfg.AUTHOR_ICON_URL,
        )

        await ctx.send(embed=embed)
Exemple #3
0
async def adosc_command(
    ctx, ticker="", is_open="False", fast="3", slow="10", start="", end=""
):
    """Displays chart with chaikin oscillator [Yahoo Finance]"""

    try:
        # Debug
        if cfg.DEBUG:
            # pylint: disable=logging-too-many-args
            logger.debug(
                "!stocks.ta.adosc %s %s %s %s %s",
                ticker,
                is_open,
                fast,
                slow,
                start,
                end,
            )

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

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

        if end == "":
            end = datetime.now()
        else:
            end = datetime.strptime(end, cfg.DATE_FORMAT)

        if not fast.lstrip("-").isnumeric():
            raise Exception("Number has to be an integer")
        fast = float(fast)
        if not slow.lstrip("-").isnumeric():
            raise Exception("Number has to be an integer")
        slow = float(slow)

        if is_open in ["false", "False", "FALSE", ""]:
            is_open = False

        if is_open in ["true", "True", "TRUE"]:
            is_open = True

        if is_open not in [True, False]:
            raise Exception("raw argument has to be true or false")

        ticker = ticker.upper()
        df_stock = discordbot.helpers.load(ticker, start)
        if df_stock.empty:
            raise Exception("Stock ticker is invalid")

        # Retrieve Data
        df_stock = df_stock.loc[(df_stock.index >= start) & (df_stock.index < end)]

        # Output Data
        bar_colors = [
            "r" if x[1].Open < x[1].Close else "g" for x in df_stock.iterrows()
        ]

        divisor = 1_000_000
        df_vol = df_stock["Volume"].dropna()
        df_vol = df_vol.values / divisor
        df_ta = volume_model.adosc(df_stock, is_open, fast, slow)
        df_cal = df_ta.values
        df_cal = df_cal / divisor

        fig, axes = plt.subplots(
            3,
            1,
            figsize=plot_autoscale(),
            dpi=PLOT_DPI,
        )
        ax = axes[0]
        ax.set_title(f"{ticker} AD Oscillator")
        ax.plot(df_stock.index, df_stock["Adj Close"].values, "fuchsia", lw=1)
        ax.set_xlim(df_stock.index[0], df_stock.index[-1])
        ax.set_ylabel("Price")
        ax.grid(b=True, which="major", color="#666666", linestyle="-")

        ax1 = axes[1]
        ax1.set_ylabel("Volume [M]")

        ax1.bar(
            df_stock.index,
            df_vol,
            color=bar_colors,
            alpha=0.8,
            width=0.3,
        )
        ax1.set_xlim(df_stock.index[0], df_stock.index[-1])

        ax2 = axes[2]
        ax2.set_ylabel("AD Osc [M]")
        ax2.set_xlabel("Time")
        ax2.plot(df_ta.index, df_cal, "b", lw=2, label="AD Osc")
        ax2.set_xlim(df_stock.index[0], df_stock.index[-1])
        ax2.grid(b=True, which="major", color="#666666", linestyle="-")

        plt.gcf().autofmt_xdate()
        fig.tight_layout(pad=1)
        plt.legend()

        plt.savefig("ta_adosc.png")
        uploaded_image = gst_imgur.upload_image("ta_adosc.png", title="something")
        image_link = uploaded_image.link
        if cfg.DEBUG:
            logger.debug("Image URL: %s", image_link)
        title = "Stocks: Accumulation/Distribution Oscillator " + ticker
        embed = discord.Embed(title=title, colour=cfg.COLOR)
        embed.set_author(
            name=cfg.AUTHOR_NAME,
            icon_url=cfg.AUTHOR_ICON_URL,
        )
        embed.set_image(url=image_link)
        os.remove("ta_adosc.png")

        await ctx.send(embed=embed)

    except Exception as e:
        embed = discord.Embed(
            title="ERROR Stocks: Accumulation/Distribution Oscillator",
            colour=cfg.COLOR,
            description=e,
        )
        embed.set_author(
            name=cfg.AUTHOR_NAME,
            icon_url=cfg.AUTHOR_ICON_URL,
        )

        await ctx.send(embed=embed)
Exemple #4
0
async def donchian_command(ctx,
                           ticker="",
                           upper_length="25",
                           lower_length="100",
                           start="",
                           end=""):
    """Displays chart with donchian channel [Yahoo Finance]"""

    try:

        # Debug
        if cfg.DEBUG:
            logger.debug(
                "!stocks.ta.donchian %s %s %s %s %s",
                ticker,
                upper_length,
                lower_length,
                start,
                end,
            )

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

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

        if end == "":
            end = datetime.now()
        else:
            end = datetime.strptime(end, cfg.DATE_FORMAT)

        if not upper_length.lstrip("-").isnumeric():
            raise Exception("Number has to be an integer")
        upper_length = float(upper_length)
        if not lower_length.lstrip("-").isnumeric():
            raise Exception("Number has to be an integer")
        lower_length = float(lower_length)

        ticker = ticker.upper()
        df_stock = discordbot.helpers.load(ticker, start)
        if df_stock.empty:
            raise Exception("Stock ticker is invalid")

        # Retrieve Data
        df_stock = df_stock.loc[(df_stock.index >= start)
                                & (df_stock.index < end)]

        df_ta = volatility_model.donchian(df_stock["High"], df_stock["Low"],
                                          upper_length, lower_length)

        # Output Data
        fig, ax = plt.subplots(figsize=plot_autoscale(), dpi=PLOT_DPI)
        ax.plot(df_stock.index, df_stock["Adj Close"].values, color="k", lw=3)
        ax.plot(df_ta.index,
                df_ta.iloc[:, 0].values,
                "b",
                lw=1.5,
                label="upper")
        ax.plot(df_ta.index, df_ta.iloc[:, 1].values, "b", lw=1.5, ls="--")
        ax.plot(df_ta.index,
                df_ta.iloc[:, 2].values,
                "b",
                lw=1.5,
                label="lower")
        ax.set_title(f"{ticker} donchian")
        ax.set_xlim(df_stock.index[0], df_stock.index[-1])
        ax.set_xlabel("Time")
        ax.set_ylabel("Price ($)")

        ax.legend(
            [ticker, df_ta.columns[0], df_ta.columns[1], df_ta.columns[2]])
        ax.fill_between(
            df_ta.index,
            df_ta.iloc[:, 0].values,
            df_ta.iloc[:, 2].values,
            alpha=0.1,
            color="b",
        )
        ax.grid(b=True, which="major", color="#666666", linestyle="-")

        plt.gcf().autofmt_xdate()
        fig.tight_layout(pad=1)

        plt.legend()

        plt.savefig("ta_donchian.png")
        uploaded_image = gst_imgur.upload_image("ta_donchian.png",
                                                title="something")
        image_link = uploaded_image.link
        if cfg.DEBUG:
            logger.debug("Image URL: %s", image_link)
        title = "Stocks: Donchian-Channels " + ticker
        embed = discord.Embed(title=title, colour=cfg.COLOR)
        embed.set_author(
            name=cfg.AUTHOR_NAME,
            icon_url=cfg.AUTHOR_ICON_URL,
        )
        embed.set_image(url=image_link)
        os.remove("ta_donchian.png")

        await ctx.send(embed=embed)

    except Exception as e:
        embed = discord.Embed(
            title="ERROR Stocks: Donchian-Channels",
            colour=cfg.COLOR,
            description=e,
        )
        embed.set_author(
            name=cfg.AUTHOR_NAME,
            icon_url=cfg.AUTHOR_ICON_URL,
        )

        await ctx.send(embed=embed)
Exemple #5
0
async def ad_command(ctx, ticker="", is_open="False", start="", end=""):
    """Displays chart with accumulation/distribution line [Yahoo Finance]"""

    try:

        # Debug
        if cfg.DEBUG:
            logger.debug("!stocks.ta.ad %s %s %s %s", ticker, is_open, start, end)

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

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

        if end == "":
            end = datetime.now()
        else:
            end = datetime.strptime(end, cfg.DATE_FORMAT)

        if is_open in ["false", "False", "FALSE", ""]:
            is_open = False

        if is_open in ["true", "True", "TRUE"]:
            is_open = True

        if is_open not in [True, False]:
            raise Exception("is_open argument has to be true or false")

        ticker = ticker.upper()
        df_stock = discordbot.helpers.load(ticker, start)
        if df_stock.empty:
            raise Exception("Stock ticker is invalid")

        # Retrieve Data
        df_stock = df_stock.loc[(df_stock.index >= start) & (df_stock.index < end)]

        bar_colors = [
            "r" if x[1].Open < x[1].Close else "g" for x in df_stock.iterrows()
        ]

        divisor = 1_000_000
        df_vol = df_stock["Volume"].dropna()
        df_vol = df_vol.values / divisor
        df_ta = volume_model.ad(df_stock, is_open)
        df_cal = df_ta.values
        df_cal = df_cal / divisor

        fig, axes = plt.subplots(
            3,
            1,
            gridspec_kw={"height_ratios": [2, 1, 1]},
            figsize=plot_autoscale(),
            dpi=PLOT_DPI,
        )
        ax = axes[0]
        ax.plot(df_stock.index, df_stock["Adj Close"].values, "k", lw=2)
        ax.set_title(f"{ticker} AD")
        ax.set_xlim(df_stock.index[0], df_stock.index[-1])
        ax.set_ylabel("Price")
        ax.grid(b=True, which="major", color="#666666", linestyle="-")

        ax2 = axes[1]
        ax2.set_ylabel("Volume [M]")
        ax2.bar(
            df_stock.index,
            df_vol,
            color=bar_colors,
            alpha=0.8,
            width=0.3,
        )
        ax2.set_xlim(df_stock.index[0], df_stock.index[-1])

        ax3 = axes[2]
        ax3.set_ylabel("A/D [M]")
        ax3.set_xlabel("Time")
        ax3.plot(df_ta.index, df_cal, "b", lw=1)
        ax3.set_xlim(df_stock.index[0], df_stock.index[-1])
        ax3.axhline(0, linewidth=2, color="k", ls="--")
        ax3.grid(b=True, which="major", color="#666666", linestyle="-")

        plt.gcf().autofmt_xdate()
        fig.tight_layout(pad=1)

        plt.savefig("ta_ad.png")
        uploaded_image = gst_imgur.upload_image("ta_ad.png", title="something")
        image_link = uploaded_image.link
        if cfg.DEBUG:
            logger.debug("Image URL: %s", image_link)
        title = "Stocks: Accumulation/Distribution Line " + ticker
        embed = discord.Embed(title=title, colour=cfg.COLOR)
        embed.set_author(
            name=cfg.AUTHOR_NAME,
            icon_url=cfg.AUTHOR_ICON_URL,
        )
        embed.set_image(url=image_link)
        os.remove("ta_ad.png")

        await ctx.send(embed=embed)

    except Exception as e:
        embed = discord.Embed(
            title="ERROR Stocks: Accumulation/Distribution Line",
            colour=cfg.COLOR,
            description=e,
        )
        embed.set_author(
            name=cfg.AUTHOR_NAME,
            icon_url=cfg.AUTHOR_ICON_URL,
        )

        await ctx.send(embed=embed)
Exemple #6
0
async def shorted_command(ctx, num="10"):
    """Show most shorted stocks [Yahoo Finance]"""

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

        # Check for argument
        if not num.lstrip("-").isnumeric():
            raise Exception("Number has to be an integer")

        num = int(num)

        if num < 0:
            raise Exception("Number has to be above 0")

        # Retrieve data
        df = yahoofinance_model.get_most_shorted().head(num)

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

        # Output data
        df.dropna(how="all", axis=1, inplace=True)
        df = df.replace(float("NaN"), "")
        future_column_name = df["Symbol"]
        df = df.transpose()
        df.columns = future_column_name
        df.drop("Symbol")
        columns = []

        initial_str = "Page 0: Overview"
        i = 1

        for col_name in df.columns.values:
            initial_str += f"\nPage {i}: {col_name}"
            i += 1

        columns.append(
            discord.Embed(
                title="Stocks: [Yahoo Finance] Most Shorted",
                description=initial_str,
                colour=cfg.COLOR,
            ).set_author(
                name=cfg.AUTHOR_NAME,
                icon_url=cfg.AUTHOR_ICON_URL,
            ))
        for column in df.columns.values:
            columns.append(
                discord.Embed(
                    description="```" + df[column].fillna("").to_string() +
                    "```",
                    colour=cfg.COLOR,
                ).set_author(
                    name=cfg.AUTHOR_NAME,
                    icon_url=cfg.AUTHOR_ICON_URL,
                ))

        await pagination(columns, ctx)

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

        await ctx.send(embed=embed)
Exemple #7
0
async def arktrades_command(ctx, ticker="", num=""):
    """Displays trades made by ark [cathiesark.com]"""

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

        if num == "":
            pass
        else:
            if not num.lstrip("-").isnumeric():
                raise Exception("Number has to be an integer")
            num = int(num)

        if ticker == "":
            raise Exception("A ticker is required")

        ark_holdings = ark_model.get_ark_trades_by_ticker(ticker)

        if ark_holdings.empty:
            raise Exception(
                "Issue getting data from cathiesark.com. Likely no trades found.\n"
            )

        ark_holdings = ark_holdings.drop(columns=["ticker"])
        ark_holdings["Total"] = ark_holdings["Total"] / 1_000_000
        ark_holdings.rename(columns={
            "Close": "Close ($)",
            "Total": "Total ($1M)"
        },
                            inplace=True)

        ark_holdings.index = pd.Series(
            ark_holdings.index).apply(lambda x: x.strftime("%Y-%m-%d"))

        if num == "":
            ark_holdings_str = ark_holdings.to_string()
        else:
            ark_holdings_str = ark_holdings.head(num).to_string()

        if len(ark_holdings_str) <= 4000:
            embed = discord.Embed(
                title=f"Stocks: [cathiesark.com] {ticker} Trades by Ark",
                description="```" + ark_holdings_str + "```",
                colour=cfg.COLOR,
            )
            embed.set_author(
                name=cfg.AUTHOR_NAME,
                icon_url=cfg.AUTHOR_ICON_URL,
            )

            await ctx.send(embed=embed)

        else:
            i = 0
            str_start = 0
            str_end = 4000
            columns = []
            while i <= len(ark_holdings_str) / 4000:
                columns.append(
                    discord.Embed(
                        title=
                        f"Stocks: [cathiesark.com] {ticker} Trades by Ark",
                        description="```" +
                        ark_holdings_str[str_start:str_end] + "```",
                        colour=cfg.COLOR,
                    ).set_author(
                        name=cfg.AUTHOR_NAME,
                        icon_url=cfg.AUTHOR_ICON_URL,
                    ))
                str_end = str_start
                str_start += 4000
                i += 1

            await pagination(columns, ctx)

    except Exception as e:
        embed = discord.Embed(
            title=f"ERROR Stocks: [cathiesark.com] {ticker} Trades by Ark",
            colour=cfg.COLOR,
            description=e,
        )
        embed.set_author(
            name=cfg.AUTHOR_NAME,
            icon_url=cfg.AUTHOR_ICON_URL,
        )

        await ctx.send(embed=embed)
Exemple #8
0
async def rsi_command(ctx,
                      ticker="",
                      length="14",
                      scalar="100",
                      drift="1",
                      start="",
                      end=""):
    """Displays chart with relative strength index [Yahoo Finance]"""

    try:

        # Debug
        if cfg.DEBUG:
            # pylint: disable=logging-too-many-args
            logger.debug(
                "!stocks.ta.rsi %s %s %s %s %s %s",
                ticker,
                length,
                scalar,
                drift,
                start,
                end,
            )

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

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

        if end == "":
            end = datetime.now()
        else:
            end = datetime.strptime(end, cfg.DATE_FORMAT)

        if not length.lstrip("-").isnumeric():
            raise Exception("Number has to be an integer")
        length = float(length)
        if not scalar.lstrip("-").isnumeric():
            raise Exception("Number has to be an integer")
        scalar = float(scalar)
        if not drift.lstrip("-").isnumeric():
            raise Exception("Number has to be an integer")
        drift = float(drift)

        ticker = ticker.upper()
        df_stock = discordbot.helpers.load(ticker, start)
        if df_stock.empty:
            raise Exception("Stock ticker is invalid")

        # Retrieve Data
        df_stock = df_stock.loc[(df_stock.index >= start)
                                & (df_stock.index < end)]
        df_ta = momentum_model.rsi(df_stock["Adj Close"], length, scalar,
                                   drift)

        # Output Data
        fig, axes = plt.subplots(2, 1, figsize=plot_autoscale(), dpi=PLOT_DPI)
        ax = axes[0]
        ax.plot(df_stock.index, df_stock["Adj Close"].values, "k", lw=2)
        ax.set_title(f" {ticker} RSI{length} ")
        ax.set_xlim(df_stock.index[0], df_stock.index[-1])
        ax.set_ylabel("Share Price ($)")
        ax.grid(b=True, which="major", color="#666666", linestyle="-")

        ax2 = axes[1]
        ax2.plot(df_ta.index, df_ta.values, "b", lw=2)
        ax2.set_xlim(df_stock.index[0], df_stock.index[-1])
        ax2.axhspan(70, 100, facecolor="r", alpha=0.2)
        ax2.axhspan(0, 30, facecolor="g", alpha=0.2)
        ax2.axhline(70, linewidth=3, color="r", ls="--")
        ax2.axhline(30, linewidth=3, color="g", ls="--")
        ax2.grid(b=True, which="major", color="#666666", linestyle="-")
        ax2.set_ylim([0, 100])
        ax3 = ax2.twinx()
        ax3.set_ylim(ax2.get_ylim())
        ax3.set_yticks([30, 70])
        ax3.set_yticklabels(["OVERSOLD", "OVERBOUGHT"])

        plt.gcf().autofmt_xdate()
        fig.tight_layout(pad=1)

        plt.savefig("ta_rsi.png")
        uploaded_image = gst_imgur.upload_image("ta_rsi.png",
                                                title="something")
        image_link = uploaded_image.link
        if cfg.DEBUG:
            logger.debug("Image URL: %s", image_link)
        title = "Stocks: Relative-Strength-Index " + ticker
        embed = discord.Embed(title=title, colour=cfg.COLOR)
        embed.set_author(
            name=cfg.AUTHOR_NAME,
            icon_url=cfg.AUTHOR_ICON_URL,
        )
        embed.set_image(url=image_link)
        os.remove("ta_rsi.png")

        await ctx.send(embed=embed)

    except Exception as e:
        embed = discord.Embed(
            title="ERROR Stocks: Relative-Strength-Index",
            colour=cfg.COLOR,
            description=e,
        )
        embed.set_author(
            name=cfg.AUTHOR_NAME,
            icon_url=cfg.AUTHOR_ICON_URL,
        )

        await ctx.send(embed=embed)
Exemple #9
0
async def cg_command(ctx, ticker="", length="14", start="", end=""):
    """Displays chart with centre of gravity [Yahoo Finance]"""

    try:

        # Debug
        if cfg.DEBUG:
            logger.debug(
                "!stocks.ta.cg %s %s %s %s",
                ticker,
                length,
                start,
                end,
            )

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

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

        if end == "":
            end = datetime.now()
        else:
            end = datetime.strptime(end, cfg.DATE_FORMAT)

        if not length.lstrip("-").isnumeric():
            raise Exception("Number has to be an integer")
        length = float(length)

        ticker = ticker.upper()
        df_stock = discordbot.helpers.load(ticker, start)
        if df_stock.empty:
            raise Exception("Stock ticker is invalid")

        # Retrieve Data
        df_stock = df_stock.loc[(df_stock.index >= start) & (df_stock.index < end)]
        df_close = df_stock["Adj Close"]
        df_close.columns = ["values"]
        df_ta = momentum_model.cg(df_close, length)

        # Output Data
        fig, axes = plt.subplots(2, 1, figsize=plot_autoscale(), dpi=PLOT_DPI)
        ax = axes[0]
        ax.set_title(f"{ticker} Centre of Gravity")
        ax.plot(df_stock.index, df_stock["Adj Close"].values, "k", lw=1)
        ax.set_xlim(df_stock.index[0], df_stock.index[-1])
        ax.set_ylabel("Share Price ($)")
        ax.grid(b=True, which="major", color="#666666", linestyle="-")

        ax2 = axes[1]
        ax2.plot(df_ta.index, df_ta.values, "b", lw=2, label="CG")
        # shift cg 1 bar forward for signal
        signal = df_ta.values
        signal = np.roll(signal, 1)
        ax2.plot(df_ta.index, signal, "g", lw=1, label="Signal")
        ax2.set_xlim(df_stock.index[0], df_stock.index[-1])
        ax2.grid(b=True, which="major", color="#666666", linestyle="-")

        plt.gcf().autofmt_xdate()
        fig.tight_layout(pad=1)
        plt.legend()

        plt.savefig("ta_cg.png")
        uploaded_image = gst_imgur.upload_image("ta_cg.png", title="something")
        image_link = uploaded_image.link
        if cfg.DEBUG:
            logger.debug("Image URL: %s", image_link)
        title = "Stocks: Center-of-Gravity " + ticker
        embed = discord.Embed(title=title, colour=cfg.COLOR)
        embed.set_author(
            name=cfg.AUTHOR_NAME,
            icon_url=cfg.AUTHOR_ICON_URL,
        )
        embed.set_image(url=image_link)
        os.remove("ta_cg.png")

        await ctx.send(embed=embed)

    except Exception as e:
        embed = discord.Embed(
            title="ERROR Stocks: Center-of-Gravity",
            colour=cfg.COLOR,
            description=e,
        )
        embed.set_author(
            name=cfg.AUTHOR_NAME,
            icon_url=cfg.AUTHOR_ICON_URL,
        )

        await ctx.send(embed=embed)
Exemple #10
0
async def pt_command(ctx, ticker="", raw="", start=""):
    """Displays price targets [Business Insider]"""

    try:
        # Debug
        if cfg.DEBUG:
            logger.debug("!stocks.dd.pt %s", ticker)

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

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

        if raw in ["false", "False", "FALSE", ""]:
            raw = False

        if raw in ["true", "True", "TRUE"]:
            raw = True

        if raw not in [True, False]:
            raise Exception("raw argument has to be true or false")

        df_analyst_data = business_insider_model.get_price_target_from_analysts(
            ticker)
        stock = discordbot.helpers.load(ticker, start)

        if df_analyst_data.empty or stock.empty:
            raise Exception("Enter valid ticker")

        # Output Data

        if raw:
            df_analyst_data.sort_index(ascending=False)
            report = "´´´" + df_analyst_data.to_string() + "´´´"
            embed = discord.Embed(
                title="Stocks: [Business Insider] Price Targets",
                description=report,
                colour=cfg.COLOR,
            ).set_author(
                name=cfg.AUTHOR_NAME,
                icon_url=cfg.AUTHOR_ICON_URL,
            )
            ctx.send(embed=embed)
        else:
            plt.figure(dpi=PLOT_DPI)
            if start:
                df_analyst_data = df_analyst_data[start:]

            plt.plot(stock.index, stock["Adj Close"].values, lw=3)

            plt.plot(df_analyst_data.groupby(by=["Date"]).mean())

            plt.scatter(df_analyst_data.index,
                        df_analyst_data["Price Target"],
                        c="r",
                        s=40)

            plt.legend(
                ["Closing Price", "Average Price Target", "Price Target"])

            plt.title(f"{ticker} (Time Series) and Price Target")
            plt.xlim(stock.index[0], stock.index[-1])
            plt.xlabel("Time")
            plt.ylabel("Share Price")
            plt.grid(b=True, which="major", color="#666666", linestyle="-")
            plt.gcf().autofmt_xdate()
            plt.savefig("ta_pt.png")
            uploaded_image = gst_imgur.upload_image("ta_pt.png",
                                                    title="something")
            image_link = uploaded_image.link
            if cfg.DEBUG:
                logger.debug("Image URL: %s", image_link)
            title = "Stocks: [Business Insider] Price Targets " + ticker
            embed = discord.Embed(title=title, colour=cfg.COLOR)
            embed.set_author(
                name=cfg.AUTHOR_NAME,
                icon_url=cfg.AUTHOR_ICON_URL,
            )
            embed.set_image(url=image_link)
            os.remove("ta_pt.png")

            await ctx.send(embed=embed)

    except Exception as e:
        embed = discord.Embed(
            title="ERROR Stocks: [Business Insider] Price Targets",
            colour=cfg.COLOR,
            description=e,
        )
        embed.set_author(
            name=cfg.AUTHOR_NAME,
            icon_url=cfg.AUTHOR_ICON_URL,
        )

        await ctx.send(embed=embed)
Exemple #11
0
async def contracts_command(ctx, ticker="", past_transaction_days="", raw=""):
    """Displays contracts associated with tickers [quiverquant.com]"""
    try:
        # Debug user input
        if cfg.DEBUG:
            logger.debug(
                "!stocks.gov.contracts %s %s %s", ticker, past_transaction_days, raw
            )

        if past_transaction_days == "":
            past_transaction_days = 10
        else:
            if not past_transaction_days.lstrip("-").isnumeric():
                raise Exception("Number has to be an integer")
            past_transaction_days = int(past_transaction_days)

        if raw in ["false", "False", "FALSE", ""]:
            raw = False

        if raw in ["true", "True", "TRUE"]:
            raw = True

        if raw not in [True, False]:
            raise Exception("raw argument has to be true or false")

        if ticker == "":
            raise Exception("A ticker is required")

        # Retrieve Data
        df_contracts = quiverquant_model.get_government_trading("contracts", ticker)

        if df_contracts.empty:
            raise Exception("No government contracts found")

        # Output Data
        df_contracts["Date"] = pd.to_datetime(df_contracts["Date"]).dt.date

        df_contracts = df_contracts[
            df_contracts["Date"].isin(
                df_contracts["Date"].unique()[:past_transaction_days]
            )
        ]

        df_contracts.drop_duplicates(inplace=True)

        fig, ax = plt.subplots(figsize=plot_autoscale(), dpi=PLOT_DPI)

        df_contracts.groupby("Date").sum().div(1000).plot(kind="bar", rot=0, ax=ax)
        ax.set_ylabel("Amount ($1k)")
        ax.set_title(f"Sum of latest government contracts to {ticker}")
        fig.tight_layout()

        plt.savefig("gov_contracts.png")
        uploaded_image = gst_imgur.upload_image("gov_contracts.png", title="something")
        image_link = uploaded_image.link
        if cfg.DEBUG:
            logger.debug("Image URL: %s", image_link)
        title = f"Stocks: [quiverquant.com] Contracts by {ticker}"
        if raw:
            description = df_contracts.to_string()
            embed = discord.Embed(
                title=title, description=description, colour=cfg.COLOR
            )
        else:
            embed = discord.Embed(title=title, colour=cfg.COLOR)
        embed.set_author(
            name=cfg.AUTHOR_NAME,
            icon_url=cfg.AUTHOR_ICON_URL,
        )
        embed.set_image(url=image_link)
        os.remove("gov_contracts.png")

        await ctx.send(embed=embed)

    except Exception as e:
        embed = discord.Embed(
            title=f"ERROR Stocks: [quiverquant.com] Contracts by {ticker}",
            colour=cfg.COLOR,
            description=e,
        )
        embed.set_author(
            name=cfg.AUTHOR_NAME,
            icon_url=cfg.AUTHOR_ICON_URL,
        )

        await ctx.send(embed=embed)
Exemple #12
0
async def aroon_command(ctx,
                        ticker="",
                        length="25",
                        scalar="100",
                        start="",
                        end=""):
    """Displays chart with aroon indicator [Yahoo Finance]"""

    try:

        # Debug
        if cfg.DEBUG:
            logger.debug(
                "!stocks.ta.aroon %s %s %s %s %s",
                ticker,
                length,
                scalar,
                start,
                end,
            )

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

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

        if end == "":
            end = datetime.now()
        else:
            end = datetime.strptime(end, cfg.DATE_FORMAT)

        if not length.lstrip("-").isnumeric():
            raise Exception("Number has to be an integer")
        length = int(length)
        if not scalar.lstrip("-").isnumeric():
            raise Exception("Number has to be an integer")
        scalar = float(scalar)

        ticker = ticker.upper()
        df_stock = discordbot.helpers.load(ticker, start)
        if df_stock.empty:
            raise Exception("Stock ticker is invalid")

        # Retrieve Data
        df_stock = df_stock.loc[(df_stock.index >= start)
                                & (df_stock.index < end)]

        df_ta = trend_indicators_model.aroon(df_stock["High"], df_stock["Low"],
                                             length, scalar)

        fig, ax = plt.subplots(3, 1, figsize=plot_autoscale(), dpi=PLOT_DPI)
        ax0 = ax[0]
        ax0.plot(df_stock.index, df_stock["Adj Close"].values, "k", lw=2)

        ax0.set_title(f"Aroon on {ticker}")
        ax0.set_xlim(df_stock.index[0], df_stock.index[-1])
        ax0.set_ylabel("Share Price ($)")
        ax0.grid(b=True, which="major", color="#666666", linestyle="-")

        ax1 = ax[1]
        ax1.plot(df_ta.index, df_ta.iloc[:, 0].values, "r", lw=2)
        ax1.plot(df_ta.index, df_ta.iloc[:, 1].values, "g", lw=2)
        ax1.set_xlim(df_stock.index[0], df_stock.index[-1])
        ax1.axhline(50, linewidth=1, color="k", ls="--")
        ax1.legend(
            [
                f"Aroon DOWN ({df_ta.columns[0]})",
                f"Aroon UP ({df_ta.columns[1]})"
            ],
            loc="upper left",
        )
        ax1.grid(b=True, which="major", color="#666666", linestyle="-")
        ax1.set_ylim([0, 100])

        ax2 = ax[2]
        ax2.plot(df_ta.index, df_ta.iloc[:, 2].values, "b", lw=2)
        ax2.set_xlim(df_stock.index[0], df_stock.index[-1])
        ax2.set_xlabel("Time")
        ax2.legend([f"Aroon OSC ({df_ta.columns[2]})"], loc="upper left")
        ax2.grid(b=True, which="major", color="#666666", linestyle="-")
        ax2.set_ylim([-100, 100])

        fig.tight_layout(pad=1)
        plt.gcf().autofmt_xdate()

        plt.savefig("ta_aroon.png")
        uploaded_image = gst_imgur.upload_image("ta_aroon.png",
                                                title="something")
        image_link = uploaded_image.link
        if cfg.DEBUG:
            logger.debug("Image URL: %s", image_link)
        title = "Stocks: Aroon-Indicator " + ticker
        embed = discord.Embed(title=title, colour=cfg.COLOR)
        embed.set_author(
            name=cfg.AUTHOR_NAME,
            icon_url=cfg.AUTHOR_ICON_URL,
        )
        embed.set_image(url=image_link)
        os.remove("ta_aroon.png")

        await ctx.send(embed=embed)

    except Exception as e:
        embed = discord.Embed(
            title="ERROR Stocks: Aroon-Indicator",
            colour=cfg.COLOR,
            description=e,
        )
        embed.set_author(
            name=cfg.AUTHOR_NAME,
            icon_url=cfg.AUTHOR_ICON_URL,
        )

        await ctx.send(embed=embed)
Exemple #13
0
async def fisher_command(ctx, ticker="", length="14", start="", end=""):
    """Displays chart with fisher transformation [Yahoo Finance]"""

    try:

        # Debug
        if cfg.DEBUG:
            logger.debug("!stocks.ta.fisher %s %s %s %s", ticker, length,
                         start, end)

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

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

        if end == "":
            end = datetime.now()
        else:
            end = datetime.strptime(end, cfg.DATE_FORMAT)

        if not length.lstrip("-").isnumeric():
            raise Exception("Number has to be an integer")
        length = int(length)

        ticker = ticker.upper()
        df_stock = discordbot.helpers.load(ticker, start)
        if df_stock.empty:
            raise Exception("Stock ticker is invalid")

        # Retrieve Data
        df_stock = df_stock.loc[(df_stock.index >= start)
                                & (df_stock.index < end)]

        df_ta = momentum_model.fisher(df_stock["High"], df_stock["Low"],
                                      length)

        # Output Data
        fig, axes = plt.subplots(2, 1, figsize=plot_autoscale(), dpi=PLOT_DPI)
        ax = axes[0]
        ax.set_title(f"{ticker} Fisher Transform")
        ax.plot(df_stock.index, df_stock["Adj Close"].values, "k", lw=1)
        ax.set_xlim(df_stock.index[0], df_stock.index[-1])
        ax.set_ylabel("Price")
        ax.grid(b=True, which="major", color="#666666", linestyle="-")

        ax2 = axes[1]
        ax2.plot(
            df_ta.index,
            df_ta.iloc[:, 0].values,
            "b",
            lw=2,
            label="Fisher",
        )
        ax2.plot(
            df_ta.index,
            df_ta.iloc[:, 1].values,
            "fuchsia",
            lw=2,
            label="Signal",
        )
        ax2.set_xlim(df_stock.index[0], df_stock.index[-1])
        ax2.axhspan(2, plt.gca().get_ylim()[1], facecolor="r", alpha=0.2)
        ax2.axhspan(plt.gca().get_ylim()[0], -2, facecolor="g", alpha=0.2)
        ax2.axhline(2, linewidth=3, color="r", ls="--")
        ax2.axhline(-2, linewidth=3, color="g", ls="--")
        ax2.grid(b=True, which="major", color="#666666", linestyle="-")
        ax2.set_xlim(df_stock.index[0], df_stock.index[-1])
        ax2.axhspan(2, plt.gca().get_ylim()[1], facecolor="r", alpha=0.2)
        ax2.axhspan(plt.gca().get_ylim()[0], -2, facecolor="g", alpha=0.2)
        ax2.axhline(2, linewidth=3, color="r", ls="--")
        ax2.axhline(-2, linewidth=3, color="g", ls="--")
        ax2.grid(b=True, which="major", color="#666666", linestyle="-")
        ax2.set_yticks([-2, 0, 2])
        ax2.set_yticklabels(["-2 STDEV", "0", "+2 STDEV"])

        plt.gcf().autofmt_xdate()
        fig.tight_layout(pad=1)

        plt.legend()

        plt.savefig("ta_fisher.png")
        uploaded_image = gst_imgur.upload_image("ta_fisher.png",
                                                title="something")
        image_link = uploaded_image.link
        if cfg.DEBUG:
            logger.debug("Image URL: %s", image_link)
        title = "Stocks: Fisher-Transform " + ticker
        embed = discord.Embed(title=title, colour=cfg.COLOR)
        embed.set_author(
            name=cfg.AUTHOR_NAME,
            icon_url=cfg.AUTHOR_ICON_URL,
        )
        embed.set_image(url=image_link)
        os.remove("ta_fisher.png")

        await ctx.send(embed=embed)

    except Exception as e:
        embed = discord.Embed(
            title="ERROR Stocks: Fisher-Transform",
            colour=cfg.COLOR,
            description=e,
        )
        embed.set_author(
            name=cfg.AUTHOR_NAME,
            icon_url=cfg.AUTHOR_ICON_URL,
        )

        await ctx.send(embed=embed)
Exemple #14
0
async def ftd_command(ctx, ticker="", start="", end=""):
    """Fails-to-deliver data [SEC]"""

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

        # 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")

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

        if end == "":
            end = datetime.now()
        else:
            end = datetime.strptime(end, cfg.DATE_FORMAT)

        # Retrieve data
        ftds_data = sec_model.get_fails_to_deliver(ticker, start, end, 0)

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

        plt.figure(dpi=PLOT_DPI)
        # Output data
        plt.bar(
            ftds_data["SETTLEMENT DATE"],
            ftds_data["QUANTITY (FAILS)"] / 1000,
        )
        plt.ylabel("Shares [K]")
        plt.title(f"Fails-to-deliver Data for {ticker}")
        plt.grid(b=True, which="major", color="#666666", linestyle="-", alpha=0.2)
        plt.gca().xaxis.set_major_formatter(mdates.DateFormatter("%Y/%m/%d"))
        plt.gca().xaxis.set_major_locator(mdates.DayLocator(interval=7))
        plt.gcf().autofmt_xdate()
        plt.xlabel("Days")
        _ = plt.gca().twinx()
        stock = discordbot.helpers.load(ticker, start)
        stock_ftd = stock[stock.index > start]
        stock_ftd = stock_ftd[stock_ftd.index < end]
        plt.plot(stock_ftd.index, stock_ftd["Adj Close"], color="tab:orange")
        plt.ylabel("Share Price [$]")
        plt.savefig("dps_ftd.png")
        plt.close("all")
        uploaded_image = gst_imgur.upload_image("dps_ftd.png", title="something")
        image_link = uploaded_image.link

        title = "Stocks: [SEC] Failure-to-deliver " + ticker
        embed = discord.Embed(title=title, colour=cfg.COLOR)
        embed.set_author(
            name=cfg.AUTHOR_NAME,
            icon_url=cfg.AUTHOR_ICON_URL,
        )
        embed.set_image(url=image_link)

        os.remove("dps_ftd.png")

        await ctx.send(embed=embed)

    except Exception as e:
        embed = discord.Embed(
            title=f"ERROR Stocks: [SEC] Failure-to-deliver {ticker}",
            colour=cfg.COLOR,
            description=e,
        )
        embed.set_author(
            name=cfg.AUTHOR_NAME,
            icon_url=cfg.AUTHOR_ICON_URL,
        )

        await ctx.send(embed=embed)
Exemple #15
0
async def technical_command(ctx, preset="template", sort="", limit="5", ascend="False"):
    """Displays stocks according to chosen preset, sorting by technical factors [Finviz]"""
    try:
        # Check for argument
        if preset == "template" or preset not in so.all_presets:
            raise Exception("Invalid preset selected!")

        # Debug
        if cfg.DEBUG:
            logger.debug(
                "!stocks.scr.technical %s %s %s %s", preset, sort, limit, ascend
            )

        # Check for argument
        if not limit.lstrip("-").isnumeric():
            raise Exception("Number has to be an integer")

        limit = int(limit)

        if limit < 0:
            raise Exception("Number has to be above 0")

        if ascend.lower() == "false":
            ascend = False
        elif ascend.lower() == "true":
            ascend = True
        else:
            raise Exception("ascend argument has to be true or false")

        # Output Data
        df_screen = get_screener_data(
            preset,
            "technical",
            limit,
            ascend,
        )

        description = ""

        if isinstance(df_screen, pd.DataFrame):
            if df_screen.empty:
                return []

            df_screen = df_screen.dropna(axis="columns", how="all")

            if sort:
                if " ".join(sort) in so.d_cols_to_sort["technical"]:
                    df_screen = df_screen.sort_values(
                        by=[" ".join(sort)],
                        ascending=ascend,
                        na_position="last",
                    )
                else:
                    similar_cmd = difflib.get_close_matches(
                        " ".join(sort),
                        so.d_cols_to_sort["technical"],
                        n=1,
                        cutoff=0.7,
                    )
                    if similar_cmd:
                        description = f"Replacing '{' '.join(sort)}' by '{similar_cmd[0]}' so table can be sorted.\n\n"
                        df_screen = df_screen.sort_values(
                            by=[similar_cmd[0]],
                            ascending=ascend,
                            na_position="last",
                        )
                    else:
                        raise ValueError(
                            f"Wrong sort column provided! Select from: {', '.join(so.d_cols_to_sort['technical'])}"
                        )

            df_screen = df_screen.fillna("")
            future_column_name = df_screen["Ticker"]
            df_screen = df_screen.head(n=limit).transpose()
            df_screen.columns = future_column_name
            df_screen.drop("Ticker")

            columns = []
            initial_str = description + "Page 0: Overview"
            i = 1
            for column in df_screen.columns.values:
                initial_str = initial_str + "\nPage " + str(i) + ": " + column
                i += 1
            columns.append(
                discord.Embed(
                    title="Stocks: [Finviz] Technical Screener",
                    description=initial_str,
                    colour=cfg.COLOR,
                ).set_author(
                    name=cfg.AUTHOR_NAME,
                    icon_url=cfg.AUTHOR_ICON_URL,
                )
            )
            for column in df_screen.columns.values:
                columns.append(
                    discord.Embed(
                        title="Stocks: [Finviz] Technical Screener",
                        description="```"
                        + df_screen[column].fillna("").to_string()
                        + "```",
                        colour=cfg.COLOR,
                    ).set_author(
                        name=cfg.AUTHOR_NAME,
                        icon_url=cfg.AUTHOR_ICON_URL,
                    )
                )

            await pagination(columns, ctx)

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

        await ctx.send(embed=embed)
Exemple #16
0
async def macd_command(ctx,
                       ticker="",
                       fast="12",
                       slow="26",
                       signal="9",
                       start="",
                       end=""):
    """Displays chart with moving average convergence/divergence [Yahoo Finance]"""

    try:

        # Debug
        if cfg.DEBUG:
            # pylint: disable=logging-too-many-args
            logger.debug(
                "!stocks.ta.macd %s %s %s %s %s %s",
                ticker,
                fast,
                slow,
                signal,
                start,
                end,
            )

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

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

        if end == "":
            end = datetime.now()
        else:
            end = datetime.strptime(end, cfg.DATE_FORMAT)

        if not fast.lstrip("-").isnumeric():
            raise Exception("Number has to be an integer")
        fast = float(fast)
        if not slow.lstrip("-").isnumeric():
            raise Exception("Number has to be an integer")
        slow = float(slow)
        if not signal.lstrip("-").isnumeric():
            raise Exception("Number has to be an integer")
        signal = float(signal)

        ticker = ticker.upper()
        df_stock = discordbot.helpers.load(ticker, start)
        if df_stock.empty:
            raise Exception("Stock ticker is invalid")

        # Retrieve Data
        df_stock = df_stock.loc[(df_stock.index >= start)
                                & (df_stock.index < end)]

        df_ta = momentum_model.macd(df_stock["Adj Close"], fast, slow, signal)

        # Output Data
        fig, axes = plt.subplots(2, 1, figsize=plot_autoscale(), dpi=PLOT_DPI)
        ax = axes[0]
        ax.set_title(f"{ticker} MACD")
        ax.plot(df_stock.index, df_stock["Adj Close"].values, "k", lw=2)
        ax.set_xlim(df_stock.index[0], df_stock.index[-1])
        ax.set_ylabel("Share Price ($)")
        ax.grid(b=True, which="major", color="#666666", linestyle="-")

        ax2 = axes[1]
        ax2.plot(df_ta.index, df_ta.iloc[:, 0].values, "b", lw=2)
        ax2.plot(df_ta.index, df_ta.iloc[:, 2].values, "r", lw=2)
        ax2.bar(df_ta.index, df_ta.iloc[:, 1].values, color="g")
        ax2.legend(
            [
                f"MACD Line {df_ta.columns[0]}",
                f"Signal Line {df_ta.columns[2]}",
                f"Histogram {df_ta.columns[1]}",
            ],
            loc="upper left",
        )
        ax2.set_xlim(df_stock.index[0], df_stock.index[-1])
        ax2.grid(b=True, which="major", color="#666666", linestyle="-")

        plt.gcf().autofmt_xdate()
        fig.tight_layout(pad=1)

        plt.savefig("ta_macd.png")
        uploaded_image = gst_imgur.upload_image("ta_macd.png",
                                                title="something")
        image_link = uploaded_image.link
        if cfg.DEBUG:
            logger.debug("Image URL: %s", image_link)
        title = "Stocks: Moving-Average-Convergence-Divergence " + ticker
        embed = discord.Embed(title=title, colour=cfg.COLOR)
        embed.set_author(
            name=cfg.AUTHOR_NAME,
            icon_url=cfg.AUTHOR_ICON_URL,
        )
        embed.set_image(url=image_link)
        os.remove("ta_macd.png")

        await ctx.send(embed=embed)

    except Exception as e:
        embed = discord.Embed(
            title="ERROR Stocks: Moving-Average-Convergence-Divergence",
            colour=cfg.COLOR,
            description=e,
        )
        embed.set_author(
            name=cfg.AUTHOR_NAME,
            icon_url=cfg.AUTHOR_ICON_URL,
        )

        await ctx.send(embed=embed)
Exemple #17
0
async def wma_command(ctx, ticker="", window="", offset="", start="", end=""):
    """Displays chart with weighted moving average [Yahoo Finance]"""

    try:
        # Debug
        if cfg.DEBUG:
            logger.debug(
                "!stocks.ta.wma %s %s %s %s %s",
                ticker,
                window,
                offset,
                start,
                end,
            )

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

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

        if end == "":
            end = datetime.now()
        else:
            end = datetime.strptime(end, cfg.DATE_FORMAT)

        l_legend = [ticker]

        if window == "":
            window = [20, 50]
        else:
            window_temp = list()
            for wind in window.split(","):
                try:
                    window_temp.append(float(wind))
                except Exception as e:
                    raise Exception("Window needs to be a float") from e
            window = window_temp

        if offset == "":
            offset = 0
        else:
            if not offset.lstrip("-").isnumeric():
                raise Exception("Number has to be an integer")
            offset = float(offset)

        ticker = ticker.upper()
        stock = discordbot.helpers.load(ticker, start)
        if stock.empty:
            raise Exception("Stock ticker is invalid")

        # Retrieve Data
        price_df = pd.DataFrame(stock["Adj Close"].values,
                                columns=["Price"],
                                index=stock.index)
        i = 1
        for win in window:
            wma_data = overlap_model.wma(values=stock["Adj Close"],
                                         length=win,
                                         offset=offset)
            price_df = price_df.join(wma_data)
            l_legend.append(f"WMA {win}")
            i += 1

        # Output Data
        start = start.strftime("%Y-%m-%d")
        end = end.strftime("%Y-%m-%d")
        price_df = price_df.loc[(price_df.index >= start)
                                & (price_df.index < end)]

        fig, ax = plt.subplots(figsize=plot_autoscale(), dpi=PLOT_DPI)
        ax.set_title(f"{ticker} WMA")

        ax.plot(price_df.index, price_df["Price"], lw=3, c="k")

        ax.set_xlabel("Time")
        ax.set_xlim([price_df.index[0], price_df.index[-1]])
        ax.set_ylabel(f"{ticker} Price")

        for idx in range(1, price_df.shape[1]):
            ax.plot(price_df.iloc[:, idx])

        ax.legend(l_legend)
        ax.grid(b=True, which="major", color="#666666", linestyle="-")

        plt.gcf().autofmt_xdate()
        fig.tight_layout(pad=1)

        plt.savefig("ta_wma.png")
        uploaded_image = gst_imgur.upload_image("ta_wma.png",
                                                title="something")
        image_link = uploaded_image.link
        if cfg.DEBUG:
            logger.debug("Image URL: %s", image_link)
        title = "Stocks: Weighted-Moving-Average " + ticker
        embed = discord.Embed(title=title, colour=cfg.COLOR)
        embed.set_author(
            name=cfg.AUTHOR_NAME,
            icon_url=cfg.AUTHOR_ICON_URL,
        )
        embed.set_image(url=image_link)
        os.remove("ta_wma.png")

        await ctx.send(embed=embed)

    except Exception as e:
        embed = discord.Embed(
            title="ERROR Stocks: Weighted-Moving-Average",
            colour=cfg.COLOR,
            description=e,
        )
        embed.set_author(
            name=cfg.AUTHOR_NAME,
            icon_url=cfg.AUTHOR_ICON_URL,
        )

        await ctx.send(embed=embed)
Exemple #18
0
async def gtrades_command(ctx,
                          ticker="",
                          gov_type="",
                          past_transactions_months="",
                          raw=""):
    """Displays government trades [quiverquant.com]"""
    try:
        # Debug user input
        if cfg.DEBUG:
            logger.debug(
                "!stocks.gov.gtrades %s %s %s %s",
                ticker,
                gov_type,
                past_transactions_months,
                raw,
            )

        if past_transactions_months == "":
            past_transactions_months = 10
        else:
            if not past_transactions_months.lstrip("-").isnumeric():
                raise Exception("Number has to be an integer")
            past_transactions_months = float(past_transactions_months)

        if raw in ["false", "False", "FALSE", ""]:
            raw = False

        if raw in ["true", "True", "TRUE"]:
            raw = True

        if raw not in [True, False]:
            raise Exception("raw argument has to be true or false")

        if ticker == "":
            raise Exception("A ticker is required")

        possible_args = ["congress", "senate", "house"]
        if gov_type == "":
            gov_type = "congress"
        elif gov_type not in possible_args:
            raise Exception(
                "Enter a valid government argument, options are: congress, senate and house"
            )

        # Retrieve Data
        df_gov = quiverquant_model.get_government_trading(gov_type, ticker)

        if df_gov.empty:
            raise Exception(f"No {gov_type} trading data found")

        # Output Data
        df_gov = df_gov.sort_values("TransactionDate", ascending=False)

        start_date = datetime.now() - timedelta(days=past_transactions_months *
                                                30)

        df_gov["TransactionDate"] = pd.to_datetime(df_gov["TransactionDate"])

        df_gov = df_gov[df_gov["TransactionDate"] > start_date]

        if df_gov.empty:
            logger.debug("No recent %s trading data found", gov_type)
            return

        df_gov["min"] = df_gov["Range"].apply(
            lambda x: x.split("-")[0].strip("$").replace(",", "").strip())
        df_gov["max"] = df_gov["Range"].apply(
            lambda x: x.split("-")[1].replace(",", "").strip().strip("$")
            if "-" in x else x.strip("$").replace(",", "").split("\n")[0])

        df_gov["lower"] = df_gov[["min", "max", "Transaction"]].apply(
            lambda x: int(float(x["min"]))
            if x["Transaction"] == "Purchase" else -int(float(x["max"])),
            axis=1,
        )
        df_gov["upper"] = df_gov[["min", "max", "Transaction"]].apply(
            lambda x: int(float(x["max"]))
            if x["Transaction"] == "Purchase" else -1 * int(float(x["min"])),
            axis=1,
        )

        df_gov = df_gov.sort_values("TransactionDate", ascending=True)

        fig, ax = plt.subplots(figsize=plot_autoscale(), dpi=PLOT_DPI)

        ax.fill_between(
            df_gov["TransactionDate"].unique(),
            df_gov.groupby("TransactionDate")["lower"].sum().values / 1000,
            df_gov.groupby("TransactionDate")["upper"].sum().values / 1000,
        )

        ax.set_xlim([
            df_gov["TransactionDate"].values[0],
            df_gov["TransactionDate"].values[-1],
        ])
        ax.grid()
        ax.set_title(f"{gov_type.capitalize()} trading on {ticker}")
        ax.set_xlabel("Date")
        ax.set_ylabel("Amount ($1k)")
        plt.gca().xaxis.set_major_formatter(mdates.DateFormatter("%Y/%m/%d"))
        plt.gcf().autofmt_xdate()
        fig.tight_layout()

        plt.savefig("gov_gtrades.png")
        uploaded_image = gst_imgur.upload_image("gov_gtrades.png",
                                                title="something")
        image_link = uploaded_image.link
        if cfg.DEBUG:
            logger.debug("Image URL: %s", image_link)
        title = "Stocks: [quiverquant.com] Government Trades"
        if raw:
            description = df_gov.to_string()
            embed = discord.Embed(title=title,
                                  description=description,
                                  colour=cfg.COLOR)
        else:
            embed = discord.Embed(title=title, colour=cfg.COLOR)
        embed.set_author(
            name=cfg.AUTHOR_NAME,
            icon_url=cfg.AUTHOR_ICON_URL,
        )
        embed.set_image(url=image_link)
        os.remove("gov_gtrades.png")

        await ctx.send(embed=embed)

    except Exception as e:
        embed = discord.Embed(
            title="ERROR Stocks: [quiverquant.com] Government Trades",
            colour=cfg.COLOR,
            description=e,
        )
        embed.set_author(
            name=cfg.AUTHOR_NAME,
            icon_url=cfg.AUTHOR_ICON_URL,
        )

        await ctx.send(embed=embed)
Exemple #19
0
async def sidtc_command(ctx, sort="float", num="10"):
    """Short interest and days to cover [Stockgrid]"""

    try:
        # Debug
        if cfg.DEBUG:
            logger.debug("!stocks.dps.sidtc %s %s", sort, num)

        # Check for argument
        possible_sorts = ("float", "dtc", "si")

        if sort not in possible_sorts:
            raise Exception(
                f"The possible sorts are: {', '.join(possible_sorts)}")

        if not num.lstrip("-").isnumeric():
            raise Exception("Number has to be an integer")

        num = int(num)

        if num < 0:
            raise Exception("Number has to be above 0")

        # Retrieve data
        df = stockgrid_model.get_short_interest_days_to_cover(sort)
        df = df.iloc[:num]

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

        # Output data
        dp_date = df["Date"].values[0]
        df = df.drop(columns=["Date"])
        df["Short Interest"] = df["Short Interest"] / 1_000_000
        df.head()
        df.columns = [
            "Ticker",
            "Float Short %",
            "Days to Cover",
            "Short Interest (1M)",
        ]
        future_column_name = df["Ticker"]
        df = df.transpose()
        df.columns = future_column_name
        df.drop("Ticker")
        columns = []
        initial_str = "Page 0: Overview"
        i = 1
        for column in df.columns.values:
            initial_str = initial_str + "\nPage " + str(i) + ": " + column
            i += 1
        columns.append(
            discord.Embed(title="Dark Pool Shorts",
                          description=initial_str,
                          colour=cfg.COLOR).set_author(
                              name=cfg.AUTHOR_NAME,
                              icon_url=cfg.AUTHOR_ICON_URL,
                          ))
        for column in df.columns.values:
            columns.append(
                discord.Embed(
                    title=
                    "Stocks: [Stockgrid] Short Interest and Days to Cover",
                    description=
                    "```The following data corresponds to the date: " +
                    dp_date + "\n\n" + df[column].fillna("").to_string() +
                    "```",
                    colour=cfg.COLOR,
                ).set_author(
                    name=cfg.AUTHOR_NAME,
                    icon_url=cfg.AUTHOR_ICON_URL,
                ))

        await pagination(columns, ctx)

    except Exception as e:
        embed = discord.Embed(
            title="ERROR Stocks: [Stockgrid] Short Interest and Days to Cover",
            colour=cfg.COLOR,
            description=e,
        )
        embed.set_author(
            name=cfg.AUTHOR_NAME,
            icon_url=cfg.AUTHOR_ICON_URL,
        )

        await ctx.send(embed=embed)
Exemple #20
0
async def calls_command(ctx, ticker: str = "", expiration_date: str = ""):
    """Show calls for given ticker and expiration"""
    try:
        # Debug
        if cfg.DEBUG:
            logger.debug("!stocks.opt.calls %s %s", ticker, expiration_date)

        # Check for argument
        if ticker == "":
            raise Exception("Stock ticker is required")
        calls = yf.Ticker(ticker).option_chain(expiration_date).calls.fillna(0)
        calls = calls[["strike", "bid", "ask", "volume", "openInterest"]]
        calls_string = tabulate(
            calls,
            headers=calls.columns,
            showindex=False,
            tablefmt="pipe",
            numalign="left",
            stralign="center",
        )
        if len(calls_string) <= 4000:
            embed = discord.Embed(
                title=
                f"Stocks: Call Options [yfinance] for {ticker} on {expiration_date}",
                description="```" + calls_string + "```",
                colour=cfg.COLOR,
            )
            embed.set_author(
                name=cfg.AUTHOR_NAME,
                icon_url=cfg.AUTHOR_ICON_URL,
            )
            await ctx.send(embed=embed)
        else:
            i = 0
            str_start = 0
            str_end = 4000
            columns = []
            while i <= len(calls_string) / 4000:
                columns.append(
                    discord.Embed(
                        title=
                        f"Stocks: Call Options [yfinance] for {ticker} on {expiration_date}",
                        description="```" + calls_string[str_start:str_end] +
                        "```",
                        colour=cfg.COLOR,
                    ).set_author(
                        name=cfg.AUTHOR_NAME,
                        icon_url=cfg.AUTHOR_ICON_URL,
                    ))
                str_end = str_start
                str_start += 4000
                i += 1

            await pagination(columns, ctx)

        await ctx.send(embed=embed)

    except Exception as e:
        embed = discord.Embed(
            title="ERROR Stock-Options: Expirations",
            colour=cfg.COLOR,
            description=e,
        )
        embed.set_author(
            name=cfg.AUTHOR_NAME,
            icon_url=cfg.AUTHOR_ICON_URL,
        )
        await ctx.send(embed=embed)
Exemple #21
0
async def qtrcontracts_command(ctx, num="", analysis=""):
    """Displays a look at government contracts [quiverquant.com]"""
    try:
        # Debug user input
        if cfg.DEBUG:
            logger.debug("!stocks.gov.qtrcontracts %s %s", num, analysis)

        if num == "":
            num = 20
        else:
            if not num.lstrip("-").isnumeric():
                raise Exception("Number has to be an integer")
            num = int(num)

        possible_args = ["total", "upmom", "downmom"]
        if analysis == "":
            analysis = "total"
        elif analysis not in possible_args:
            raise Exception(
                "Enter a valid analysis argument, options are: total, upmom and downmom"
            )

        # Retrieve Data
        df_contracts = quiverquant_model.get_government_trading(
            "quarter-contracts")

        if df_contracts.empty:
            raise Exception("No quarterly government contracts found")

        tickers = quiverquant_model.analyze_qtr_contracts(analysis, num)

        # Output Data
        if analysis in {"upmom", "downmom"}:
            description = tickers.to_string()
            fig, ax = plt.subplots(figsize=plot_autoscale(), dpi=PLOT_DPI)
            max_amount = 0
            quarter_ticks = []
            for symbol in tickers:
                amounts = (
                    df_contracts[df_contracts["Ticker"] == symbol].sort_values(
                        by=["Year", "Qtr"])["Amount"].values)

                qtr = (
                    df_contracts[df_contracts["Ticker"] == symbol].sort_values(
                        by=["Year", "Qtr"])["Qtr"].values)
                year = (
                    df_contracts[df_contracts["Ticker"] == symbol].sort_values(
                        by=["Year", "Qtr"])["Year"].values)

                ax.plot(np.arange(0, len(amounts)),
                        amounts / 1_000_000,
                        "-*",
                        lw=2,
                        ms=15)

                if len(amounts) > max_amount:
                    max_amount = len(amounts)
                    quarter_ticks = [
                        f"{quarter[0]} - Q{quarter[1]} "
                        for quarter in zip(year, qtr)
                    ]

            ax.set_xlim([-0.5, max_amount - 0.5])
            ax.set_xticks(np.arange(0, max_amount))
            ax.set_xticklabels(quarter_ticks)
            ax.grid()
            ax.legend(tickers)
            titles = {
                "upmom": "Highest increasing quarterly Government Contracts",
                "downmom": "Highest decreasing quarterly Government Contracts",
            }
            ax.set_title(titles[analysis])
            ax.set_xlabel("Date")
            ax.set_ylabel("Amount ($1M)")
            fig.tight_layout()

            plt.savefig("gov_qtrcontracts.png")
            uploaded_image = gst_imgur.upload_image("gov_qtrcontracts.png",
                                                    title="something")
            image_link = uploaded_image.link
            if cfg.DEBUG:
                logger.debug("Image URL: %s", image_link)
            title = "Stocks: [quiverquant.com] Government contracts"
            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("gov_qtrcontracts.png")

            await ctx.send(embed=embed)

        elif analysis == "total":

            tickers.index = [
                ind + " " * (7 - len(ind)) for ind in tickers.index
            ]
            tickers[:] = [
                str(round(val[0] / 1e9, 2)) for val in tickers.values
            ]
            tickers.columns = ["Amount [M]"]

            tickers_str = tabulate(
                tickers,
                headers=tickers.columns,
                showindex=True,
                numalign="right",
                stralign="center",
            )

            embed = discord.Embed(
                title="Stocks: [quiverquant.com] Government contracts",
                description=tickers_str,
                colour=cfg.COLOR,
            )
            embed.set_author(
                name=cfg.AUTHOR_NAME,
                icon_url=cfg.AUTHOR_ICON_URL,
            )

            await ctx.send(embed=embed)

    except Exception as e:
        embed = discord.Embed(
            title="ERROR Stocks: [quiverquant.com] Government contracts",
            colour=cfg.COLOR,
            description=e,
        )
        embed.set_author(
            name=cfg.AUTHOR_NAME,
            icon_url=cfg.AUTHOR_ICON_URL,
        )

        await ctx.send(embed=embed)
Exemple #22
0
async def histcont_command(ctx, ticker=""):
    """Displays historical quarterly-contracts [quiverquant.com]"""
    try:
        # Debug user input
        if cfg.DEBUG:
            logger.debug("!stocks.gov.histcont %s", ticker)

        if ticker == "":
            raise Exception("A ticker is required")

        # Retrieve Data
        df_contracts = quiverquant_model.get_government_trading(
            "quarter-contracts", ticker=ticker)

        if df_contracts.empty:
            logger.debug("No quarterly government contracts found")
            return

        # Output Data
        amounts = df_contracts.sort_values(by=["Year", "Qtr"])["Amount"].values

        qtr = df_contracts.sort_values(by=["Year", "Qtr"])["Qtr"].values
        year = df_contracts.sort_values(by=["Year", "Qtr"])["Year"].values

        quarter_ticks = [
            f"{quarter[0]}" if quarter[1] == 1 else ""
            for quarter in zip(year, qtr)
        ]
        fig, ax = plt.subplots(figsize=plot_autoscale(), dpi=PLOT_DPI)

        ax.plot(np.arange(0, len(amounts)), amounts / 1000, "-*", lw=2, ms=15)

        ax.set_xlim([-0.5, len(amounts) - 0.5])
        ax.set_xticks(np.arange(0, len(amounts)))
        ax.set_xticklabels(quarter_ticks)
        ax.grid()
        ax.set_title(
            f"Historical Quarterly Government Contracts for {ticker.upper()}")
        ax.set_xlabel("Date")
        ax.set_ylabel("Amount ($1k)")
        fig.tight_layout()

        plt.savefig("gov_histcont.png")
        uploaded_image = gst_imgur.upload_image("gov_histcont.png",
                                                title="something")
        image_link = uploaded_image.link
        if cfg.DEBUG:
            logger.debug("Image URL: %s", image_link)
        title = "Stocks: Historical Quarterly Government Contract " + ticker
        embed = discord.Embed(title=title, colour=cfg.COLOR)
        embed.set_author(
            name=cfg.AUTHOR_NAME,
            icon_url=cfg.AUTHOR_ICON_URL,
        )
        embed.set_image(url=image_link)
        os.remove("gov_histcont.png")

        await ctx.send(embed=embed)

    except Exception as e:
        embed = discord.Embed(
            title="ERROR Stocks: Historical Quarterly Government Contract",
            colour=cfg.COLOR,
            description=e,
        )
        embed.set_author(
            name=cfg.AUTHOR_NAME,
            icon_url=cfg.AUTHOR_ICON_URL,
        )

        await ctx.send(embed=embed)
Exemple #23
0
async def unu_command(ctx, num: int = None):
    """Unusual Options"""
    try:

        # Debug
        if cfg.DEBUG:
            logger.debug("!stocks.opt.unu %s", num)

        # Check for argument
        if num is None:
            num = 10

        pages = np.arange(0, num // 20 + 1)
        data_list = []
        for page_num in pages:

            r = requests.get(
                f"https://app.fdscanner.com/api2/unusualvolume?p=0&page_size=20&page={int(page_num)}",
                headers={"User-Agent": get_user_agent()},
            )

            if r.status_code != 200:
                logger.debug("Error in fdscanner request")
                return pd.DataFrame(), "request error"

            data_list.append(r.json())

        ticker, expiry, option_strike, option_type, ask, bid, oi, vol, voi = (
            [],
            [],
            [],
            [],
            [],
            [],
            [],
            [],
            [],
        )
        for data in data_list:
            for entry in data["data"]:
                ticker.append(entry["tk"])
                expiry.append(entry["expiry"])
                option_strike.append(float(entry["s"]))
                option_type.append("Put" if entry["t"] == "P" else "Call")
                ask.append(entry["a"])
                bid.append(entry["b"])
                oi.append(entry["oi"])
                vol.append(entry["v"])
                voi.append(entry["vol/oi"])

        df = pd.DataFrame(
            {
                "Ticker": ticker,
                "Exp": expiry,
                "Strike": option_strike,
                "Type": option_type,
                "Vol/OI": voi,
                "Vol": vol,
                "OI": oi,
            }
        )

        df = df.replace({"2021-", "2022-"}, "", regex=True)

        report = (
            "```"
            + tabulate(
                df,
                headers=["T", "Exp", "ST", "C/P", "V/O", "Vol", "OI"],
                tablefmt="fancy_grid",
                showindex=False,
                floatfmt=["", "", ".1f", "", ".1f", ".0f", ".0f", ".2f", ".2f"],
            )
            + "```"
        )
        embed = discord.Embed(
            title="Unusual Options",
            description=report,
            colour=cfg.COLOR,
        )
        embed.set_author(
            name=cfg.AUTHOR_NAME,
            icon_url=cfg.AUTHOR_ICON_URL,
        )

        await ctx.send(embed=embed)

    except Exception as e:
        embed = discord.Embed(
            title="ERROR Unusual Options",
            colour=cfg.COLOR,
            description=e,
        )
        embed.set_author(
            name=cfg.AUTHOR_NAME,
            icon_url=cfg.AUTHOR_ICON_URL,
        )

        await ctx.send(embed=embed)
Exemple #24
0
async def stoch_command(ctx,
                        ticker="",
                        fast_k="14",
                        slow_d="3",
                        slow_k="3",
                        start="",
                        end=""):
    """Displays chart with stochastic relative strength average [Yahoo Finance]"""

    try:

        # Debug
        if cfg.DEBUG:
            logger.debug(
                "!stocks.ta.stoch %s %s %s %s %s %s",
                ticker,
                fast_k,
                slow_k,
                slow_d,
                start,
                end,
            )

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

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

        if end == "":
            end = datetime.now()
        else:
            end = datetime.strptime(end, cfg.DATE_FORMAT)

        if not fast_k.lstrip("-").isnumeric():
            raise Exception("Number has to be an integer")
        fast_k = int(fast_k)
        if not slow_k.lstrip("-").isnumeric():
            raise Exception("Number has to be an integer")
        slow_k = int(slow_k)
        if not slow_d.lstrip("-").isnumeric():
            raise Exception("Number has to be an integer")
        slow_d = int(slow_d)

        ticker = ticker.upper()
        df_stock = discordbot.helpers.load(ticker, start)
        if df_stock.empty:
            raise Exception("Stock ticker is invalid")

        # Retrieve Data
        df_stock = df_stock.loc[(df_stock.index >= start)
                                & (df_stock.index < end)]

        df_ta = momentum_model.stoch(
            df_stock["High"],
            df_stock["Low"],
            df_stock["Adj Close"],
            fast_k,
            slow_d,
            slow_k,
        )

        # Output Data
        fig, axes = plt.subplots(2, 1, figsize=plot_autoscale(), dpi=PLOT_DPI)
        ax = axes[0]
        ax.plot(df_stock.index, df_stock["Adj Close"].values, "k", lw=2)
        ax.set_title(
            f"Stochastic Relative Strength Index (STOCH RSI) on {ticker}")
        ax.set_xlim(df_stock.index[0], df_stock.index[-1])
        ax.set_xticklabels([])
        ax.set_ylabel("Share Price ($)")
        ax.grid(b=True, which="major", color="#666666", linestyle="-")

        ax2 = axes[1]
        ax2.plot(df_ta.index, df_ta.iloc[:, 0].values, "k", lw=2)
        ax2.plot(df_ta.index, df_ta.iloc[:, 1].values, "b", lw=2, ls="--")
        ax2.set_xlim(df_stock.index[0], df_stock.index[-1])
        ax2.axhspan(80, 100, facecolor="r", alpha=0.2)
        ax2.axhspan(0, 20, facecolor="g", alpha=0.2)
        ax2.axhline(80, linewidth=3, color="r", ls="--")
        ax2.axhline(20, linewidth=3, color="g", ls="--")
        ax2.grid(b=True, which="major", color="#666666", linestyle="-")
        ax2.set_ylim([0, 100])

        ax3 = ax2.twinx()
        ax3.set_ylim(ax2.get_ylim())
        ax3.set_yticks([20, 80])
        ax3.set_yticklabels(["OVERSOLD", "OVERBOUGHT"])
        ax2.legend([f"%K {df_ta.columns[0]}", f"%D {df_ta.columns[1]}"],
                   loc="lower left")

        plt.gcf().autofmt_xdate()
        fig.tight_layout(pad=1)

        plt.savefig("ta_stoch.png")
        uploaded_image = gst_imgur.upload_image("ta_stoch.png",
                                                title="something")
        image_link = uploaded_image.link
        if cfg.DEBUG:
            logger.debug("Image URL: %s", image_link)
        title = "Stocks: Stochastic-Relative-Strength-Index " + ticker
        embed = discord.Embed(title=title, colour=cfg.COLOR)
        embed.set_author(
            name=cfg.AUTHOR_NAME,
            icon_url=cfg.AUTHOR_ICON_URL,
        )
        embed.set_image(url=image_link)
        os.remove("ta_stoch.png")

        await ctx.send(embed=embed)

    except Exception as e:
        embed = discord.Embed(
            title="ERROR Stocks: Stochastic-Relative-Strength-Index",
            colour=cfg.COLOR,
            description=e,
        )
        embed.set_author(
            name=cfg.AUTHOR_NAME,
            icon_url=cfg.AUTHOR_ICON_URL,
        )

        await ctx.send(embed=embed)
Exemple #25
0
async def lastcontracts_command(ctx, past_transactions_days="", num=""):
    """Displays last government contracts [quiverquant.com]"""
    try:
        # Debug user input
        if cfg.DEBUG:
            logger.debug("!stocks.gov.lastcontracts %s %s",
                         past_transactions_days, num)

        if past_transactions_days == "":
            past_transactions_days = 2
        else:
            if not past_transactions_days.lstrip("-").isnumeric():
                raise Exception("Number has to be an integer")
            past_transactions_days = float(past_transactions_days)

        if num == "":
            num = 20
        else:
            if not num.lstrip("-").isnumeric():
                raise Exception("Number has to be an integer")
            num = int(num)

        df_contracts = quiverquant_model.get_government_trading("contracts")

        if df_contracts.empty:
            logger.debug("No government contracts found")
            return

        df_contracts.sort_values("Date", ascending=False)

        df_contracts["Date"] = pd.to_datetime(df_contracts["Date"])
        df_contracts["Date"] = df_contracts["Date"].dt.date

        df_contracts.drop_duplicates(inplace=True)
        df_contracts = df_contracts[df_contracts["Date"].isin(
            df_contracts["Date"].unique()[:past_transactions_days])]

        df_contracts = df_contracts[["Date", "Ticker", "Amount",
                                     "Agency"]][:num]

        initial_str = "Page 0: Overview"
        i = 1
        for col_name in df_contracts["Ticker"].values:
            initial_str += f"\nPage {i}: {col_name}"
            i += 1

        columns = []
        df_contracts = df_contracts.T
        columns.append(
            discord.Embed(
                title="Stocks: [quiverquant.com] Top buy government trading",
                description=initial_str,
                colour=cfg.COLOR,
            ).set_author(
                name=cfg.AUTHOR_NAME,
                icon_url=cfg.AUTHOR_ICON_URL,
            ))
        for column in df_contracts.columns.values:
            columns.append(
                discord.Embed(
                    description="```" +
                    df_contracts[column].fillna("").to_string() + "```",
                    colour=cfg.COLOR,
                ).set_author(
                    name=cfg.AUTHOR_NAME,
                    icon_url=cfg.AUTHOR_ICON_URL,
                ))

        await pagination(columns, ctx)

    except Exception as e:
        embed = discord.Embed(
            title="ERROR Stocks: [quiverquant.com] Top buy government trading",
            colour=cfg.COLOR,
            description=e,
        )
        embed.set_author(
            name=cfg.AUTHOR_NAME,
            icon_url=cfg.AUTHOR_ICON_URL,
        )

        await ctx.send(embed=embed)
Exemple #26
0
async def spos_command(ctx, ticker=""):
    """Net short vs position [Stockgrid]"""

    try:
        # Debug user input
        if cfg.DEBUG:
            logger.debug("!stocks.dps.spos %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 = stockgrid_model.get_net_short_position(ticker)

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

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

        fig = plt.figure(dpi=PLOT_DPI)

        ax = fig.add_subplot(111)
        ax.bar(
            df["dates"],
            df["dollar_net_volume"] / 1_000,
            color="r",
            alpha=0.4,
            label="Net Short Vol. (1k $)",
        )
        ax.set_ylabel("Net Short Vol. (1k $)")

        ax2 = ax.twinx()
        ax2.plot(
            df["dates"].values,
            df["dollar_dp_position"],
            c="tab:blue",
            label="Position (1M $)",
        )
        ax2.set_ylabel("Position (1M $)")

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

        ax.grid()
        plt.title(f"Net Short Vol. vs Position for {ticker}")
        plt.gcf().autofmt_xdate()
        file_name = ticker + "_spos.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] Net Short vs Position {ticker}",
            colour=cfg.COLOR,
            description=e,
        )
        embed.set_author(
            name=cfg.AUTHOR_NAME,
            icon_url=cfg.AUTHOR_ICON_URL,
        )

        await ctx.send(embed=embed)
Exemple #27
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)
Exemple #28
0
async def topbuys_command(ctx,
                          gov_type="",
                          past_transactions_months="",
                          num="",
                          raw=""):
    """Displays most purchased stocks by the congress/senate/house [quiverquant.com]"""
    try:
        # Debug user input
        if cfg.DEBUG:
            logger.debug(
                "!stocks.gov.topbuys %s %s %s %s",
                gov_type,
                past_transactions_months,
                num,
                raw,
            )

        if past_transactions_months == "":
            past_transactions_months = 5
        else:
            if not past_transactions_months.lstrip("-").isnumeric():
                raise Exception("Number has to be an integer")
            past_transactions_months = int(past_transactions_months)

        if num == "":
            num = 10
        else:
            if not num.lstrip("-").isnumeric():
                raise Exception("Number has to be an integer")
            num = int(num)

        if raw in ["false", "False", "FALSE", ""]:
            raw = False

        if raw in ["true", "True", "TRUE"]:
            raw = True

        if raw not in [True, False]:
            raise Exception("raw argument has to be true or false")

        possible_args = ["congress", "senate", "house"]
        if gov_type == "":
            gov_type = "congress"
        elif gov_type not in possible_args:
            raise Exception(
                "Enter a valid government argument, options are: congress, senate and house"
            )

        # Retrieve Data
        df_gov = quiverquant_model.get_government_trading(gov_type)

        if df_gov.empty:
            logger.debug("No %s trading data found", gov_type)
            return

        df_gov = df_gov.sort_values("TransactionDate", ascending=False)
        start_date = datetime.now() - timedelta(days=past_transactions_months *
                                                30)

        df_gov["TransactionDate"] = pd.to_datetime(df_gov["TransactionDate"])

        df_gov = df_gov[df_gov["TransactionDate"] > start_date].dropna()
        # Catch bug where error shown for purchase of >5,000,000
        df_gov["Range"] = df_gov["Range"].apply(
            lambda x: "$5,000,001-$5,000,001" if x == ">$5,000,000" else x)
        df_gov["min"] = df_gov["Range"].apply(
            lambda x: x.split("-")[0].strip("$").replace(",", "").strip())
        df_gov["max"] = df_gov["Range"].apply(
            lambda x: x.split("-")[1].replace(",", "").strip().strip("$")
            if "-" in x else x.strip("$").replace(",", ""))
        df_gov["lower"] = df_gov[["min", "max", "Transaction"]].apply(
            lambda x: float(x["min"])
            if x["Transaction"] == "Purchase" else -float(x["max"]),
            axis=1,
        )
        df_gov["upper"] = df_gov[["min", "max", "Transaction"]].apply(
            lambda x: float(x["max"])
            if x["Transaction"] == "Purchase" else -float(x["min"]),
            axis=1,
        )

        df_gov = df_gov.sort_values("TransactionDate", ascending=True)
        if raw:
            df = pd.DataFrame(
                df_gov.groupby("Ticker")["upper"].sum().div(1000).sort_values(
                    ascending=False).head(n=num))
            description = "```" + df.to_string() + "```"

        fig, ax = plt.subplots(figsize=plot_autoscale(), dpi=PLOT_DPI)

        df_gov.groupby("Ticker")["upper"].sum().div(1000).sort_values(
            ascending=False).head(n=num).plot(kind="bar", rot=0, ax=ax)

        ax.set_ylabel("Amount [1k $]")
        ax.set_title(
            f"Top {num} purchased stocks over last {past_transactions_months} "
            f"months (upper bound) for {gov_type.upper()}")
        plt.gcf().axes[0].yaxis.get_major_formatter().set_scientific(False)
        fig.tight_layout()

        plt.savefig("gov_topbuys.png")
        uploaded_image = gst_imgur.upload_image("gov_topbuys.png",
                                                title="something")
        image_link = uploaded_image.link
        if cfg.DEBUG:
            logger.debug("Image URL: %s", image_link)
        title = f"Stocks: [quiverquant.com] Top purchases for {gov_type.upper()}"
        if raw:
            embed = discord.Embed(title=title,
                                  description=description,
                                  colour=cfg.COLOR)
        else:
            embed = discord.Embed(title=title, colour=cfg.COLOR)
        embed.set_author(
            name=cfg.AUTHOR_NAME,
            icon_url=cfg.AUTHOR_ICON_URL,
        )
        embed.set_image(url=image_link)
        os.remove("gov_topbuys.png")

        await ctx.send(embed=embed)

    except Exception as e:
        embed = discord.Embed(
            title=
            f"ERROR Stocks: [quiverquant.com] Top purchases for {gov_type.upper()}",
            colour=cfg.COLOR,
            description=e,
        )
        embed.set_author(
            name=cfg.AUTHOR_NAME,
            icon_url=cfg.AUTHOR_ICON_URL,
        )

        await ctx.send(embed=embed)
Exemple #29
0
async def pos_command(ctx, sort="dpp_dollar", num="10"):
    """Dark pool short position [Stockgrid]"""

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

        # Check for argument
        possible_sorts = ("sv", "sv_pct", "nsv", "nsv_dollar", "dpp", "dpp_dollar")

        if sort not in possible_sorts:
            raise Exception(f"The possible sorts are: {', '.join(possible_sorts)}")

        if not num.lstrip("-").isnumeric():
            raise Exception("Number has to be an integer")

        num = int(num)

        if num < 0:
            raise Exception("Number has to be above 0")

        # Retrieve data
        df = stockgrid_model.get_dark_pool_short_positions(sort, False)
        df = df.iloc[:num]

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

        # Output data
        dp_date = df["Date"].values[0]
        df = df.drop(columns=["Date"])
        df["Net Short Volume $"] = df["Net Short Volume $"] / 100_000_000
        df["Short Volume"] = df["Short Volume"] / 1_000_000
        df["Net Short Volume"] = df["Net Short Volume"] / 1_000_000
        df["Short Volume %"] = df["Short Volume %"] * 100
        df["Dark Pools Position $"] = df["Dark Pools Position $"] / (1_000_000_000)
        df["Dark Pools Position"] = df["Dark Pools Position"] / 1_000_000
        df.columns = [
            "Ticker",
            "Short Vol. (1M)",
            "Short Vol. %",
            "Net Short Vol. (1M)",
            "Net Short Vol. ($100M)",
            "DP Position (1M)",
            "DP Position ($1B)",
        ]
        future_column_name = df["Ticker"]
        df = df.transpose()
        df.columns = future_column_name
        df.drop("Ticker")
        columns = []
        initial_str = "Page 0: Overview"
        i = 1
        for column in df.columns.values:
            initial_str = initial_str + "\nPage " + str(i) + ": " + column
            i += 1
        columns.append(
            discord.Embed(
                title="Stocks: [Stockgrid] Dark Pool Short Position",
                description=initial_str,
                colour=cfg.COLOR,
            ).set_author(
                name=cfg.AUTHOR_NAME,
                icon_url=cfg.AUTHOR_ICON_URL,
            )
        )
        for column in df.columns.values:
            columns.append(
                discord.Embed(
                    title="High Short Interest",
                    description="```The following data corresponds to the date: "
                    + dp_date
                    + "\n\n"
                    + df[column].fillna("").to_string()
                    + "```",
                    colour=cfg.COLOR,
                ).set_author(
                    name=cfg.AUTHOR_NAME,
                    icon_url=cfg.AUTHOR_ICON_URL,
                )
            )

        await pagination(columns, ctx)

    except Exception as e:
        embed = discord.Embed(
            title="ERROR Stocks: [Stockgrid] Dark Pool Short Position",
            colour=cfg.COLOR,
            description=e,
        )
        embed.set_author(
            name=cfg.AUTHOR_NAME,
            icon_url=cfg.AUTHOR_ICON_URL,
        )

        await ctx.send(embed=embed)
Exemple #30
0
async def lasttrades_command(ctx,
                             gov_type="",
                             past_transactions_days="",
                             representative=""):
    """Displays trades made by the congress/senate/house [quiverquant.com]"""
    try:
        # Debug user input
        if cfg.DEBUG:
            logger.debug(
                "!stocks.gov.lasttrades %s %s %s",
                gov_type,
                past_transactions_days,
                representative,
            )

        if past_transactions_days == "":
            past_days = 5
        else:
            if not past_transactions_days.lstrip("-").isnumeric():
                raise Exception("Number has to be an integer")
            past_days = int(past_transactions_days)

        possible_args = ["congress", "senate", "house"]
        if gov_type == "":
            gov_type = "congress"
        elif gov_type not in possible_args:
            raise Exception(
                "Enter a valid government argument, options are: congress, senate and house"
            )

        # Retrieve Data
        df_gov = quiverquant_model.get_government_trading(gov_type)

        # Output Data
        if df_gov.empty:
            raise Exception(f"No {gov_type} trading data found")
        df_gov = df_gov.sort_values("TransactionDate", ascending=False)

        df_gov = df_gov[df_gov["TransactionDate"].isin(
            df_gov["TransactionDate"].unique()[:past_days])]

        if gov_type == "congress":
            df_gov = df_gov[[
                "TransactionDate",
                "Ticker",
                "Representative",
                "Transaction",
                "Range",
                "House",
                "ReportDate",
            ]].rename(
                columns={
                    "TransactionDate": "Transaction Date",
                    "ReportDate": "Report Date",
                })
        else:
            df_gov = df_gov[[
                "TransactionDate",
                "Ticker",
                "Representative",
                "Transaction",
                "Range",
            ]].rename(columns={"TransactionDate": "Transaction Date"})

        if representative:
            df_gov_rep = df_gov[df_gov["Representative"].str.split().str[0] ==
                                representative]

            if df_gov_rep.empty:
                raise Exception(
                    f"No representative {representative} found in the past {past_days}"
                    f" days. The following are available: "
                    f"{', '.join(df_gov['Representative'].str.split().str[0].unique())}"
                )

            initial_str = "Page 0: Overview"
            i = 1
            for col_name in df_gov_rep["Ticker"].values:
                initial_str += f"\nPage {i}: {col_name}"
                i += 1

            columns = []
            df_gov_rep = df_gov_rep.T
            columns.append(
                discord.Embed(
                    title=
                    f"Stocks: [quiverquant.com] Trades by {representative}",
                    description=initial_str,
                    colour=cfg.COLOR,
                ).set_author(
                    name=cfg.AUTHOR_NAME,
                    icon_url=cfg.AUTHOR_ICON_URL,
                ))
            for column in df_gov_rep.columns.values:
                columns.append(
                    discord.Embed(
                        description="```" +
                        df_gov_rep[column].fillna("").to_string() + "```",
                        colour=cfg.COLOR,
                    ).set_author(
                        name=cfg.AUTHOR_NAME,
                        icon_url=cfg.AUTHOR_ICON_URL,
                    ))

            await pagination(columns, ctx)

        else:
            initial_str = "Page 0: Overview"
            i = 1
            for col_name in df_gov["Ticker"].values:
                initial_str += f"\nPage {i}: {col_name}"
                i += 1

            columns = []
            df_gov = df_gov.T
            columns.append(
                discord.Embed(
                    title=
                    f"Stocks: [quiverquant.com] Trades for {gov_type.upper()}",
                    description=initial_str,
                    colour=cfg.COLOR,
                ).set_author(
                    name=cfg.AUTHOR_NAME,
                    icon_url=cfg.AUTHOR_ICON_URL,
                ))

            for column in df_gov.columns.values:
                columns.append(
                    discord.Embed(
                        description="```" +
                        df_gov[column].fillna("").to_string() + "```",
                        colour=cfg.COLOR,
                    ).set_author(
                        name=cfg.AUTHOR_NAME,
                        icon_url=cfg.AUTHOR_ICON_URL,
                    ))

            await pagination(columns, ctx)

    except Exception as e:
        embed = discord.Embed(
            title=
            f"ERROR Stocks: [quiverquant.com] Trades by {gov_type.upper()}",
            colour=cfg.COLOR,
            description=e,
        )
        embed.set_author(
            name=cfg.AUTHOR_NAME,
            icon_url=cfg.AUTHOR_ICON_URL,
        )

        await ctx.send(embed=embed)