예제 #1
0
async def qtrcontracts_command(ctx, num: int = 20, 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)

        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)
        plt.style.use("seaborn")

        # 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")
            imagefile = "gov_qtrcontracts.png"

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

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

            image = Image.open(imagefile)
            image = autocrop_image(image, 0)
            image.save(imagefile, "PNG", quality=100)

            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 = disnake.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]"]

            embed = disnake.Embed(
                title="Stocks: [quiverquant.com] Government contracts",
                description=tickers.to_string(),
                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 = disnake.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, delete_after=30.0)
예제 #2
0
async def softs_command(ctx):
    """Displays softs futures data [Finviz]"""

    try:
        # Debug user input
        if cfg.DEBUG:
            logger.debug("econ-softs")

        # Retrieve data
        d_futures = finviz_model.get_futures()
        df = pd.DataFrame(d_futures["Softs"])

        # Check for argument
        if df.empty:
            raise Exception("No available data found")

        formats = {"last": "${:.2f}", "prevClose": "${:.2f}"}
        for col, value in formats.items():
            df[col] = df[col].map(lambda x: value.format(x))  # pylint: disable=W0640

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

        df = df.sort_values(by="ticker", ascending=False)
        df = df.fillna("")
        df.set_index("label", inplace=True)

        df = df[[
            "prevClose",
            "last",
            "change",
        ]]

        df.index.names = [""]
        df = df.rename(columns={
            "prevClose": "PrevClose",
            "last": "Last",
            "change": "Change"
        })

        dindex = len(df.index)
        fig = df2img.plot_dataframe(
            df,
            fig_size=(800, (40 + (40 * dindex))),
            col_width=[6, 3, 3],
            tbl_cells=dict(
                align="left",
                height=35,
            ),
            template="plotly_dark",
            font=dict(
                family="Consolas",
                size=20,
            ),
            paper_bgcolor="rgba(0, 0, 0, 0)",
        )
        imagefile = "econ-softs.png"
        df2img.save_dataframe(fig=fig, filename=imagefile)

        image = Image.open(imagefile)
        image = autocrop_image(image, 0)
        image.save(imagefile, "PNG", quality=100)

        image = disnake.File(imagefile)

        title = "Economy: [Finviz] Softs Futures"
        embed = disnake.Embed(title=title, colour=cfg.COLOR)
        embed.set_image(url=f"attachment://{imagefile}")
        embed.set_author(
            name=cfg.AUTHOR_NAME,
            icon_url=cfg.AUTHOR_ICON_URL,
        )
        os.remove(imagefile)

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

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

        await ctx.send(embed=embed, delete_after=30.0)
예제 #3
0
async def hma_command(ctx, ticker="", window="", offset="", start="", end=""):
    """Displays chart with hull moving average [Yahoo Finance]"""

    try:
        # Debug
        if cfg.DEBUG:
            logger.debug(
                "!stocks.ta.hma %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

        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:
            hma_data = overlap_model.hma(values=stock["Adj Close"],
                                         length=win,
                                         offset=offset)
            price_df = price_df.join(hma_data)
            l_legend.append(f"HMA {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 = go.Figure()
        fig.add_trace(
            go.Scatter(
                name=f"{ticker}",
                x=price_df.index,
                y=price_df["Price"],
                line=dict(color="#fdc708", width=2),
                opacity=1,
            ), )
        for i in range(1, price_df.shape[1]):
            trace_name = price_df.columns[i].replace("_", " ")
            fig.add_trace(
                go.Scatter(
                    name=trace_name,
                    x=price_df.index,
                    y=price_df.iloc[:, i],
                    opacity=1,
                ), )
        fig.update_layout(
            margin=dict(l=0, r=0, t=50, b=20),
            template=cfg.PLT_TA_STYLE_TEMPLATE,
            colorway=cfg.PLT_TA_COLORWAY,
            title=f"{ticker} HMA",
            title_x=0.5,
            yaxis_title="Stock Price ($)",
            xaxis_title="Time",
            yaxis=dict(fixedrange=False, ),
            xaxis=dict(
                rangeslider=dict(visible=False),
                type="date",
            ),
            dragmode="pan",
            legend=dict(yanchor="top", y=0.99, xanchor="left", x=0.01),
        )
        config = dict({"scrollZoom": True})
        imagefile = "ta_hma.png"

        # Check if interactive settings are enabled
        plt_link = ""
        if cfg.INTERACTIVE:
            html_ran = random.randint(69, 69420)
            fig.write_html(f"in/hma_{html_ran}.html", config=config)
            plt_link = f"[Interactive]({cfg.INTERACTIVE_URL}/hma_{html_ran}.html)"

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

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

        # Paste fig onto background img and autocrop background
        img = img.resize((w, h), Image.ANTIALIAS)
        x1 = int(0.5 * im_bg.size[0]) - int(0.5 * img.size[0])
        y1 = int(0.5 * im_bg.size[1]) - int(0.5 * img.size[1])
        x2 = int(0.5 * im_bg.size[0]) + int(0.5 * img.size[0])
        y2 = int(0.5 * im_bg.size[1]) + int(0.5 * img.size[1])
        img = img.convert("RGB")
        im_bg.paste(img, box=(x1 - 5, y1, x2 - 5, y2))
        im_bg.save(imagefile, "PNG", quality=100)
        image = Image.open(imagefile)
        image = autocrop_image(image, 0)
        image.save(imagefile, "PNG", quality=100)

        image = disnake.File(imagefile)

        print(f"Image {imagefile}")
        if cfg.DEBUG:
            logger.debug("Image: %s", imagefile)
        title = "Stocks: Hull-Moving-Average  " + ticker
        embed = disnake.Embed(title=title,
                              description=plt_link,
                              colour=cfg.COLOR)
        embed.set_image(url=f"attachment://{imagefile}")
        embed.set_author(
            name=cfg.AUTHOR_NAME,
            icon_url=cfg.AUTHOR_ICON_URL,
        )
        os.remove(imagefile)

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

    except Exception as e:
        embed = disnake.Embed(
            title="ERROR Stocks: Hull-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, delete_after=30.0)
예제 #4
0
async def arktrades_command(ctx, ticker: str = "", num: int = 10):
    """Displays trades made by ark [cathiesark.com]"""

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

        if ticker:
            ark_holdings = ark_model.get_ark_trades_by_ticker(ticker)
            ark_holdings = ark_holdings.drop(
                columns=["ticker", "everything.profile.companyName"])

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

        ark_holdings["Total"] = ark_holdings["Total"] / 1_000_000
        ark_holdings.rename(columns={
            "direction": "B/S",
            "weight": "F %"
        },
                            inplace=True)

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

        df = ark_holdings.head(num)
        dindex = len(df.head(num).index)
        formats = {"Close": "{:.2f}", "Total": "{:.2f}"}
        for col, f in formats.items():
            df[col] = df[col].map(lambda x: f.format(x))  # pylint: disable=W0640

        title = f"Stocks: [cathiesark.com] {ticker.upper()} Trades by Ark"

        embeds: list = []

        i, i2, end = 0, 0, 20
        df_pg = []
        embeds_img = []
        dindex = len(df.index)
        while i < dindex:
            df_pg = df.iloc[i:end]
            df_pg.append(df_pg)
            fig = df2img.plot_dataframe(
                df_pg,
                fig_size=(900, (40 + (40 * 20))),
                col_width=[5, 10, 4, 4, 3, 4, 5],
                tbl_cells=dict(height=35, ),
                font=dict(
                    family="Consolas",
                    size=20,
                ),
                template="plotly_dark",
                paper_bgcolor="rgba(0, 0, 0, 0)",
            )
            imagefile = f"disc-insider{i}.png"

            df2img.save_dataframe(fig=fig, filename=imagefile)
            image = Image.open(imagefile)
            image = autocrop_image(image, 0)
            image.save(imagefile, "PNG", quality=100)
            uploaded_image = gst_imgur.upload_image(imagefile,
                                                    title="something")
            image_link = uploaded_image.link
            embeds_img.append(f"{image_link}", )
            embeds.append(disnake.Embed(
                title=title,
                colour=cfg.COLOR,
            ), )
            i2 += 1
            i += 20
            end += 20
            os.remove(imagefile)

        # Author/Footer
        for i in range(0, i2):
            embeds[i].set_author(
                name=cfg.AUTHOR_NAME,
                url=cfg.AUTHOR_URL,
                icon_url=cfg.AUTHOR_ICON_URL,
            )
            embeds[i].set_footer(
                text=cfg.AUTHOR_NAME,
                icon_url=cfg.AUTHOR_ICON_URL,
            )

        i = 0
        for i in range(0, i2):
            embeds[i].set_image(url=embeds_img[i])

            i += 1
        embeds[0].set_footer(text=f"Page 1 of {len(embeds)}")
        options = [
            disnake.SelectOption(label="Home", value="0", emoji="🟢"),
        ]

        await ctx.send(embed=embeds[0], view=Menu(embeds, options))

    except Exception as e:
        embed = disnake.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, delete_after=30.0)
예제 #5
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)
        df.set_index("Ticker", inplace=True)
        dindex = len(df.index)
        fig = df2img.plot_dataframe(
            df,
            fig_size=(800, (40 + (40 * dindex))),
            col_width=[3, 3, 3, 3, 3, 3, 3],
            tbl_cells=dict(
                align="left",
                height=35,
            ),
            template="plotly_dark",
            font=dict(
                family="Consolas",
                size=20,
            ),
            paper_bgcolor="rgba(0, 0, 0, 0)",
        )
        imagefile = "opt-unu.png"
        df2img.save_dataframe(fig=fig, filename=imagefile)
        image = Image.open(imagefile)
        image = autocrop_image(image, 0)
        image.save(imagefile, "PNG", quality=100)
        image = disnake.File(imagefile)
        title = "Unusual Options"
        embed = disnake.Embed(title=title, colour=cfg.COLOR)
        embed.set_image(url=f"attachment://{imagefile}")
        embed.set_author(
            name=cfg.AUTHOR_NAME,
            icon_url=cfg.AUTHOR_ICON_URL,
        )
        await ctx.send(embed=embed, file=image)

    except Exception as e:
        embed = disnake.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, delete_after=30.0)
예제 #6
0
async def analyst_command(ctx, ticker=""):
    """Displays analyst recommendations [Finviz]"""

    try:

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

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

        df = finviz_model.get_analyst_data(ticker)
        df = df.replace(np.nan, 0)
        df.index.names = ["Date"]
        df = df.rename(
            columns={
                "category": "Category",
                "analyst": "Analyst",
                "rating": "Rating",
                "target": "Target",
                "target_from": "Target From",
                "target_to": "Target To",
            })

        dindex = len(df.index)
        fig = df2img.plot_dataframe(
            df,
            fig_size=(1500, (40 + (40 * dindex))),
            col_width=[5, 5, 8, 14, 5, 5, 5],
            tbl_cells=dict(height=35, ),
            font=dict(
                family="Consolas",
                size=20,
            ),
            template="plotly_dark",
            paper_bgcolor="rgba(0, 0, 0, 0)",
        )
        imagefile = "dd-analyst.png"

        df2img.save_dataframe(fig=fig, filename=imagefile)
        image = Image.open(imagefile)
        image = autocrop_image(image, 0)
        image.save(imagefile, "PNG", quality=100)

        image = disnake.File(imagefile)

        title = f"Stocks: [Finviz] Analyst Recommendations {ticker.upper()}"
        embed = disnake.Embed(title=title, colour=cfg.COLOR)
        embed.set_image(url=f"attachment://{imagefile}")
        embed.set_author(
            name=cfg.AUTHOR_NAME,
            icon_url=cfg.AUTHOR_ICON_URL,
        )
        os.remove(imagefile)

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

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

        await ctx.send(embed=embed, delete_after=30.0)
