示例#1
0
async def stoch_command(ctx,
                        ticker="",
                        fast_k="14",
                        slow_d="3",
                        slow_k="3",
                        start="",
                        end=""):
    """Displays chart with stochastic relative strength average [Yahoo Finance]"""

    try:

        # Debug
        if cfg.DEBUG:
            print(
                f"!stocks.ta.stoch {ticker} {fast_k} {slow_k} {slow_d} {start} {end}"
            )

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

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

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

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

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

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

        df_ta = momentum_model.stoch("1440min", df_stock, fast_k, slow_d,
                                     slow_k)

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

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

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

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

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

        await ctx.send(embed=embed)

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

        await ctx.send(embed=embed)
示例#2
0
def stoch_command(
    ticker: str = "",
    interval: int = 15,
    past_days: int = 0,
    fast_k="14",
    slow_d="3",
    slow_k="4",
    start="",
    end="",
    extended_hours: bool = False,
    heikin_candles: bool = False,
    news: bool = False,
):
    """Displays chart with stochastic relative strength average [Yahoo Finance]"""

    # Debug
    if imps.DEBUG:
        logger.debug(
            "ta stoch %s %s %s %s %s %s %s %s %s %s %s",
            ticker,
            interval,
            past_days,
            fast_k,
            slow_k,
            slow_d,
            start,
            end,
            extended_hours,
            heikin_candles,
            news,
        )

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

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

    # Retrieve Data
    df_stock, start, end, bar_start = load_candle.stock_data(
        ticker=ticker,
        interval=interval,
        past_days=past_days,
        extended_hours=extended_hours,
        start=start,
        end=end,
        heikin_candles=heikin_candles,
    )

    df_ta = df_stock.loc[(df_stock.index >= start) & (df_stock.index < end)]

    if df_ta.empty:
        raise Exception("No Data Found")

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

    # Output Data
    if interval != 1440:
        df_ta = df_ta.loc[(df_ta.index >= bar_start) & (df_ta.index < end)]
    df_ta = df_ta.fillna(0.0)

    plot = load_candle.candle_fig(
        df_ta,
        ticker,
        interval,
        extended_hours,
        news,
        bar=bar_start,
        int_bar=interval,
        rows=2,
        cols=1,
        shared_xaxes=True,
        vertical_spacing=0.07,
        row_width=[0.4, 0.6],
        specs=[[{
            "secondary_y": True
        }], [{
            "secondary_y": False
        }]],
    )
    title = f"<b>{plot['plt_title']} STOCH RSI</b>"
    fig = plot["fig"]
    idx = 6 if interval != 1440 else 11

    fig.add_trace(
        go.Scatter(
            name=f"%K {fast_k}, {slow_d}, {slow_k}",
            x=df_ta.index,
            y=df_ta.iloc[:, idx].values,
            line=dict(width=1.8),
            mode="lines",
            opacity=1,
        ),
        row=2,
        col=1,
    )
    fig.add_trace(
        go.Scatter(
            name=f"%D {fast_k}, {slow_d}, {slow_k}",
            x=df_ta.index,
            y=df_ta.iloc[:, (idx + 1)].values,
            line=dict(width=1.8, dash="dash"),
            opacity=1,
        ),
        row=2,
        col=1,
    )
    fig.add_hrect(
        y0=80,
        y1=100,
        fillcolor="red",
        opacity=0.2,
        layer="below",
        line_width=0,
        row=2,
        col=1,
    )
    fig.add_hrect(
        y0=0,
        y1=20,
        fillcolor="green",
        opacity=0.2,
        layer="below",
        line_width=0,
        row=2,
        col=1,
    )
    fig.add_hline(
        y=80,
        fillcolor="green",
        opacity=1,
        layer="below",
        line_width=3,
        line=dict(color="red", dash="dash"),
        row=2,
        col=1,
    )
    fig.add_hline(
        y=20,
        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=0, t=50, b=20),
        template=imps.PLT_TA_STYLE_TEMPLATE,
        colorway=imps.PLT_TA_COLORWAY,
        title=title,
        title_x=0.01,
        title_font_size=14,
        dragmode="pan",
    )
    imagefile = "ta_stoch.png"

    # Check if interactive settings are enabled
    plt_link = ""
    if imps.INTERACTIVE:
        plt_link = imps.inter_chart(fig, imagefile, callback=False)

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

    return {
        "title":
        f"Stocks: Stochastic-Relative-Strength-Index {ticker.upper()}",
        "description": plt_link,
        "imagefile": imagefile,
    }