예제 #7
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)

        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
        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 = make_subplots(
            rows=3,
            cols=1,
            shared_xaxes=True,
            vertical_spacing=0.06,
            row_width=[0.2, 0.2, 0.2],
        )
        fig.add_trace(
            go.Scatter(
                name=ticker,
                x=df_stock.index,
                y=df_stock["Adj Close"].values,
                line=dict(color="#fdc708", width=2),
                opacity=1,
            ),
            row=1,
            col=1,
        )
        colors = [
            "green" if row.Open < row["Adj Close"] else "red"
            for _, row in df_stock.iterrows()
        ]
        fig.add_trace(
            go.Bar(
                x=df_stock.index,
                y=df_vol,
                name="Volume",
                marker_color=colors,
            ),
            row=2,
            col=1,
        )
        fig.add_trace(
            go.Scatter(
                name="AD Osc [M]",
                x=df_ta.index,
                y=df_ta.iloc[:, 0].values,
                line=dict(width=2),
                opacity=1,
            ),
            row=3,
            col=1,
        )
        fig.update_layout(
            margin=dict(l=10, r=0, t=30, b=20),
            template=cfg.PLT_TA_STYLE_TEMPLATE,
            colorway=cfg.PLT_TA_COLORWAY,
            title=f"{ticker} AD Oscillator",
            title_x=0.3,
            yaxis_title="Stock Price ($)",
            yaxis=dict(fixedrange=False, ),
            xaxis=dict(
                rangeslider=dict(visible=False),
                type="date",
            ),
            dragmode="pan",
            legend=dict(orientation="h",
                        yanchor="bottom",
                        y=1.02,
                        xanchor="right",
                        x=1),
        )
        config = dict({"scrollZoom": True})
        imagefile = "ta_adosc.png"

        # Check if interactive settings are enabled
        plt_link = ""
        if cfg.INTERACTIVE:
            html_ran = random.randint(69, 69420)
            fig.write_html(f"in/adosc_{html_ran}.html", config=config)
            plt_link = f"[Interactive]({cfg.INTERACTIVE_URL}/adosc_{html_ran}.html)"

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

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

        # Paste fig onto background img and autocrop background
        img = img.resize((w, h), Image.ANTIALIAS)
        x1 = int(0.5 * im_bg.size[0]) - int(0.5 * img.size[0])
        y1 = int(0.5 * im_bg.size[1]) - int(0.5 * img.size[1])
        x2 = int(0.5 * im_bg.size[0]) + int(0.5 * img.size[0])
        y2 = int(0.5 * im_bg.size[1]) + int(0.5 * img.size[1])
        img = img.convert("RGB")
        im_bg.paste(img, box=(x1 - 5, y1, x2 - 5, y2))
        im_bg.save(imagefile, "PNG", quality=100)
        image = Image.open(imagefile)
        image = autocrop_image(image, 0)
        image.save(imagefile, "PNG", quality=100)

        image = disnake.File(imagefile)

        print(f"Image {imagefile}")
        if cfg.DEBUG:
            logger.debug("Image: %s", imagefile)
        title = "Stocks: Accumulation/Distribution Oscillator " + ticker
        embed = disnake.Embed(title=title,
                              description=plt_link,
                              colour=cfg.COLOR)
        embed.set_image(url=f"attachment://{imagefile}")
        embed.set_author(
            name=cfg.AUTHOR_NAME,
            icon_url=cfg.AUTHOR_ICON_URL,
        )
        os.remove(imagefile)

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

    except Exception as e:
        embed = disnake.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, delete_after=30.0)
예제 #8
0
async def hist_command(
    ctx,
    ticker: str = None,
    expiry: str = "",
    strike: float = 10,
    opt_type: str = "",
    greek: str = "",
):
    """Plot historical option prices

    Parameters
    ----------
    ticker: str
        Stock ticker
    expiry: str
        expiration date
    strike: float
        Option strike price
    put: bool
        Calls for call
        Puts for put
    """
    try:

        # Debug
        if cfg.DEBUG:
            print(f"opt-hist {ticker} {strike} {opt_type} {expiry} {greek}")

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

        if opt_type == "Puts":
            put = bool(True)
        if opt_type == "Calls":
            put = bool(False)
        chain_id = ""

        df_hist = syncretism_model.get_historical_greeks(
            ticker, expiry, chain_id, strike, put)
        title = f"\n{ticker.upper()} {strike} {opt_type} expiring {expiry} Historical {greek.upper()}"
        # Output data
        fig = make_subplots(shared_xaxes=True, specs=[[{"secondary_y": True}]])

        fig.add_trace(
            go.Scatter(
                name=ticker.upper(),
                x=df_hist.index,
                y=df_hist.price,
                line=dict(color="#fdc708", width=2),
                opacity=1,
            ), )
        fig.add_trace(
            go.Scatter(
                name="Premium",
                x=df_hist.index,
                y=df_hist["premium"],
                opacity=1,
                yaxis="y2",
            ), )
        if greek:
            fig.add_trace(
                go.Scatter(
                    name=f"{greek.upper()}",
                    x=df_hist.index,
                    y=df_hist[greek],
                    opacity=1,
                    yaxis="y3",
                ), )
        fig.update_layout(
            margin=dict(l=10, r=10, t=30, b=20),
            template=cfg.PLT_TA_STYLE_TEMPLATE,
            colorway=cfg.PLT_TA_COLORWAY,
            title=title,
            title_x=0.03,
            yaxis_title="<b>Stock Price</b> ($)",
            yaxis=dict(
                side="right",
                fixedrange=False,
                titlefont=dict(color="#fdc708"),
                tickfont=dict(color="#fdc708"),
                position=0.02,
                nticks=20,
            ),
            xaxis=dict(
                rangeslider=dict(visible=False),
                type="date",
                fixedrange=False,
                domain=[0.037, 1],
            ),
            xaxis2=dict(
                rangeslider=dict(visible=False),
                type="date",
                fixedrange=False,
            ),
            xaxis3=dict(
                rangeslider=dict(visible=False),
                type="date",
                fixedrange=False,
            ),
            dragmode="pan",
            legend=dict(orientation="h",
                        yanchor="bottom",
                        y=1.02,
                        xanchor="right",
                        x=1),
            yaxis2=dict(
                side="left",
                fixedrange=False,
                anchor="x",
                overlaying="y",
                titlefont=dict(color="#d81aea"),
                tickfont=dict(color="#d81aea"),
                nticks=20,
            ),
            yaxis3=dict(
                side="left",
                position=0,
                fixedrange=False,
                overlaying="y",
                titlefont=dict(color="#00e6c3"),
                tickfont=dict(color="#00e6c3"),
                nticks=20,
            ),
            hovermode="x unified",
        )
        config = dict({"scrollZoom": True})
        rand = random.randint(69, 69420)
        imagefile = f"opt_hist{rand}.png"

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

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

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

        # Paste fig onto background img and autocrop background
        img = img.resize((w, h), Image.ANTIALIAS)
        x1 = int(0.5 * im_bg.size[0]) - int(0.5 * img.size[0])
        y1 = int(0.5 * im_bg.size[1]) - int(0.5 * img.size[1])
        x2 = int(0.5 * im_bg.size[0]) + int(0.5 * img.size[0])
        y2 = int(0.5 * im_bg.size[1]) + int(0.5 * img.size[1])
        img = img.convert("RGB")
        im_bg.paste(img, box=(x1 - 5, y1, x2 - 5, y2))
        im_bg.save(imagefile, "PNG", quality=100)
        image = Image.open(imagefile)
        image = autocrop_image(image, 0)
        image.save(imagefile, "PNG", quality=100)

        image = disnake.File(imagefile)
        if cfg.DEBUG:
            print(f"Image: {imagefile}")
        title = f"{ticker.upper()} {strike} {opt_type} expiring {expiry} Historical"
        embed = disnake.Embed(title=title,
                              description=plt_link,
                              colour=cfg.COLOR)
        embed.set_image(url=f"attachment://{imagefile}")
        embed.set_author(
            name=cfg.AUTHOR_NAME,
            icon_url=cfg.AUTHOR_ICON_URL,
        )
        os.remove(imagefile)

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

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

        await ctx.send(embed=embed, delete_after=30.0)
예제 #9
0
async def iv_command(ctx, ticker: str = None):
    """Options IV"""

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

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

        df = barchart_model.get_options_info(ticker)
        df = df.fillna("")
        df = df.set_axis(
            [
                " ",
                "",
            ],
            axis="columns",
        )
        df.set_index(" ", inplace=True)
        fig = df2img.plot_dataframe(
            df,
            fig_size=(600, 1500),
            col_width=[3, 3],
            tbl_cells=dict(
                align="left",
                height=35,
            ),
            template="plotly_dark",
            font=dict(
                family="Consolas",
                size=20,
            ),
            paper_bgcolor="rgba(0, 0, 0, 0)",
        )
        imagefile = "opt-iv.png"
        df2img.save_dataframe(fig=fig, filename=imagefile)
        image = Image.open(imagefile)
        image = autocrop_image(image, 0)
        image.save(imagefile, "PNG", quality=100)
        image = disnake.File(imagefile)
        title = f"{ticker.upper()} Options: IV"
        embed = disnake.Embed(title=title, colour=cfg.COLOR)
        embed.set_image(url=f"attachment://{imagefile}")
        embed.set_author(
            name=cfg.AUTHOR_NAME,
            icon_url=cfg.AUTHOR_ICON_URL,
        )
        await ctx.send(embed=embed, file=image)

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

        await ctx.send(embed=embed, delete_after=30.0)
예제 #10
0
async def candle_command(
    ctx,
    ticker: str = "",
    interval: int = 15,
    past_days: int = 1,
    start="",
    end="",
):
    """Shows candle plot of loaded ticker. [Source: Yahoo Finance, IEX Cloud or Alpha Vantage]

    Parameters
    ----------
    ticker: str
        Ticker name
    interval: int
        chart mins or daily
    past_days: int
        Display the past * days. Default: 1(Not for Daily)
    start: str
        start date format YYYY-MM-DD
    end: str
        end date format YYYY-MM-DD
    """
    try:

        logger.info("candle %s %s %s %s", ticker, interval, start, end)

        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)

        futures = "=F"
        if interval == 1440:
            df_stock_candidate = yf.download(
                ticker,
                start=start,
                end=end,
                progress=False,
            )

            # Check that loading a stock was not successful
            if df_stock_candidate.empty:
                raise Exception(f"No data found for {ticker.upper()}")

            df_stock_candidate.index.name = "date"
        else:
            s_int = str(interval) + "m"
            d_granularity = {
                "1m": past_days,
                "5m": past_days,
                "15m": past_days,
                "30m": past_days,
                "60m": past_days,
            }
            s_start_dt = datetime.utcnow() - timedelta(
                days=d_granularity[s_int])
            s_date_start = s_start_dt.strftime("%Y-%m-%d")

            df_stock_candidate = yf.download(
                ticker,
                start=s_date_start
                if s_start_dt > start else start.strftime("%Y-%m-%d"),
                progress=False,
                interval=s_int,
                prepost=True,
            )

        # Check that loading a stock was not successful
        if df_stock_candidate.empty:
            raise Exception(f"No data found for {ticker.upper()}.")

        df_stock_candidate.index = df_stock_candidate.index.tz_localize(None)
        df_stock_candidate.index.name = "date"
        df_stock = df_stock_candidate
        price_df = df_stock.loc[(df_stock.index >= start)
                                & (df_stock.index < end)]

        df_vwap = overlap_model.vwap(price_df, 0)

        plt_title = [f"{ticker.upper()} Intraday {interval}min", "Volume"]
        title = f"Intraday {interval}min Chart for {ticker.upper()}"
        if interval == 1440:
            plt_title = [f"{ticker.upper()} Daily", "Volume"]
            title = f"Daily Chart for {ticker.upper()}"

        fig = make_subplots(
            rows=2,
            cols=1,
            shared_xaxes=True,
            vertical_spacing=0.06,
            subplot_titles=plt_title,
            row_width=[0.2, 0.7],
        )
        fig.add_trace(
            go.Candlestick(
                x=df_stock.index,
                open=df_stock.Open,
                high=df_stock.High,
                low=df_stock.Low,
                close=df_stock.Close,
                name="OHLC",
                showlegend=False,
            ),
            row=1,
            col=1,
        )
        colors = [
            "green" if row.Open < row["Adj Close"] else "red"
            for _, row in df_stock.iterrows()
        ]
        fig.add_trace(
            go.Bar(
                x=df_stock.index,
                y=df_stock.Volume,
                name="Volume",
                marker_color=colors,
                showlegend=False,
            ),
            row=2,
            col=1,
        )
        fig.update_layout(
            margin=dict(l=0, r=0, t=25, b=20),
            template=cfg.PLT_CANDLE_STYLE_TEMPLATE,
            yaxis_title="Stock Price ($)",
            yaxis=dict(
                fixedrange=False,
                showspikes=True,
            ),
            xaxis=dict(
                rangeslider=dict(visible=False),
                type="date",
                showspikes=True,
            ),
            legend=dict(orientation="h",
                        yanchor="bottom",
                        y=1.02,
                        xanchor="right",
                        x=1),
            dragmode="pan",
            hovermode="x unified",
        )
        if interval != 1440:
            fig.add_trace(
                go.Scatter(
                    name="VWAP",
                    x=df_stock.index,
                    y=df_vwap["VWAP_D"],
                    opacity=1,
                    line=dict(color="#d81aea", width=2),
                    showlegend=True,
                ), )
            if futures in ticker.upper():
                fig.update_xaxes(rangebreaks=[
                    dict(bounds=["fri", "sun"]),
                    dict(bounds=[17, 17.5], pattern="hour"),
                ], )
            else:
                fig.update_xaxes(rangebreaks=[
                    dict(bounds=["sat", "mon"]),
                    dict(bounds=[19, 9.5], pattern="hour"),
                ], )
        config = dict({"scrollZoom": True})
        rand = random.randint(69, 69420)
        imagefile = f"candle{rand}.png"

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

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

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

        # Paste fig onto background img and autocrop background
        img = img.resize((w, h), Image.ANTIALIAS)
        x1 = int(0.5 * im_bg.size[0]) - int(0.5 * img.size[0])
        y1 = int(0.5 * im_bg.size[1]) - int(0.5 * img.size[1])
        x2 = int(0.5 * im_bg.size[0]) + int(0.5 * img.size[0])
        y2 = int(0.5 * im_bg.size[1]) + int(0.5 * img.size[1])
        img = img.convert("RGB")
        im_bg.paste(img, box=(x1 - 5, y1, x2 - 5, y2))
        im_bg.save(imagefile, "PNG", quality=100)
        image = Image.open(imagefile)
        image = autocrop_image(image, 0)
        image.save(imagefile, "PNG", quality=100)

        image = disnake.File(imagefile)

        print(f"Image {imagefile}")
        embed = disnake.Embed(title=title,
                              description=plt_link,
                              colour=cfg.COLOR)
        embed.set_image(url=f"attachment://{imagefile}")
        embed.set_author(
            name=cfg.AUTHOR_NAME,
            icon_url=cfg.AUTHOR_ICON_URL,
        )
        os.remove(imagefile)

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

    except Exception as e:
        embed = disnake.Embed(
            title="ERROR Stocks: Intraday",
            colour=cfg.COLOR,
            description=e,
        )

        await ctx.send(embed=embed, delete_after=30.0)
예제 #11
0
async def cc_hist_command(
    ctx, ticker: str = None, expiry: str = "", strike: float = 10, opt_type: str = ""
):
    """Plot historical option prices

    Parameters
    ----------
    ticker: str
        Stock ticker
    expiry: str
        expiration date
    strike: float
        Option strike price
    put: bool
        Calls for call
        Puts for put
    """
    try:

        # Debug
        if cfg.DEBUG:
            print(f"opt-hist {ticker} {strike} {opt_type} {expiry}")

        # Check for argument
        if ticker is None:
            raise Exception("Stock ticker is required")
        yf_ticker = yf.Ticker(ticker)
        dates = list(yf_ticker.options)

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

        options = yf.Ticker(ticker).option_chain(expiry)

        if opt_type == "Calls":
            options = options.calls
        if opt_type == "Puts":
            options = options.puts

        chain_id = options.loc[options.strike == strike, "contractSymbol"].values[0]
        df_hist = yf.download(chain_id)
        df_hist.index.name = "date"

        plt_title = [
            f"\n{ticker.upper()} {strike} {opt_type} expiring {expiry} Historical",
            "Volume",
        ]
        title = f"\n{ticker.upper()} {strike} {opt_type} expiring {expiry} Historical"

        fig = make_subplots(
            rows=2,
            cols=1,
            shared_xaxes=True,
            vertical_spacing=0.06,
            subplot_titles=plt_title,
            row_width=[0.2, 0.7],
        )
        fig.add_trace(
            go.Candlestick(
                x=df_hist.index,
                open=df_hist.Open,
                high=df_hist.High,
                low=df_hist.Low,
                close=df_hist.Close,
                name="OHLC",
            ),
            row=1,
            col=1,
        )
        colors = [
            "green" if row.Open < row["Close"] else "red"
            for _, row in df_hist.iterrows()  # pylint: disable=E1120
        ]
        fig.add_trace(
            go.Bar(
                x=df_hist.index,
                y=df_hist.Volume,
                name="Volume",
                marker_color=colors,
            ),
            row=2,
            col=1,
        )
        fig.update_layout(
            margin=dict(l=0, r=0, t=25, b=5),
            template=cfg.PLT_CANDLE_STYLE_TEMPLATE,
            showlegend=False,
            yaxis_title="Premium",
            xaxis=dict(
                rangeslider=dict(visible=False),
                type="date",
            ),
            dragmode="pan",
        )
        fig.update_xaxes(
            rangebreaks=[
                dict(bounds=["sat", "mon"]),
            ],
        )
        config = dict({"scrollZoom": True})
        rand = random.randint(69, 69420)
        imagefile = f"opt_hist{rand}.png"
        fig.write_image(imagefile)

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

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

        # Paste fig onto background img and autocrop background
        img = img.resize((w, h), Image.ANTIALIAS)
        x1 = int(0.5 * im_bg.size[0]) - int(0.5 * img.size[0])
        y1 = int(0.5 * im_bg.size[1]) - int(0.5 * img.size[1])
        x2 = int(0.5 * im_bg.size[0]) + int(0.5 * img.size[0])
        y2 = int(0.5 * im_bg.size[1]) + int(0.5 * img.size[1])
        img = img.convert("RGB")
        im_bg.paste(img, box=(x1 - 5, y1, x2 - 5, y2))
        im_bg.save(imagefile, "PNG", quality=100)
        image = Image.open(imagefile)
        image = autocrop_image(image, 0)
        image.save(imagefile, "PNG", quality=100)

        image = disnake.File(imagefile)
        if cfg.DEBUG:
            print(f"Image: {imagefile}")
        title = f"{ticker.upper()} {strike} {opt_type} expiring {expiry} Historical"
        embed = disnake.Embed(title=title, description=plt_link, colour=cfg.COLOR)
        embed.set_image(url=f"attachment://{imagefile}")
        embed.set_author(
            name=cfg.AUTHOR_NAME,
            icon_url=cfg.AUTHOR_ICON_URL,
        )
        os.remove(imagefile)

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

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

        await ctx.send(embed=embed, delete_after=30.0)
예제 #12
0
async def ftd_command(ctx, ticker: str = "", 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()

        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())

        stock = discordbot.helpers.load(ticker, start)
        stock_ftd = stock[stock.index > start]
        stock_ftd = stock_ftd[stock_ftd.index < end]

        # Output data
        fig = make_subplots(shared_xaxes=True, specs=[[{"secondary_y": True}]])

        fig.add_trace(
            go.Scatter(
                name=ticker,
                x=stock_ftd.index,
                y=stock_ftd["Adj Close"],
                line=dict(color="#fdc708", width=2),
                opacity=1,
                showlegend=False,
            ),
            secondary_y=False,
        )
        fig.add_trace(
            go.Bar(
                name="FTDs",
                x=ftds_data["SETTLEMENT DATE"],
                y=ftds_data["QUANTITY (FAILS)"] / 1000,
                opacity=1,
            ),
            secondary_y=True,
        )
        # Set y-axes titles
        fig.update_yaxes(title_text="<b>Shares</b> [K]", secondary_y=True)
        fig.update_layout(
            margin=dict(l=0, r=20, t=30, b=20),
            template=cfg.PLT_TA_STYLE_TEMPLATE,
            colorway=cfg.PLT_TA_COLORWAY,
            title=f"{ticker}",
            title_x=0.5,
            yaxis_title="<b>Stock Price</b> ($)",
            yaxis=dict(
                side="right",
                fixedrange=False,
            ),
            xaxis=dict(
                rangeslider=dict(visible=False),
                type="date",
                fixedrange=False,
            ),
            xaxis2=dict(
                rangeslider=dict(visible=False),
                type="date",
                fixedrange=False,
            ),
            dragmode="pan",
            legend=dict(orientation="h",
                        yanchor="bottom",
                        y=1.02,
                        xanchor="right",
                        x=1),
            yaxis2=dict(
                side="left",
                position=0.15,
                fixedrange=False,
            ),
            hovermode="x unified",
        )
        config = dict({"scrollZoom": True})
        imagefile = "dps_ftd.png"

        # Check if interactive settings are enabled
        plt_link = ""
        if cfg.INTERACTIVE:
            html_ran = random.randint(69, 69420)
            fig.write_html(f"in/ftds_{html_ran}.html", config=config)
            plt_link = f"[Interactive]({cfg.INTERACTIVE_URL}/ftds_{html_ran}.html)"

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

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

        # Paste fig onto background img and autocrop background
        img = img.resize((w, h), Image.ANTIALIAS)
        x1 = int(0.5 * im_bg.size[0]) - int(0.5 * img.size[0])
        y1 = int(0.5 * im_bg.size[1]) - int(0.5 * img.size[1])
        x2 = int(0.5 * im_bg.size[0]) + int(0.5 * img.size[0])
        y2 = int(0.5 * im_bg.size[1]) + int(0.5 * img.size[1])
        img = img.convert("RGB")
        im_bg.paste(img, box=(x1 - 5, y1, x2 - 5, y2))
        im_bg.save(imagefile, "PNG", quality=100)
        image = Image.open(imagefile)
        image = autocrop_image(image, 0)
        image.save(imagefile, "PNG", quality=100)

        image = disnake.File(imagefile)

        print(f"Image {imagefile}")
        if cfg.DEBUG:
            logger.debug("Image: %s", imagefile)
        title = "Stocks: [SEC] Failure-to-deliver " + ticker
        embed = disnake.Embed(title=title,
                              description=plt_link,
                              colour=cfg.COLOR)
        embed.set_image(url=f"attachment://{imagefile}")
        embed.set_author(
            name=cfg.AUTHOR_NAME,
            icon_url=cfg.AUTHOR_ICON_URL,
        )
        os.remove(imagefile)

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

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

        await ctx.send(embed=embed, delete_after=30.0)