def view_stoch(
    s_ticker: str,
    s_interval: str,
    df_stock: pd.DataFrame,
    fastkperiod: int,
    slowdperiod: int,
    slowkperiod: int,
    export: str,
):
    """Plot stochastic oscillator signal

    Parameters
    ----------
    s_ticker : str
        Stock ticker
    s_interval : str
        Interval of data
    df_stock : pd.DataFrame
        Dataframe of prices
    fastkperiod : int
        Fast k period
    slowdperiod : int
        Slow d period
    slowkperiod : int
        Slow k period
    export : str
        Format to export data
    """
    df_ta = momentum_model.stoch(s_interval, df_stock, fastkperiod,
                                 slowdperiod, slowkperiod)

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

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

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

    if gtff.USE_ION:
        plt.ion()

    plt.gcf().autofmt_xdate()
    fig.tight_layout(pad=1)
    plt.show()
    print("")

    export_data(
        export,
        os.path.dirname(os.path.abspath(__file__)).replace("common", "stocks"),
        "stoch",
        df_ta,
    )
示例#4
0
def stoch_command(ticker="", fast_k="14", slow_d="3", slow_k="3", start="", end=""):
    """Displays chart with stochastic relative strength average [Yahoo Finance]"""

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

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

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

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

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

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

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

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

    fig = make_subplots(
        rows=2,
        cols=1,
        shared_xaxes=True,
        vertical_spacing=0.07,
        row_width=[0.5, 0.7],
    )
    fig.add_trace(
        go.Scatter(
            x=df_stock.index,
            y=df_stock["Adj Close"].values,
            line=dict(color="#fdc708", width=2),
            opacity=1,
            showlegend=False,
        ),
        row=1,
        col=1,
    )
    K = df_ta.columns[0].replace("_", " ")
    D = df_ta.columns[1].replace("_", " ")
    fig.add_trace(
        go.Scatter(
            name=f"%K {K}",
            x=df_stock.index,
            y=df_ta.iloc[:, 0].values,
            line=dict(width=1.8),
            opacity=1,
        ),
        row=2,
        col=1,
    )
    fig.add_trace(
        go.Scatter(
            name=f"%D {D}",
            x=df_stock.index,
            y=df_ta.iloc[:, 1].values,
            line=dict(width=1.8, dash="dash"),
            opacity=1,
        ),
        row=2,
        col=1,
    )
    fig.add_hrect(
        y0=80,
        y1=100,
        fillcolor="red",
        opacity=0.2,
        layer="below",
        line_width=0,
        row=2,
        col=1,
    )
    fig.add_hrect(
        y0=0,
        y1=20,
        fillcolor="green",
        opacity=0.2,
        layer="below",
        line_width=0,
        row=2,
        col=1,
    )
    fig.add_hline(
        y=80,
        fillcolor="green",
        opacity=1,
        layer="below",
        line_width=3,
        line=dict(color="red", dash="dash"),
        row=2,
        col=1,
    )
    fig.add_hline(
        y=20,
        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=0, t=40, b=20),
        template=cfg.PLT_TA_STYLE_TEMPLATE,
        colorway=cfg.PLT_TA_COLORWAY,
        title=f"Stochastic Relative Strength Index (STOCH RSI) on {ticker}",
        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_stoch.png"

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

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

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

    return {
        "title": f"Stocks: Stochastic-Relative-Strength-Index {ticker}",
        "description": plt_link,
        "imagefile": imagefile,
    }
示例#5
0
async def stoch_command(
    ctx, ticker="", fast_k="14", slow_d="3", slow_k="3", start="", end=""
):
    """Displays chart with stochastic relative strength average [Yahoo Finance]"""

    try:

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

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

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

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

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

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

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

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

        fig = make_subplots(
            rows=2,
            cols=1,
            shared_xaxes=True,
            vertical_spacing=0.07,
            row_width=[0.5, 0.7],
        )
        fig.add_trace(
            go.Scatter(
                x=df_stock.index,
                y=df_stock["Adj Close"].values,
                line=dict(color="#fdc708", width=2),
                opacity=1,
                showlegend=False,
            ),
            row=1,
            col=1,
        )
        K = df_ta.columns[0].replace("_", " ")
        D = df_ta.columns[1].replace("_", " ")
        fig.add_trace(
            go.Scatter(
                name=f"%K {K}",
                x=df_stock.index,
                y=df_ta.iloc[:, 0].values,
                line=dict(width=1.8),
                opacity=1,
            ),
            row=2,
            col=1,
        )
        fig.add_trace(
            go.Scatter(
                name=f"%D {D}",
                x=df_stock.index,
                y=df_ta.iloc[:, 1].values,
                line=dict(width=1.8, dash="dash"),
                opacity=1,
            ),
            row=2,
            col=1,
        )
        fig.add_hrect(
            y0=80,
            y1=100,
            fillcolor="red",
            opacity=0.2,
            layer="below",
            line_width=0,
            row=2,
            col=1,
        )
        fig.add_hrect(
            y0=0,
            y1=20,
            fillcolor="green",
            opacity=0.2,
            layer="below",
            line_width=0,
            row=2,
            col=1,
        )
        fig.add_hline(
            y=80,
            fillcolor="green",
            opacity=1,
            layer="below",
            line_width=3,
            line=dict(color="red", dash="dash"),
            row=2,
            col=1,
        )
        fig.add_hline(
            y=20,
            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=0, t=40, b=20),
            template=cfg.PLT_TA_STYLE_TEMPLATE,
            colorway=cfg.PLT_TA_COLORWAY,
            title=f"Stochastic Relative Strength Index (STOCH RSI) on {ticker}",
            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_stoch.png"

        # Check if interactive settings are enabled
        plt_link = ""
        if cfg.INTERACTIVE:
            html_ran = random.randint(69, 69420)
            fig.write_html(f"in/stoch_{html_ran}.html", config=config)
            plt_link = f"[Interactive]({cfg.INTERACTIVE_URL}/stoch_{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

        # 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=f"Stocks: Stochastic-Relative-Strength-Index {ticker}",
            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: Stochastic-Relative-Strength-Index",
            colour=cfg.COLOR,
            description=e,
        )
        embed.set_author(
            name=cfg.AUTHOR_NAME,
            icon_url=cfg.AUTHOR_ICON_URL,
        )

        await ctx.send(embed=embed, delete_after=30.0)