예제 #13
0
async def psi_command(ctx, ticker: str = ""):
    """Price vs short interest volume [Stockgrid]"""

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

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

        ticker = ticker.upper()

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        await ctx.send(embed=embed)

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

        await ctx.send(embed=embed, delete_after=30.0)
예제 #14
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)
        trace_name = df_ta.columns[0].replace("_", " ")

        fig = make_subplots(
            rows=2,
            cols=1,
            shared_xaxes=True,
            vertical_spacing=0.07,
            row_width=[0.5, 0.6],
        )
        fig.add_trace(
            go.Scatter(
                name=ticker,
                x=df_stock.index,
                y=df_stock["Adj Close"].values,
                line=dict(color="#fdc708", width=2),
                opacity=1,
                showlegend=False,
            ),
            row=1,
            col=1,
        )
        fig.add_trace(
            go.Bar(
                name="MACD Histogram",
                x=df_ta.index,
                y=df_ta.iloc[:, 1].values,
                opacity=1,
            ),
            row=2,
            col=1,
        )
        fig.add_trace(
            go.Scatter(
                mode="lines",
                name="MACD Line",
                x=df_ta.index,
                y=df_ta.iloc[:, 0].values,
                opacity=1,
            ),
            row=2,
            col=1,
        )
        fig.add_trace(
            go.Scatter(
                mode="lines",
                name="Signal Line",
                x=df_ta.index,
                y=df_ta.iloc[:, 2].values,
                opacity=1,
            ),
            row=2,
            col=1,
        )
        fig.update_layout(
            margin=dict(l=0, r=20, t=30, b=20),
            template=cfg.PLT_TA_STYLE_TEMPLATE,
            colorway=cfg.PLT_TA_COLORWAY,
            title=f"{ticker} {trace_name}",
            title_x=0.3,
            yaxis_title="Stock Price ($)",
            yaxis=dict(fixedrange=False, ),
            xaxis=dict(
                rangeslider=dict(visible=False),
                type="date",
            ),
            dragmode="pan",
            legend=dict(orientation="h",
                        yanchor="bottom",
                        y=1.02,
                        xanchor="right",
                        x=1),
        )
        config = dict({"scrollZoom": True})
        imagefile = "ta_macd.png"

        # Check if interactive settings are enabled
        plt_link = ""
        if cfg.INTERACTIVE:
            html_ran = random.randint(69, 69420)
            fig.write_html(f"in/macd_{html_ran}.html", config=config)
            plt_link = f"[Interactive]({cfg.INTERACTIVE_URL}/macd_{html_ran}.html)"

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

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

        # Paste fig onto background img and autocrop background
        img = img.resize((w, h), Image.ANTIALIAS)
        x1 = int(0.5 * im_bg.size[0]) - int(0.5 * img.size[0])
        y1 = int(0.5 * im_bg.size[1]) - int(0.5 * img.size[1])
        x2 = int(0.5 * im_bg.size[0]) + int(0.5 * img.size[0])
        y2 = int(0.5 * im_bg.size[1]) + int(0.5 * img.size[1])
        img = img.convert("RGB")
        im_bg.paste(img, box=(x1 - 5, y1, x2 - 5, y2))
        im_bg.save(imagefile, "PNG", quality=100)
        image = Image.open(imagefile)
        image = autocrop_image(image, 0)
        image.save(imagefile, "PNG", quality=100)

        image = disnake.File(imagefile)

        print(f"Image {imagefile}")
        if cfg.DEBUG:
            logger.debug("Image: %s", imagefile)
        title = "Stocks: Moving-Average-Convergence-Divergence " + ticker
        embed = disnake.Embed(title=title,
                              description=plt_link,
                              colour=cfg.COLOR)
        embed.set_image(url=f"attachment://{imagefile}")
        embed.set_author(
            name=cfg.AUTHOR_NAME,
            icon_url=cfg.AUTHOR_ICON_URL,
        )
        os.remove(imagefile)

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

    except Exception as e:
        embed = disnake.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, delete_after=30.0)
예제 #15
0
async def ford_command(ctx):
    """Display Orders by Fidelity Customers. [Source: Fidelity]

    Parameters
    ----------
    num: Number of stocks to display
    """

    try:
        # Debug
        if cfg.DEBUG:
            logger.debug("!ford")
        order_header, df_orders = fidelity_model.get_orders()

        df_orders = df_orders.head(n=30).iloc[:, :-1]
        df_orders = df_orders.applymap(str)

        font_color = (["white"] * 2 + [[
            "#ad0000" if boolv else "#0d5700"
            for boolv in df_orders["Price Change"].str.contains("-")
        ]] + [["white"] * 3])

        df_orders.set_index("Symbol", inplace=True)
        df_orders = df_orders.apply(lambda x: x.str.slice(0, 20))

        dindex = len(df_orders.index)
        fig = df2img.plot_dataframe(
            df_orders,
            fig_size=(1500, (40 + (40 * dindex))),
            col_width=[1, 3, 2.2, 3, 2, 2],
            tbl_cells=dict(
                align=["left", "center", "left", "left", "center"],
                font=dict(color=font_color),
                height=35,
            ),
            template="plotly_dark",
            font=dict(
                family="Consolas",
                size=20,
            ),
            paper_bgcolor="rgba(0, 0, 0, 0)",
        )
        imagefile = "disc-ford.png"
        df2img.save_dataframe(fig=fig, filename=imagefile)

        image = Image.open(imagefile)
        image = autocrop_image(image, 0)
        image.save(imagefile, "PNG", quality=100)

        image = disnake.File(imagefile)

        title = "Fidelity Customer Orders"
        embed = disnake.Embed(title=title, colour=cfg.COLOR)
        embed.set_image(url=f"attachment://{imagefile}")
        embed.set_author(
            name=cfg.AUTHOR_NAME,
            icon_url=cfg.AUTHOR_ICON_URL,
        )
        os.remove(imagefile)

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

    except Exception as e:
        embed = disnake.Embed(
            title="ERROR Fidelity Customer Orders",
            colour=cfg.COLOR,
            description=e,
        )
        embed.set_author(
            name=cfg.AUTHOR_NAME,
            icon_url=cfg.AUTHOR_ICON_URL,
        )

        await ctx.send(embed=embed, delete_after=30.0)