示例#6
0
def display_stoch(
    ohlc: pd.DataFrame,
    fastkperiod: int = 14,
    slowdperiod: int = 3,
    slowkperiod: int = 3,
    s_ticker: str = "",
    export: str = "",
    external_axes: Optional[List[plt.Axes]] = None,
) -> None:
    """Plot stochastic oscillator signal

    Parameters
    ----------
    ohlc : pd.DataFrame
        Dataframe of prices
    fastkperiod : int
        Fast k period
    slowdperiod : int
        Slow d period
    slowkperiod : int
        Slow k period
    s_ticker : str
        Stock ticker
    export : str
        Format to export data
    external_axes : Optional[List[plt.Axes]], optional
        External axes (3 axes are expected in the list), by default None
    """
    df_ta = momentum_model.stoch(
        ohlc["High"],
        ohlc["Low"],
        ohlc["Adj Close"],
        fastkperiod,
        slowdperiod,
        slowkperiod,
    )
    # This plot has 3 axes
    if not external_axes:
        _, axes = plt.subplots(2,
                               1,
                               sharex=True,
                               figsize=plot_autoscale(),
                               dpi=PLOT_DPI)
        ax1, ax2 = axes
        ax3 = ax2.twinx()
    else:
        if len(external_axes) != 3:
            logger.error("Expected list of three axis items.")
            console.print("[red]Expected list of 3 axis items./n[/red]")
            return
        ax1, ax2, ax3 = external_axes

    plot_data = pd.merge(ohlc,
                         df_ta,
                         how="outer",
                         left_index=True,
                         right_index=True)
    plot_data = reindex_dates(plot_data)

    ax1.plot(plot_data.index, plot_data["Adj Close"].values)

    ax1.set_title(
        f"Stochastic Relative Strength Index (STOCH RSI) on {s_ticker}")
    ax1.set_xlim(plot_data.index[0], plot_data.index[-1])
    ax1.set_ylabel("Share Price ($)")
    theme.style_primary_axis(
        ax1,
        data_index=plot_data.index.to_list(),
        tick_labels=plot_data["date"].to_list(),
    )

    ax2.plot(plot_data.index, plot_data[df_ta.columns[0]].values)
    ax2.plot(plot_data.index, plot_data[df_ta.columns[1]].values, ls="--")
    ax2.set_xlim(plot_data.index[0], plot_data.index[-1])
    theme.style_primary_axis(
        ax2,
        data_index=plot_data.index.to_list(),
        tick_labels=plot_data["date"].to_list(),
    )

    ax3.set_ylim(ax2.get_ylim())
    ax3.axhspan(80, 100, facecolor=theme.down_color, alpha=0.2)
    ax3.axhspan(0, 20, facecolor=theme.up_color, alpha=0.2)
    ax3.axhline(80, color=theme.down_color, ls="--")
    ax3.axhline(20, color=theme.up_color, ls="--")
    theme.style_twin_axis(ax3)

    ax2.set_yticks([20, 80])
    ax2.set_yticklabels(["OVERSOLD", "OVERBOUGHT"])
    ax2.legend([f"%K {df_ta.columns[0]}", f"%D {df_ta.columns[1]}"])

    if external_axes is None:
        theme.visualize_output()

    export_data(
        export,
        os.path.dirname(os.path.abspath(__file__)).replace("common", "stocks"),
        "stoch",
        df_ta,
    )