예제 #16
0
async def overview_command(
    ctx,
    ticker: str = None,
    expiry: str = None,
    min_sp: float = None,
    max_sp: float = None,
):
    """Options Overview"""

    try:

        # Debug
        startTime2 = time.time()
        if cfg.DEBUG:
            print(f"!stocks.opt.iv {ticker} {expiry} {min_sp} {max_sp}")

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

        # Get options info/dates, Look for logo_url
        df = get_options_info(ticker)  # Barchart Options IV Overview

        dates = yfinance_model.option_expirations(ticker)  # Expiration dates
        tup = f"{ticker.upper()}"
        url = yf.Ticker(tup).info["logo_url"]
        url += "?raw=true" if url else ""

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

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

        min_strike2 = np.percentile(calls["strike"], 1)
        max_strike2 = np.percentile(calls["strike"], 100)
        min_strike = 0.75 * current_price
        max_strike = 1.95 * current_price

        if len(calls) > 40:
            min_strike = 0.75 * current_price
            max_strike = 1.25 * current_price

        if min_sp:
            min_strike = min_sp
            min_strike2 = min_sp
        if max_sp:
            max_strike = max_sp
            max_strike2 = max_sp
            if min_sp > max_sp:  # type: ignore
                min_sp, max_sp = max_strike2, min_strike2

        call_oi = calls.set_index("strike")["openInterest"] / 1000
        put_oi = puts.set_index("strike")["openInterest"] / 1000

        df_opt = pd.merge(call_oi, put_oi, left_index=True, right_index=True)
        df_opt = df_opt.rename(columns={
            "openInterest_x": "OI_call",
            "openInterest_y": "OI_put"
        })

        max_pain = op_helpers.calculate_max_pain(df_opt)
        fig = go.Figure()

        dmax = df_opt[["OI_call", "OI_put"]].values.max()
        dmin = df_opt[["OI_call", "OI_put"]].values.min()
        fig.add_trace(
            go.Scatter(
                x=df_opt.index,
                y=df_opt["OI_call"],
                name="Calls",
                mode="lines+markers",
                line=dict(color="green", width=3),
            ))

        fig.add_trace(
            go.Scatter(
                x=df_opt.index,
                y=df_opt["OI_put"],
                name="Puts",
                mode="lines+markers",
                line=dict(color="red", width=3),
            ))
        fig.add_trace(
            go.Scatter(
                x=[current_price, current_price],
                y=[dmin, dmax],
                mode="lines",
                line=dict(color="gold", width=2),
                name="Current Price",
            ))
        fig.add_trace(
            go.Scatter(
                x=[max_pain, max_pain],
                y=[dmin, dmax],
                mode="lines",
                line=dict(color="grey", width=3, dash="dash"),
                name=f"Max Pain: {max_pain}",
            ))
        fig.update_xaxes(
            range=[min_strike, max_strike],
            constrain="domain",
        )
        fig.update_layout(
            margin=dict(l=0, r=0, t=60, b=20),
            template=cfg.PLT_SCAT_STYLE_TEMPLATE,
            title=f"Open Interest for {ticker.upper()} expiring {expiry}",
            title_x=0.5,
            legend_title="",
            xaxis_title="Strike",
            yaxis_title="Open Interest (1k)",
            xaxis=dict(rangeslider=dict(visible=False), ),
            legend=dict(yanchor="top", y=0.99, xanchor="left", x=0.01),
            dragmode="pan",
        )
        config = dict({"scrollZoom": True})
        imagefile = "opt_oi.png"
        fig.write_image(imagefile)

        plt_link = ""
        if cfg.INTERACTIVE:
            html_ran = random.randint(69, 69420)
            fig.write_html(f"in/oi_{html_ran}.html", config=config)
            plt_link = f"[Interactive]({cfg.INTERACTIVE_URL}/oi_{html_ran}.html)"

        img = Image.open(imagefile)
        im_bg = Image.open(cfg.IMG_BG)

        h = img.height + 240
        w = img.width + 520

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

        uploaded_image_oi = gst_imgur.upload_image(imagefile,
                                                   title="something")
        image_link_oi = uploaded_image_oi.link

        column_map = {
            "openInterest": "oi",
            "volume": "vol",
            "impliedVolatility": "iv"
        }
        columns = [
            "strike",
            "bid",
            "ask",
            "volume",
            "openInterest",
            "impliedVolatility",
        ]

        calls_df = calls[columns].rename(columns=column_map)
        puts_df = puts[columns].rename(columns=column_map)

        calls_df = calls_df[calls_df["strike"] >= min_strike2]
        calls_df = calls_df[calls_df["strike"] <= max_strike2]
        puts_df = puts_df[puts_df["strike"] >= min_strike2]
        puts_df = puts_df[puts_df["strike"] <= max_strike2]

        calls_df["iv"] = pd.to_numeric(calls_df["iv"].astype(float))
        puts_df["iv"] = pd.to_numeric(puts_df["iv"].astype(float))

        formats = {"iv": "{:.2f}"}
        for col, f in formats.items():
            calls_df[col] = calls_df[col].map(lambda x: f.format(x)  # pylint: disable=W0640
                                              )
            puts_df[col] = puts_df[col].map(lambda x: f.format(x)  # pylint: disable=W0640
                                            )

        calls_df.set_index("strike", inplace=True)
        puts_df.set_index("strike", inplace=True)

        if "-" in df.iloc[0, 1]:
            iv = f"```diff\n-             {df.iloc[0, 1]}\n```"
        else:
            iv = f"```yaml\n              {df.iloc[0, 1]}\n```"

        pfix, sfix = f"{ticker.upper()} ", f" expiring {expiry}"
        if expiry == dates[0]:
            pfix = f"{ticker.upper()} Weekly "
            sfix = ""

        embeds = [
            disnake.Embed(
                title=f"{ticker.upper()} Overview",
                color=cfg.COLOR,
            ),
            disnake.Embed(
                title=f"{pfix}Open Interest{sfix}",
                description=plt_link,
                colour=cfg.COLOR,
            ),
        ]
        choices = [
            disnake.SelectOption(label=f"{ticker.upper()} Overview",
                                 value="0",
                                 emoji="🟢"),
            disnake.SelectOption(label=f"{pfix}Open Interest{sfix}",
                                 value="1",
                                 emoji="🟢"),
        ]
        embeds_img = []

        i, i2, end = 0, 0, 20
        df_calls = []
        dindex = len(calls_df.index)
        while i <= dindex:
            df_calls = calls_df.iloc[i:end]
            df_calls.append(df_calls)
            figp = df2img.plot_dataframe(
                df_calls,
                fig_size=(1000, (40 + (40 * 20))),
                col_width=[3, 3, 3, 3],
                tbl_cells=cfg.PLT_TBL_CELLS,
                font=cfg.PLT_TBL_FONT,
                template=cfg.PLT_TBL_STYLE_TEMPLATE,
                paper_bgcolor="rgba(0, 0, 0, 0)",
            )
            imagefile = f"opt-calls{i}.png"

            df2img.save_dataframe(fig=figp, filename=imagefile)
            image = Image.open(imagefile)
            image = autocrop_image(image, 0)
            image.save(imagefile, "PNG", quality=100)
            uploaded_image = gst_imgur.upload_image(imagefile,
                                                    title="something")
            image_link = uploaded_image.link
            embeds_img.append(f"{image_link}", )
            embeds.append(
                disnake.Embed(
                    title=f"{pfix}Calls{sfix}",
                    colour=cfg.COLOR,
                ), )
            i2 += 1
            i += 20
            end += 20
            os.remove(imagefile)

        # Add Calls page field
        i, page, puts_page = 2, 0, 3
        i3 = i2 + 2
        choices.append(
            disnake.SelectOption(label="Calls Page 1", value="2",
                                 emoji="🟢"), )
        for i in range(2, i3):
            page += 1
            puts_page += 1

            embeds[i].add_field(name=f"Calls Page {page}",
                                value="_ _",
                                inline=True)

        # Puts Pages
        i, end = 0, 20
        df_puts = []

        dindex = len(puts_df.index)
        while i <= dindex:
            df_puts = puts_df.iloc[i:end]
            df_puts.append(df_puts)
            figp = df2img.plot_dataframe(
                df_puts,
                fig_size=(1000, (40 + (40 * 20))),
                col_width=[3, 3, 3, 3],
                tbl_cells=cfg.PLT_TBL_CELLS,
                font=cfg.PLT_TBL_FONT,
                template=cfg.PLT_TBL_STYLE_TEMPLATE,
                paper_bgcolor="rgba(0, 0, 0, 0)",
            )
            imagefile = f"opt-puts{i}.png"

            df2img.save_dataframe(fig=figp, filename=imagefile)
            image = Image.open(imagefile)
            image = autocrop_image(image, 0)
            image.save(imagefile, "PNG", quality=100)
            uploaded_image = gst_imgur.upload_image(imagefile,
                                                    title="something")
            image_link = uploaded_image.link
            embeds_img.append(f"{image_link}", )
            embeds.append(
                disnake.Embed(
                    title=f"{pfix}Puts{sfix}",
                    colour=cfg.COLOR,
                ), )
            i2 += 1
            i += 20
            end += 20
            os.remove(imagefile)

        # Add Puts page field
        i, page = 0, 0
        puts_page -= 1
        i2 += 2
        choices.append(
            disnake.SelectOption(label="Puts Page 1",
                                 value=f"{puts_page}",
                                 emoji="🟢"), )
        for i in range(puts_page, i2):
            page += 1
            embeds[i].add_field(name=f"Puts Page {page}",
                                value="_ _",
                                inline=True)

        # Author/Footer
        for i in range(0, i2):
            embeds[i].set_author(
                name=cfg.AUTHOR_NAME,
                url=cfg.AUTHOR_URL,
                icon_url=cfg.AUTHOR_ICON_URL,
            )
            embeds[i].set_footer(
                text=cfg.AUTHOR_NAME,
                icon_url=cfg.AUTHOR_ICON_URL,
            )

        # Set images to Pages
        i = 0
        img_i = 0
        embeds[1].set_image(url=image_link_oi)
        for i in range(2, i2):
            embeds[i].set_image(url=embeds_img[img_i])
            img_i += 1
            i += 1

        if url:
            embeds[0].set_thumbnail(url=f"{url}")
        else:
            embeds[0].set_thumbnail(url=cfg.AUTHOR_ICON_URL)

        # Overview Section
        embeds[0].add_field(name=f"{df.iloc[0, 0]}", value=iv, inline=False)

        embeds[0].add_field(name=f"•{df.iloc[1, 0]}",
                            value=f"```css\n{df.iloc[1, 1]}\n```",
                            inline=True)
        for N in range(2, 6):
            embeds[0].add_field(
                name=f"_ _ _ _ _ _ _ _ _ _ •{df.iloc[N, 0]}",
                value=f"```css\n{df.iloc[N, 1]}\n```",
                inline=True,
            )

        embeds[0].add_field(name="_ _", value="_ _", inline=False)
        for N in range(6, 8):
            embeds[0].add_field(
                name=f"_ _ _ _ _ _ _ _ _ _ •{df.iloc[N, 0]}",
                value=f"```css\n{df.iloc[N, 1]}\n```",
                inline=True,
            )

        embeds[0].add_field(name="_ _", value="_ _", inline=False)
        for N in range(8, 10):
            embeds[0].add_field(
                name=f"_ _ _ _ _ _ _ _ _ _ •{df.iloc[N, 0]}",
                value=f"```css\n{df.iloc[N, 1]}\n```",
                inline=True,
            )

        embeds[0].add_field(name="_ _", value="_ _", inline=False)
        for N in range(10, 12):
            embeds[0].add_field(
                name=f"_ _ _ _ _ _ _ _ _ _ •{df.iloc[N, 0]}",
                value=f"```css\n{df.iloc[N, 1]}\n```",
                inline=True,
            )

        embeds[0].set_footer(text=f"Page 1 of {len(embeds)}")
        executionTime2 = time.time() - startTime2
        print(
            f"\n> {__name__} is finished: time in seconds: {executionTime2}\n")
        await ctx.send(embed=embeds[0], view=Menu(embeds, choices))

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

        await ctx.send(embed=embed, delete_after=30.0)
예제 #17
0
async def kc_command(ctx,
                     ticker="",
                     length="20",
                     scalar="2",
                     mamode="sma",
                     offset="0",
                     start="",
                     end=""):
    """Displays chart with keltner channel [Yahoo Finance]"""

    try:

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

        # Check for argument
        possible_ma = ["sma", "ema", "wma", "hma", "zlma"]

        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)
        if not offset.lstrip("-").isnumeric():
            raise Exception("Number has to be an integer")
        offset = float(offset)

        if mamode not in possible_ma:
            raise Exception("Invalid ma entered")

        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.kc(
            df_stock["High"],
            df_stock["Low"],
            df_stock["Adj Close"],
            length,
            scalar,
            mamode,
            offset,
        )

        # Output Data
        fig = go.Figure()
        fig.add_trace(
            go.Scatter(
                name="upper",
                x=df_ta.index,
                y=df_ta.iloc[:, 2].values,
                opacity=1,
                mode="lines",
                line_color="indigo",
                showlegend=False,
            ), )
        fig.add_trace(
            go.Scatter(
                name="lower",
                x=df_ta.index,
                y=df_ta.iloc[:, 0].values,
                opacity=1,
                mode="lines",
                line_color="indigo",
                fill="tonexty",
                fillcolor="rgba(74, 0, 128, 0.2)",
                showlegend=False,
            ), )
        fig.add_trace(
            go.Scatter(
                name="mid",
                x=df_ta.index,
                y=df_ta.iloc[:, 1].values,
                opacity=1,
                line=dict(
                    width=1.5,
                    dash="dash",
                ),
            ), )
        fig.add_trace(
            go.Scatter(
                name=f"{ticker}",
                x=df_stock.index,
                y=df_stock["Adj Close"],
                line=dict(color="#fdc708", width=2),
                opacity=1,
            ), )
        fig.update_layout(
            margin=dict(l=0, r=0, t=50, b=20),
            template=cfg.PLT_TA_STYLE_TEMPLATE,
            colorway=cfg.PLT_TA_COLORWAY,
            title=f"{ticker} Keltner Channels ({mamode.upper()})",
            title_x=0.5,
            yaxis_title="Stock Price ($)",
            xaxis_title="Time",
            yaxis=dict(fixedrange=False, ),
            xaxis=dict(
                rangeslider=dict(visible=False),
                type="date",
            ),
            dragmode="pan",
            legend=dict(yanchor="top", y=0.99, xanchor="left", x=0.01),
        )
        config = dict({"scrollZoom": True})
        imagefile = "ta_kc.png"

        # Check if interactive settings are enabled
        plt_link = ""
        if cfg.INTERACTIVE:
            html_ran = random.randint(69, 69420)
            fig.write_html(f"in/kc_{html_ran}.html", config=config)
            plt_link = f"[Interactive]({cfg.INTERACTIVE_URL}/kc_{html_ran}.html)"

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

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

        # Paste fig onto background img and autocrop background
        img = img.resize((w, h), Image.ANTIALIAS)
        x1 = int(0.5 * im_bg.size[0]) - int(0.5 * img.size[0])
        y1 = int(0.5 * im_bg.size[1]) - int(0.5 * img.size[1])
        x2 = int(0.5 * im_bg.size[0]) + int(0.5 * img.size[0])
        y2 = int(0.5 * im_bg.size[1]) + int(0.5 * img.size[1])
        img = img.convert("RGB")
        im_bg.paste(img, box=(x1 - 5, y1, x2 - 5, y2))
        im_bg.save(imagefile, "PNG", quality=100)
        image = Image.open(imagefile)
        image = autocrop_image(image, 0)
        image.save(imagefile, "PNG", quality=100)

        image = disnake.File(imagefile)

        print(f"Image {imagefile}")
        if cfg.DEBUG:
            logger.debug("Image: %s", imagefile)
        title = "Stocks: Keltner-Channel " + ticker
        embed = disnake.Embed(title=title,
                              description=plt_link,
                              colour=cfg.COLOR)
        embed.set_image(url=f"attachment://{imagefile}")
        embed.set_author(
            name=cfg.AUTHOR_NAME,
            icon_url=cfg.AUTHOR_ICON_URL,
        )
        os.remove(imagefile)

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

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

        await ctx.send(embed=embed, delete_after=30.0)
예제 #18
0
async def topbuys_command(
    ctx,
    gov_type="",
    past_transactions_months: int = 5,
    num: int = 20,
    raw: bool = False,
):
    """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,
            )

        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() + "```"

        plt.style.use("seaborn")
        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")
        imagefile = "gov_topbuys.png"

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

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

        image = Image.open(imagefile)
        image = autocrop_image(image, 0)
        image.save(imagefile, "PNG", quality=100)

        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 = disnake.Embed(title=title,
                                  description=description,
                                  colour=cfg.COLOR)
        else:
            embed = disnake.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 = disnake.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, delete_after=30.0)
예제 #19
0
async def contracts_command(ctx,
                            ticker: str = "",
                            past_transaction_days: int = 10,
                            raw: bool = False):
    """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 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)
        plt.style.use("seaborn")

        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")
        imagefile = "gov_contracts.png"

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

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

        image = Image.open(imagefile)
        image = autocrop_image(image, 0)
        image.save(imagefile, "PNG", quality=100)

        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 = disnake.Embed(title=title,
                                  description=description,
                                  colour=cfg.COLOR)
        else:
            embed = disnake.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 = disnake.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, delete_after=30.0)
예제 #20
0
async def chain_command(
    ctx,
    ticker: str = None,
    expiry: str = None,
    opt_type: str = None,
    min_sp: float = None,
    max_sp: float = None,
):
    """Show calls/puts for given ticker and expiration"""
    try:
        # Debug
        if cfg.DEBUG:
            logger.debug("opt-chain %s %s %s %s %s", ticker, expiry, opt_type,
                         min_sp, max_sp)

        # Check for argument
        if not ticker:
            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, str(expiry))
        calls_df = options.calls
        puts_df = options.puts

        column_map = {
            "openInterest": "oi",
            "volume": "vol",
            "impliedVolatility": "iv"
        }
        columns = [
            "strike",
            "bid",
            "ask",
            "volume",
            "openInterest",
            "impliedVolatility",
        ]

        if opt_type == "Calls":
            df = calls_df[columns].rename(columns=column_map)
        if opt_type == "Puts":
            df = puts_df[columns].rename(columns=column_map)

        min_strike = np.percentile(df["strike"], 1)
        max_strike = np.percentile(df["strike"], 100)

        if min_sp:
            min_strike = min_sp
        if max_sp:
            max_strike = max_sp
            if min_sp > max_sp:  # type: ignore
                min_sp, max_sp = max_strike, min_strike

        df = df[df["strike"] >= min_strike]
        df = df[df["strike"] <= max_strike]

        df["iv"] = pd.to_numeric(df["iv"].astype(float))

        formats = {"iv": "{:.2f}"}
        for col, f in formats.items():
            df[col] = df[col].map(lambda x: f.format(x))  # pylint: disable=W0640
        df.set_index("strike", inplace=True)

        title = f"Stocks: {opt_type} Option Chain for {ticker.upper()} on {expiry} [yfinance]"

        embeds: list = []
        # Weekly Calls Pages
        i, i2, end = 0, 0, 20
        df_pg = []
        embeds_img = []
        dindex = len(df.index)
        while i < dindex:
            df_pg = df.iloc[i:end]
            df_pg.append(df_pg)
            figp = df2img.plot_dataframe(
                df_pg,
                fig_size=(1000, (40 + (40 * 20))),
                col_width=[3, 3, 3, 3],
                tbl_cells=dict(height=35, ),
                font=dict(
                    family="Consolas",
                    size=20,
                ),
                template="plotly_dark",
                paper_bgcolor="rgba(0, 0, 0, 0)",
            )
            imagefile = f"opt-chain{i}.png"

            df2img.save_dataframe(fig=figp, filename=imagefile)
            image = Image.open(imagefile)
            image = autocrop_image(image, 0)
            image.save(imagefile, "PNG", quality=100)

            uploaded_image = gst_imgur.upload_image(imagefile,
                                                    title="something")
            image_link = uploaded_image.link
            embeds_img.append(f"{image_link}", )
            embeds.append(disnake.Embed(
                title=title,
                colour=cfg.COLOR,
            ), )
            i2 += 1
            i += 20
            end += 20
            os.remove(imagefile)

        # Author/Footer
        for i in range(0, i2):
            embeds[i].set_author(
                name=cfg.AUTHOR_NAME,
                url=cfg.AUTHOR_URL,
                icon_url=cfg.AUTHOR_ICON_URL,
            )
            embeds[i].set_footer(
                text=cfg.AUTHOR_NAME,
                icon_url=cfg.AUTHOR_ICON_URL,
            )

        i = 0
        for i in range(0, i2):
            embeds[i].set_image(url=embeds_img[i])

            i += 1
        embeds[0].set_footer(text=f"Page 1 of {len(embeds)}")
        options = [
            disnake.SelectOption(label="Home", value="0", emoji="🟢"),
        ]

        await ctx.send(embed=embeds[0], view=Menu(embeds, options))

    except Exception as e:
        embed = disnake.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, delete_after=30.0)
예제 #21
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("econ-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")

        # Check for argument
        if df_group.empty:
            raise Exception("No available data found")

        # Output data
        df = pd.DataFrame(df_group)
        df = df.replace(np.nan, 0)

        df = df.set_axis(
            [
                "Name",
                "MarketCap",
                "P/E",
                "FwdP/E",
                "PEG",
                "P/S",
                "P/B",
                "P/C",
                "P/FCF",
                "EPSpast5Y",
                "EPSnext5Y",
                "Salespast5Y",
                "Change",
                "Volume",
            ],
            axis="columns",
        )

        df["P/E"] = pd.to_numeric(df["P/E"].astype(float))
        df["FwdP/E"] = pd.to_numeric(df["FwdP/E"].astype(float))
        df["EPSpast5Y"] = pd.to_numeric(df["EPSpast5Y"].astype(float))
        df["EPSnext5Y"] = pd.to_numeric(df["EPSnext5Y"].astype(float))
        df["Salespast5Y"] = pd.to_numeric(df["Salespast5Y"].astype(float))
        df["Volume"] = pd.to_numeric(df["Volume"].astype(float))
        df["Volume"] = df["Volume"] / 1_000_000

        formats = {
            "P/E": "{:.2f}",
            "FwdP/E": "{:.2f}",
            "EPSpast5Y": "{:.2f}",
            "EPSnext5Y": "{:.2f}",
            "Salespast5Y": "{:.2f}",
            "Change": "{:.2f}",
            "Volume": "{:.0f}M",
        }
        for col, value in formats.items():
            df[col] = df[col].map(lambda x: value.format(x))  # pylint: disable=W0640

        df = df.fillna("")
        df.set_index("Name", inplace=True)

        dindex = len(df.index)
        fig = df2img.plot_dataframe(
            df,
            fig_size=(1600, (40 + (50 * dindex))),
            col_width=[12, 5, 4, 4, 4, 4, 4, 4, 4, 6, 6, 6, 4, 4],
            tbl_cells=dict(
                align=["left", "center"],
                height=35,
            ),
            template="plotly_dark",
            font=dict(
                family="Consolas",
                size=20,
            ),
            paper_bgcolor="rgba(0, 0, 0, 0)",
        )
        imagefile = "econ-valuation.png"
        df2img.save_dataframe(fig=fig, filename=imagefile)

        image = Image.open(imagefile)
        image = autocrop_image(image, 0)
        image.save(imagefile, "PNG", quality=100)

        image = disnake.File(imagefile)

        title = f"Economy: [Finviz] Valuation {group}"
        embed = disnake.Embed(title=title, colour=cfg.COLOR)
        embed.set_image(url=f"attachment://{imagefile}")
        embed.set_author(
            name=cfg.AUTHOR_NAME,
            icon_url=cfg.AUTHOR_ICON_URL,
        )
        os.remove(imagefile)

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

    except Exception as e:
        embed = disnake.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, delete_after=30.0)
예제 #22
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:
            print(f"opt-vol {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

        df_opt = pd.merge(put_v, call_v, left_index=True, right_index=True)
        dmax = df_opt.values.max()

        fig = go.Figure()
        fig.add_trace(
            go.Scatter(
                x=call_v.index,
                y=call_v.values,
                name="Calls",
                mode="lines+markers",
                line=dict(color="green", width=3),
            ))
        fig.add_trace(
            go.Scatter(
                x=put_v.index,
                y=put_v.values,
                name="Puts",
                mode="lines+markers",
                line=dict(color="red", width=3),
            ))
        fig.add_trace(
            go.Scatter(
                x=[current_price, current_price],
                y=[0, dmax],
                mode="lines",
                line=dict(color="gold", width=2),
                name="Current Price",
            ))
        fig.update_xaxes(
            range=[min_strike, max_strike],
            constrain="domain",
        )
        fig.update_layout(
            margin=dict(l=0, r=0, t=60, b=20),
            template=cfg.PLT_SCAT_STYLE_TEMPLATE,
            title=f"Volume for {ticker.upper()} expiring {expiry}",
            title_x=0.5,
            legend_title="",
            xaxis_title="Strike",
            yaxis_title="Volume (1k)",
            xaxis=dict(rangeslider=dict(visible=False), ),
            legend=dict(yanchor="top", y=0.99, xanchor="left", x=0.01),
            dragmode="pan",
        )
        config = dict({"scrollZoom": True})
        imagefile = "opt_vol.png"
        fig.write_image(imagefile)

        # Check if interactive settings are enabled
        plt_link = ""
        if cfg.INTERACTIVE:
            html_ran = random.randint(69, 69420)
            fig.write_html(f"in/vol_{html_ran}.html", config=config)
            plt_link = f"[Interactive]({cfg.INTERACTIVE_URL}/vol_{html_ran}.html)"

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

        # Paste fig onto background img and autocrop background
        img = img.resize((w, h), Image.ANTIALIAS)
        x1 = int(0.5 * im_bg.size[0]) - int(0.5 * img.size[0])
        y1 = int(0.5 * im_bg.size[1]) - int(0.5 * img.size[1])
        x2 = int(0.5 * im_bg.size[0]) + int(0.5 * img.size[0])
        y2 = int(0.5 * im_bg.size[1]) + int(0.5 * img.size[1])
        img = img.convert("RGB")
        im_bg.paste(img, box=(x1 - 5, y1, x2 - 5, y2))
        im_bg.save(imagefile, "PNG", quality=100)
        image = Image.open(imagefile)
        image = autocrop_image(image, 0)
        image.save(imagefile, "PNG", quality=100)

        image = discord.File(imagefile)

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

        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, delete_after=30.0)
예제 #23
0
async def vsurf_command(
    ctx,
    ticker: str = "",
    z: str = "IV",
):
    """Display vol surface

    Parameters
    ----------
    ticker: Stock Ticker
    z : The variable for the Z axis
    """
    try:

        # Debug
        print(f"!stocks.opt.oi {ticker} {z}")

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

        data = yfinance_model.get_iv_surface(ticker)
        if data.empty:
            raise Exception(f"No options data found for {ticker}.\n")

        Y = data.dte
        X = data.strike
        if z == "IV":
            Z = data.impliedVolatility
            label = "Volatility"
        elif z == "OI":
            Z = data.openInterest
            label = "Open Interest"
        elif z == "LP":
            Z = data.lastPrice
            label = "Last Price"

        points3D = np.vstack((X, Y, Z)).T
        points2D = points3D[:, :2]
        tri = Delaunay(points2D)
        I, J, K = tri.simplices.T

        lighting_effects = dict(ambient=0.5,
                                diffuse=0.5,
                                roughness=0.5,
                                specular=0.4,
                                fresnel=0.4)
        fig = go.Figure(data=[
            go.Mesh3d(
                z=Z,
                x=X,
                y=Y,
                i=I,
                j=J,
                k=K,
                intensity=Z,
                colorscale=cfg.PLT_3DMESH_COLORSCALE,
                hovertemplate="<b>DTE</b>: %{y} <br><b>Strike</b>: %{x} <br><b>"
                + z + "</b>: %{z}<extra></extra>",
                showscale=False,
                flatshading=True,
                lighting=lighting_effects,
            )
        ])
        fig.update_layout(scene=dict(
            xaxis=dict(
                title="Strike",
                tickfont=dict(size=11),
                titlefont=dict(size=12),
            ),
            yaxis=dict(title="DTE", ),
            zaxis=dict(title=z, ),
        ), )
        fig.update_layout(
            margin=dict(l=0, r=0, t=40, b=20),
            width=1320,
            height=740,
            template=cfg.PLT_3DMESH_STYLE_TEMPLATE,
            title=f"{label} Surface for {ticker.upper()}",
            title_x=0.5,
            hoverlabel=cfg.PLT_3DMESH_HOVERLABEL,
            scene_camera=dict(
                up=dict(x=0, y=0, z=2),
                center=dict(x=0, y=0, z=-0.3),
                eye=dict(x=1.25, y=1.25, z=0.69),
            ),
            scene=cfg.PLT_3DMESH_SCENE,
        )
        config = dict({"scrollZoom": True})
        imagefile = "opt-vsurf.png"
        fig.write_image(imagefile)

        # Check if interactive settings are enabled
        plt_link = ""
        if cfg.INTERACTIVE:
            html_ran = random.randint(69, 69420)
            fig.write_html(f"in/vsurf_{html_ran}.html", config=config)
            plt_link = f"[Interactive]({cfg.INTERACTIVE_URL}/vsurf_{html_ran}.html)"

        img = Image.open(imagefile)
        im_bg = Image.open(cfg.IMG_BG)
        h = img.height
        w = img.width

        # Paste fig onto background img and autocrop background
        img = img.resize((w, h), Image.ANTIALIAS)
        x1 = int(0.5 * im_bg.size[0]) - int(0.5 * img.size[0])
        y1 = int(0.5 * im_bg.size[1]) - int(0.5 * img.size[1])
        x2 = int(0.5 * im_bg.size[0]) + int(0.5 * img.size[0])
        y2 = int(0.5 * im_bg.size[1]) + int(0.5 * img.size[1])
        img = img.convert("RGB")
        im_bg.paste(img, box=(x1 - 5, y1, x2 - 5, y2))
        im_bg.save(imagefile, "PNG", quality=100)
        image = Image.open(imagefile)
        image = autocrop_image(image, 0)
        image.save(imagefile, "PNG", quality=100)

        image = disnake.File(imagefile)

        print(f"Image {imagefile}")
        title = f"{label} Surface for {ticker.upper()}"
        embed = disnake.Embed(title=title,
                              description=plt_link,
                              colour=cfg.COLOR)
        embed.set_image(url=f"attachment://{imagefile}")
        embed.set_author(
            name=cfg.AUTHOR_NAME,
            icon_url=cfg.AUTHOR_ICON_URL,
        )
        os.remove(imagefile)

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

    except IndexError:
        embed = disnake.Embed(
            title="ERROR Options: Volatility Surface",
            colour=cfg.COLOR,
            description=f"Inconistent data for {ticker.upper()} {z}",
        )
        embed.set_author(
            name=cfg.AUTHOR_NAME,
            icon_url=cfg.AUTHOR_ICON_URL,
        )

        await ctx.send(embed=embed, delete_after=30.0)

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

        await ctx.send(embed=embed, delete_after=30.0)
예제 #24
0
async def historical_command(ctx, signal: str = "", 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 not in so.d_signals_desc:
            raise Exception("Invalid preset selected!")

        register_matplotlib_converters()

        screen = ticker.Ticker()

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

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

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

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

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

        if start == "":
            start = datetime.now() - timedelta(days=365)
        else:
            start = datetime.strptime(start, 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.style.use("seaborn")
        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 = disnake.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, delete_after=30.0)

            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")
        imagefile = "scr_historical.png"

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

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

        image = Image.open(imagefile)
        image = autocrop_image(image, 0)
        image.save(imagefile, "PNG", quality=100)

        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 = disnake.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 = disnake.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, delete_after=30.0)
예제 #25
0
async def oi_command(
    ctx,
    ticker: str = None,
    expiry: str = "",
    min_sp: float = None,
    max_sp: float = None,
):
    """Options OI"""

    try:

        # Debug
        print(f"!stocks.opt.oi {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)
        calls = options.calls
        puts = options.puts
        current_price = yfinance_model.get_price(ticker)

        min_strike = 0.75 * current_price
        max_strike = 1.95 * current_price

        if len(calls) > 40:
            min_strike = 0.75 * current_price
            max_strike = 1.25 * current_price

        if min_sp:
            min_strike = min_sp
        if max_sp:
            max_strike = max_sp

        call_oi = calls.set_index("strike")["openInterest"] / 1000
        put_oi = puts.set_index("strike")["openInterest"] / 1000

        df_opt = pd.merge(call_oi, put_oi, left_index=True, right_index=True)
        df_opt = df_opt.rename(
            columns={"openInterest_x": "OI_call", "openInterest_y": "OI_put"}
        )

        max_pain = op_helpers.calculate_max_pain(df_opt)
        fig = go.Figure()

        dmax = df_opt[["OI_call", "OI_put"]].values.max()
        dmin = df_opt[["OI_call", "OI_put"]].values.min()
        fig.add_trace(
            go.Scatter(
                x=df_opt.index,
                y=df_opt["OI_call"],
                name="Calls",
                mode="lines+markers",
                line=dict(color="green", width=3),
            )
        )

        fig.add_trace(
            go.Scatter(
                x=df_opt.index,
                y=df_opt["OI_put"],
                name="Puts",
                mode="lines+markers",
                line=dict(color="red", width=3),
            )
        )
        fig.add_trace(
            go.Scatter(
                x=[current_price, current_price],
                y=[dmin, dmax],
                mode="lines",
                line=dict(color="gold", width=2),
                name="Current Price",
            )
        )
        fig.add_trace(
            go.Scatter(
                x=[max_pain, max_pain],
                y=[dmin, dmax],
                mode="lines",
                line=dict(color="grey", width=3, dash="dash"),
                name=f"Max Pain: {max_pain}",
            )
        )
        fig.update_xaxes(
            range=[min_strike, max_strike],
            constrain="domain",
        )
        fig.update_layout(
            margin=dict(l=0, r=0, t=60, b=20),
            template=cfg.PLT_SCAT_STYLE_TEMPLATE,
            title=f"Open Interest for {ticker.upper()} expiring {expiry}",
            title_x=0.5,
            legend_title="",
            xaxis_title="Strike",
            yaxis_title="Open Interest (1k)",
            xaxis=dict(
                rangeslider=dict(visible=False),
            ),
            legend=dict(yanchor="top", y=0.99, xanchor="left", x=0.01),
            dragmode="pan",
        )
        config = dict({"scrollZoom": True})
        imagefile = "opt_oi.png"

        # Check if interactive settings are enabled
        plt_link = ""
        if cfg.INTERACTIVE:
            html_ran = random.randint(69, 69420)
            fig.write_html(f"in/cci_{html_ran}.html", config=config)
            plt_link = f"[Interactive]({cfg.INTERACTIVE_URL}/cci_{html_ran}.html)"

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

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

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

        image = disnake.File(imagefile)

        if cfg.DEBUG:
            print(f"Image URL: {imagefile}")
        title = f"Open Interest for {ticker.upper()} expiring {expiry}"
        embed = disnake.Embed(title=title, description=plt_link, colour=cfg.COLOR)
        embed.set_image(url=f"attachment://{imagefile}")
        embed.set_author(
            name=cfg.AUTHOR_NAME,
            icon_url=cfg.AUTHOR_ICON_URL,
        )
        os.remove(imagefile)

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

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

        await ctx.send(embed=embed, delete_after=30.0)
예제 #26
0
async def gtrades_command(
    ctx,
    ticker: str = "",
    gov_type="",
    past_transactions_months: int = 10,
    raw: bool = False,
):
    """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 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)
        plt.style.use("seaborn")

        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")
        imagefile = "gov_gtrades.png"

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

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

        image = Image.open(imagefile)
        image = autocrop_image(image, 0)
        image.save(imagefile, "PNG", quality=100)

        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 = disnake.Embed(title=title,
                                  description=description,
                                  colour=cfg.COLOR)
        else:
            embed = disnake.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 = disnake.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, delete_after=30.0)
예제 #27
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 = make_subplots(
            rows=2,
            cols=1,
            shared_xaxes=True,
            vertical_spacing=0.07,
            row_width=[0.5, 0.6],
        )
        fig.add_trace(
            go.Scatter(
                name=ticker,
                x=df_stock.index,
                y=df_stock["Adj Close"].values,
                line=dict(color="#fdc708", width=2),
                opacity=1,
                showlegend=False,
            ),
            row=1,
            col=1,
        )
        for i in range(0, df_ta.shape[1]):
            trace_name = df_ta.columns[i].replace("_", " ")
            fig.add_trace(
                go.Scatter(
                    name=trace_name,
                    x=df_ta.index,
                    y=df_ta.iloc[:, i],
                    opacity=1,
                ),
                row=2,
                col=1,
            )
        fig.add_hrect(
            y0=70,
            y1=100,
            fillcolor="red",
            opacity=0.2,
            layer="below",
            line_width=0,
            row=2,
            col=1,
        )
        fig.add_hrect(
            y0=0,
            y1=30,
            fillcolor="green",
            opacity=0.2,
            layer="below",
            line_width=0,
            row=2,
            col=1,
        )
        fig.add_hline(
            y=70,
            fillcolor="green",
            opacity=1,
            layer="below",
            line_width=3,
            line=dict(color="red", dash="dash"),
            row=2,
            col=1,
        )
        fig.add_hline(
            y=30,
            fillcolor="green",
            opacity=1,
            layer="below",
            line_width=3,
            line=dict(color="green", dash="dash"),
            row=2,
            col=1,
        )
        fig.update_layout(
            margin=dict(l=0, r=20, t=30, b=20),
            template=cfg.PLT_TA_STYLE_TEMPLATE,
            colorway=cfg.PLT_TA_COLORWAY,
            title=f"{ticker} {trace_name}",
            title_x=0.5,
            yaxis_title="Stock Price ($)",
            yaxis=dict(fixedrange=False, ),
            xaxis=dict(
                rangeslider=dict(visible=False),
                type="date",
            ),
            dragmode="pan",
            legend=dict(yanchor="top", y=0.99, xanchor="left", x=0.01),
        )
        config = dict({"scrollZoom": True})
        imagefile = "ta_rsi.png"

        # Check if interactive settings are enabled
        plt_link = ""
        if cfg.INTERACTIVE:
            html_ran = random.randint(69, 69420)
            fig.write_html(f"in/rsi_{html_ran}.html", config=config)
            plt_link = f"[Interactive]({cfg.INTERACTIVE_URL}/rsi_{html_ran}.html)"

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

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

        # Paste fig onto background img and autocrop background
        img = img.resize((w, h), Image.ANTIALIAS)
        x1 = int(0.5 * im_bg.size[0]) - int(0.5 * img.size[0])
        y1 = int(0.5 * im_bg.size[1]) - int(0.5 * img.size[1])
        x2 = int(0.5 * im_bg.size[0]) + int(0.5 * img.size[0])
        y2 = int(0.5 * im_bg.size[1]) + int(0.5 * img.size[1])
        img = img.convert("RGB")
        im_bg.paste(img, box=(x1 - 5, y1, x2 - 5, y2))
        im_bg.save(imagefile, "PNG", quality=100)
        image = Image.open(imagefile)
        image = autocrop_image(image, 0)
        image.save(imagefile, "PNG", quality=100)

        image = disnake.File(imagefile)

        print(f"Image {imagefile}")
        if cfg.DEBUG:
            logger.debug("Image: %s", imagefile)
        title = f"Stocks: Relative-Strength-Index {ticker}"
        embed = disnake.Embed(title=title,
                              description=plt_link,
                              colour=cfg.COLOR)
        embed.set_image(url=f"attachment://{imagefile}")
        embed.set_author(
            name=cfg.AUTHOR_NAME,
            icon_url=cfg.AUTHOR_ICON_URL,
        )
        os.remove(imagefile)

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

    except Exception as e:
        embed = disnake.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, delete_after=30.0)
예제 #28
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)
        ]
        plt.style.use("seaborn")

        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")
        imagefile = "gov_histcont.png"

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

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

        image = Image.open(imagefile)
        image = autocrop_image(image, 0)
        image.save(imagefile, "PNG", quality=100)

        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 = disnake.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 = disnake.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, delete_after=30.0)
예제 #29
0
async def futures_command(ctx):
    """Futures and commodities overview [Wall St. Journal]"""

    try:
        # Debug user input
        if cfg.DEBUG:
            logger.debug("econ-futures")

        # Retrieve data
        df = wsj_model.top_commodities()

        # Check for argument
        if df.empty:
            raise Exception("No available data found")

        df["Price"] = pd.to_numeric(df["Price"].astype(float))
        df["Chg"] = pd.to_numeric(df["Chg"].astype(float))
        df["%Chg"] = pd.to_numeric(df["%Chg"].astype(float))

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

        formats = {"Price": "${:.2f}", "Chg": "${:.2f}", "%Chg": "{:.2f}%"}
        for col, value in formats.items():
            df[col] = df[col].map(lambda x: value.format(x))  # pylint: disable=W0640

        df = df.fillna("")
        df.set_index(" ", inplace=True)

        df = df[[
            "Price",
            "Chg",
            "%Chg",
        ]]
        dindex = len(df.index)
        fig = df2img.plot_dataframe(
            df,
            fig_size=(800, (40 + (40 * dindex))),
            col_width=[8, 3, 3],
            tbl_cells=dict(
                align="left",
                height=35,
            ),
            template="plotly_dark",
            font=dict(
                family="Consolas",
                size=20,
            ),
            paper_bgcolor="rgba(0, 0, 0, 0)",
        )
        imagefile = "econ-futures.png"
        df2img.save_dataframe(fig=fig, filename=imagefile)
        image = Image.open(imagefile)
        image = autocrop_image(image, 0)
        image.save(imagefile, "PNG", quality=100)
        image = disnake.File(imagefile)
        title = "Economy: [WSJ] Futures/Commodities"
        embed = disnake.Embed(title=title, colour=cfg.COLOR)
        embed.set_image(url=f"attachment://{imagefile}")
        embed.set_author(
            name=cfg.AUTHOR_NAME,
            icon_url=cfg.AUTHOR_ICON_URL,
        )
        os.remove(imagefile)

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

    except Exception as e:
        embed = disnake.Embed(
            title="ERROR Economy: [WSJ] Futures/Commodities",
            colour=cfg.COLOR,
            description=e,
        )
        embed.set_author(
            name=cfg.AUTHOR_NAME,
            icon_url=cfg.AUTHOR_ICON_URL,
        )

        await ctx.send(embed=embed, delete_after=30.0)
예제 #30
0
async def est_command(ctx, ticker: str = ""):
    """Displays earning estimates [Business Insider]"""

    try:

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

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

        (
            df_year_estimates,
            df_quarter_earnings,
            df_quarter_revenues,
        ) = business_insider_model.get_estimates(ticker)

        if (df_quarter_revenues.empty and df_year_estimates.empty
                and df_quarter_earnings.empty):
            raise Exception("Enter a valid ticker")

        # Debug user output
        if cfg.DEBUG:
            logger.debug(df_year_estimates.to_string())
            logger.debug(df_quarter_earnings.to_string())
            logger.debug(df_quarter_revenues.to_string())

        dindex = len(df_year_estimates.index)
        fig = df2img.plot_dataframe(
            df_year_estimates,
            fig_size=(1200, (40 + (60 * dindex))),
            col_width=[12, 4, 4, 4, 4],
            tbl_cells=dict(height=35, ),
            font=dict(
                family="Consolas",
                size=20,
            ),
            template="plotly_dark",
            paper_bgcolor="rgba(0, 0, 0, 0)",
        )
        imagefile = "estimates.png"

        df2img.save_dataframe(fig=fig, filename=imagefile)
        image = Image.open(imagefile)
        image = autocrop_image(image, 0)
        image.save(imagefile, "PNG", quality=100)
        uploaded_image = gst_imgur.upload_image(imagefile, title="something")
        link_estimates = uploaded_image.link

        os.remove(imagefile)

        fig = df2img.plot_dataframe(
            df_quarter_earnings,
            fig_size=(1200, (40 + (40 * 20))),
            col_width=[5, 5, 4, 4, 5, 4],
            tbl_cells=dict(height=35, ),
            font=dict(
                family="Consolas",
                size=20,
            ),
            template="plotly_dark",
            paper_bgcolor="rgba(0, 0, 0, 0)",
        )
        imagefile = "earnings.png"

        df2img.save_dataframe(fig=fig, filename=imagefile)
        image = Image.open(imagefile)
        image = autocrop_image(image, 0)
        image.save(imagefile, "PNG", quality=100)
        uploaded_image = gst_imgur.upload_image(imagefile, title="something")
        link_earnings = uploaded_image.link
        os.remove(imagefile)

        fig = df2img.plot_dataframe(
            df_quarter_revenues,
            fig_size=(1200, (40 + (40 * 20))),
            col_width=[5, 5, 4, 4, 5, 4],
            tbl_cells=dict(height=35, ),
            font=dict(
                family="Consolas",
                size=20,
            ),
            template="plotly_dark",
            paper_bgcolor="rgba(0, 0, 0, 0)",
        )
        imagefile = "revenues.png"

        df2img.save_dataframe(fig=fig, filename=imagefile)
        image = Image.open(imagefile)
        image = autocrop_image(image, 0)
        image.save(imagefile, "PNG", quality=100)
        uploaded_image = gst_imgur.upload_image(imagefile, title="something")
        link_revenues = uploaded_image.link
        os.remove(imagefile)

        embeds = [
            disnake.Embed(
                title=f"**{ticker.upper()} Year Estimates**",
                color=cfg.COLOR,
            ),
            disnake.Embed(
                title=f"**{ticker.upper()} Quarter Earnings**",
                colour=cfg.COLOR,
            ),
            disnake.Embed(
                title=f"**{ticker.upper()} Quarter Revenues**",
                colour=cfg.COLOR,
            ),
        ]
        embeds[0].set_image(url=link_estimates)
        embeds[1].set_image(url=link_earnings)
        embeds[2].set_image(url=link_revenues)
        # Output data
        choices = [
            disnake.SelectOption(label=f"{ticker.upper()} Year Estimates",
                                 value="0",
                                 emoji="🟢"),
            disnake.SelectOption(label=f"{ticker.upper()} Quarter Earnings",
                                 value="1",
                                 emoji="🟢"),
            disnake.SelectOption(label=f"{ticker.upper()} Quarter Revenues",
                                 value="2",
                                 emoji="🟢"),
        ]

        await ctx.send(embed=embeds[0], view=Menu(embeds, choices))
    except Exception as e:
        embed = disnake.Embed(
            title="ERROR Stocks: [Business Insider] Earning Estimates",
            colour=cfg.COLOR,
            description=e,
        )
        embed.set_author(
            name=cfg.AUTHOR_NAME,
            icon_url=cfg.AUTHOR_ICON_URL,
        )

        await ctx.send(embed=embed, delete_after=30.0)