Discordbot/expiryreactions++ (#1102)

* added load extension for options menu

* options menu: oi, iv, unusual options

* Update opt_menu.py

* Update unu.py

if no num requested set default to 10

* Update opt_menu.py

+ !oi ticker expiry request added without inputting date format. accepts 0-9 up to 10 weeks
+ added option volume plot (works same as oi)

* Create vol.py

* Create reaction_helper.py

* Cleaned up, added historical options

Cleaned up
+ added historical options data
+ added expiry reaction helper function

* Create hist.py

* cleanup

* added min/max strike price

* cleanup

* cleanup, added min/max strike price

* Update opt_menu.py

* added yfinance if no tradier token

* Update vol.py

* Update opt_menu.py

* Create oi_tradier.py

* Update oi.py

* Update opt_menu.py

* Update oi.py

* Update opt_menu.py

* Update oi.py

* Update iv.py

* Update unu.py

* Update oi_tradier.py

* Update hist.py

* Update opt_menu.py

* Update reaction_helper.py

* Create options_menu.py

* Update run_discordbot.py

* Update vol.py

* Rename discordbot/options_menu.py to discordbot/stocks/options/options_menu.py

* Delete opt_menu.py

* Update oi.py

+ min strike/max strike

* Delete oi_tradier.py

* Update options_menu.py

* Update hist.py

* Update vol.py

* Update oi.py

* Update options_menu.py

* Linting/Pre-Commit Fixes

* linting

* Linting

* linting

* pylint fixes

* Update iv.py

* Update options_menu.py

* Update reaction_helper.py

* Improved Code

- removed 148 lines same function

* Update run_discordbot.py

* Update reaction_helper.py
This commit is contained in:
teh_coderer
2021-12-29 21:07:46 -06:00
committed by GitHub
parent af62b22bb7
commit f83ee10c22
7 changed files with 765 additions and 60 deletions

View File

@@ -0,0 +1,126 @@
import asyncio
import discord
from gamestonk_terminal.config_terminal import TRADIER_TOKEN
from gamestonk_terminal.stocks.options import tradier_model, yfinance_model
from discordbot.run_discordbot import gst_bot
import discordbot.config_discordbot as cfg
async def expiry_dates_reaction(ctx, ticker, expiry, func_cmd, call_arg: tuple = None):
if TRADIER_TOKEN == "REPLACE_ME":
dates = yfinance_model.option_expirations(ticker)
else:
dates = tradier_model.option_expirations(ticker)
index_dates = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
if expiry is not None:
try:
if expiry not in dates:
exp = int(expiry.replace("-", ""))
if (expiry not in dates) and (exp not in index_dates):
raise Exception("Enter a valid expiration date.")
if expiry in dates:
if call_arg is None:
await func_cmd(ctx, ticker, expiry)
else:
await func_cmd(ctx, ticker, expiry, *call_arg)
return
if exp in index_dates:
expiry = dates[int(expiry)]
if call_arg is None:
await func_cmd(ctx, ticker, expiry)
else:
await func_cmd(ctx, ticker, expiry, *call_arg)
return
except Exception as e:
embed = discord.Embed(
title="ERROR Options: Expiry Date",
colour=cfg.COLOR,
description=e,
)
embed.set_author(
name=cfg.AUTHOR_NAME,
icon_url=cfg.AUTHOR_ICON_URL,
)
await ctx.send(embed=embed)
return
if not dates:
embed = discord.Embed(
title="ERROR Options",
colour=cfg.COLOR,
description="Enter a valid stock ticker",
)
embed.set_author(
name=cfg.AUTHOR_NAME,
icon_url=cfg.AUTHOR_ICON_URL,
)
await ctx.send(embed=embed)
return
text = (
"```0️⃣ " + dates[0] + "\n"
"1️⃣ " + dates[1] + "\n"
"2️⃣ " + dates[2] + "\n"
"3️⃣ " + dates[3] + "\n"
"4️⃣ " + dates[4] + "\n"
"5️⃣ " + dates[5] + "\n"
"6️⃣ " + dates[6] + "\n"
"7️⃣ " + dates[7] + "\n"
"8️⃣ " + dates[8] + "\n"
"9️⃣ " + dates[9] + "```"
)
title = " " + ticker.upper() + " Options: Expiry Date"
embed = discord.Embed(title=title, description=text, colour=cfg.COLOR)
embed.set_author(
name=cfg.AUTHOR_NAME,
icon_url=cfg.AUTHOR_ICON_URL,
)
msg = await ctx.send(embed=embed)
emoji_list = ["0️⃣", "1️⃣", "2️⃣", "3️⃣", "4️⃣", "5️⃣", "6️⃣", "7️⃣", "8️⃣", "9️⃣"]
for emoji in emoji_list:
await msg.add_reaction(emoji)
def check(reaction, user):
return user == ctx.message.author and str(reaction.emoji) in emoji_list
try:
reaction, _ = await gst_bot.wait_for(
"reaction_add", timeout=cfg.MENU_TIMEOUT, check=check
)
for N in range(0, 10):
if reaction.emoji == emoji_list[N]:
if cfg.DEBUG:
print(f"Reaction selected: {N}")
expiry = dates[N]
if call_arg is None:
await func_cmd(ctx, ticker, expiry)
else:
await func_cmd(ctx, ticker, expiry, *call_arg)
for emoji in emoji_list:
await msg.remove_reaction(emoji, ctx.bot.user)
except asyncio.TimeoutError:
for emoji in emoji_list:
await msg.remove_reaction(emoji, ctx.bot.user)
embed = discord.Embed(
description="Error timeout - you snooze you lose! 😋",
colour=cfg.COLOR,
title="TIMEOUT " + ticker.upper() + " Options: Expiry Date",
)
embed.set_author(
name=cfg.AUTHOR_NAME,
icon_url=cfg.AUTHOR_ICON_URL,
)
await ctx.send(embed=embed)

View File

@@ -0,0 +1,103 @@
import os
import discord
import mplfinance as mpf
import discordbot.config_discordbot as cfg
from gamestonk_terminal.stocks.options import tradier_model
async def hist_command(
ctx, ticker: str = None, expiry: str = "", strike: float = None, put: bool = False
):
"""Plot historical option prices
Parameters
----------
ticker: str
Stock ticker
expiry: str
accepts 0-9
0 being weeklies
1+ for weeks out
prompts reaction helper if empty
strike: float
Option strike price
put: bool
c for call
p for put
"""
try:
# Debug
if cfg.DEBUG:
print(f"!stocks.opt.hist {ticker} {strike} {put} {expiry}")
# Check for argument
if ticker is None:
raise Exception("Stock ticker is required")
if strike is None or put == "":
raise Exception(
'A strike and c/p is required\n```bash\n"!hist {ticker} {strike} {c/p}"```'
)
chain_id = None
df_hist = tradier_model.get_historical_options(
ticker, expiry, strike, put, chain_id
)
op_type = ["call", "put"][put]
mc = mpf.make_marketcolors(
up="green", down="red", edge="black", wick="black", volume="in", ohlc="i"
)
s = mpf.make_mpf_style(
base_mpl_style="seaborn", marketcolors=mc, gridstyle=":", y_on_right=True
)
mpf.plot(
df_hist,
type="candle",
volume=True,
title=f"\n{ticker.upper()} {strike} {op_type} expiring {expiry} Historical",
tight_layout=True,
style=s,
figratio=(10, 7),
figscale=1.10,
figsize=(12, 5),
update_width_config=dict(
candle_linewidth=1.0, candle_width=0.8, volume_linewidth=1.0
),
savefig="opt_hist.png",
)
imagefile = "opt_hist.png"
image = discord.File(imagefile)
if cfg.DEBUG:
print(f"Image: {imagefile}")
title = " " + ticker.upper() + " Options: History"
embed = discord.Embed(title=title, colour=cfg.COLOR)
embed.set_image(url="attachment://opt_hist.png")
embed.set_author(
name=cfg.AUTHOR_NAME,
icon_url=cfg.AUTHOR_ICON_URL,
)
os.remove("opt_hist.png")
await ctx.send(embed=embed, file=image)
except Exception as e:
embed = discord.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)

View File

@@ -0,0 +1,48 @@
import discord
from tabulate import tabulate
import discordbot.config_discordbot as cfg
from gamestonk_terminal.stocks.options import barchart_model
async def iv_command(ctx, ticker: str = None):
"""Options IV"""
try:
# Debug
if cfg.DEBUG:
print(f"!stocks.opt.iv {ticker}")
# Check for argument
if ticker is None:
raise Exception("Stock ticker is required")
df = barchart_model.get_options_info(ticker)
tickerr = ticker.upper()
report = "```" + tabulate(df, tablefmt="fancy_grid", showindex=False) + "```"
embed = discord.Embed(
title=" " + tickerr.__str__() + " Options: IV",
description=report,
colour=cfg.COLOR,
)
embed.set_author(
name=cfg.AUTHOR_NAME,
icon_url=cfg.AUTHOR_ICON_URL,
)
await ctx.send(embed=embed)
except Exception as e:
embed = discord.Embed(
title="ERROR 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)

View File

@@ -3,31 +3,52 @@ import os
import discord
import matplotlib.pyplot as plt
import pandas as pd
import yfinance as yf
import discordbot.config_discordbot as cfg
from discordbot.run_discordbot import gst_imgur
from gamestonk_terminal.config_plot import PLOT_DPI
from gamestonk_terminal.helper_funcs import plot_autoscale
from gamestonk_terminal.stocks.options import op_helpers
from gamestonk_terminal.stocks.options import op_helpers, yfinance_model
async def oi_command(ctx, ticker: str = "", expiration_date: str = ""):
"""Show open interest for expiration and ticker"""
async def oi_command(
ctx,
ticker: str = None,
expiry: str = "",
min_sp: float = None,
max_sp: float = None,
):
"""Options OI"""
try:
# Debug
if cfg.DEBUG:
print(f"!stocks.opt.oi {ticker.upper()} {expiration_date}")
print(f"!stocks.opt.oi {ticker} {expiry} {min_sp} {max_sp}")
# Check for argument
if ticker == "":
# Check for argument
if ticker is None:
raise Exception("Stock ticker is required")
fig, ax = plt.subplots(figsize=plot_autoscale(), dpi=PLOT_DPI)
dates = yfinance_model.option_expirations(ticker)
options = yf.Ticker(ticker).option_chain(expiration_date)
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)
if min_sp is None:
min_strike = 0.75 * current_price
else:
min_strike = min_sp
if max_sp is None:
max_strike = 1.90 * current_price
else:
max_strike = max_sp
call_oi = calls.set_index("strike")["openInterest"] / 1000
put_oi = puts.set_index("strike")["openInterest"] / 1000
@@ -36,22 +57,10 @@ async def oi_command(ctx, ticker: str = "", expiration_date: str = ""):
columns={"openInterest_x": "OI_call", "openInterest_y": "OI_put"}
)
df_opt = pd.merge(call_oi, put_oi, left_index=True, right_index=True).fillna(0)
df_opt = df_opt.rename(
columns={"openInterest_x": "OI_call", "openInterest_y": "OI_put"}
)
max_pain = op_helpers.calculate_max_pain(df_opt)
current_price = float(yf.Ticker(ticker).info["regularMarketPrice"])
plt.style.use("seaborn")
fig, ax = plt.subplots(figsize=plot_autoscale(), dpi=PLOT_DPI)
call_oi.plot(
x="strike",
y="openInterest",
label="Calls",
ax=ax,
marker="o",
ls="-",
c="g",
)
put_oi.plot(
x="strike",
y="openInterest",
@@ -61,37 +70,48 @@ async def oi_command(ctx, ticker: str = "", expiration_date: str = ""):
ls="-",
c="r",
)
ax.set_xlabel("Strike Price")
ax.set_ylabel("Open Interest (1k)")
call_oi.plot(
x="strike",
y="openInterest",
label="Calls",
ax=ax,
marker="o",
ls="-",
c="g",
)
ax.axvline(
current_price, lw=2, c="k", ls="--", label="Current Price", alpha=0.4
)
ax.axvline(max_pain, lw=3, c="k", label=f"Max Pain: {max_pain}", alpha=0.4)
ax.set_title(f"Open Interest for {ticker.upper()} on {expiration_date}")
ax.grid("on")
ax.legend()
ax.set_xlabel("Strike Price")
ax.set_ylabel("Open Interest (1k) ")
ax.set_xlim(min_strike, max_strike)
ax.set_title(f"Open Interest for {ticker.upper()} expiring {expiry}")
plt.legend(loc=0)
fig.tight_layout()
plt.savefig("OI.png")
uploaded_image = gst_imgur.upload_image("OI.png", title="something")
image_link = uploaded_image.link
imagefile = "opt_oi.png"
plt.savefig("opt_oi.png")
image = discord.File(imagefile)
if cfg.DEBUG:
print(f"Image URL: {image_link}")
title = f"Open Interest for {ticker} on {expiration_date}"
print(f"Image {imagefile}")
title = " " + ticker.upper() + " Options: Open Interest"
embed = discord.Embed(title=title, colour=cfg.COLOR)
embed.set_image(url="attachment://opt_oi.png")
embed.set_author(
name=cfg.AUTHOR_NAME,
icon_url=cfg.AUTHOR_ICON_URL,
)
embed.set_image(url=image_link)
os.remove("OI.png")
os.remove("opt_oi.png")
await ctx.send(embed=embed)
await ctx.send(embed=embed, file=image)
except Exception as e:
embed = discord.Embed(
title="ERROR Stock-Options: Open Interest",
title="ERROR Options: Open Interest",
colour=cfg.COLOR,
description=e,
)

View File

@@ -1,21 +1,58 @@
import asyncio
import discord
import discordbot.config_discordbot as cfg
from discordbot.run_discordbot import gst_bot
from discordbot.reaction_helper import expiry_dates_reaction
from discordbot.stocks.options.calls import calls_command
from discordbot.stocks.options.expirations import expirations_command
from discordbot.stocks.options.hist import hist_command
from discordbot.stocks.options.iv import iv_command
from discordbot.stocks.options.oi import oi_command
from discordbot.stocks.options.puts import puts_command
from discordbot.stocks.options.unu import unu_command
from discordbot.stocks.options.vol import vol_command
class OptionsCommands(discord.ext.commands.Cog):
"""Dark Pool Shorts menu"""
"""Options menu."""
def __init__(self, bot: discord.ext.commands.Bot):
self.bot = bot
@discord.ext.commands.command(name="stocks.opt.iv", usage="[ticker]")
async def iv(self, ctx: discord.ext.commands.Context, ticker: str = None):
"""Displays ticker options IV [Barchart]
Parameters
-----------
ticker: str
ticker,
"""
async with ctx.typing():
await asyncio.sleep(0.2)
await iv_command(ctx, ticker)
@discord.ext.commands.command(name="stocks.opt.unu", usage="[ticker]")
async def unu(
self,
ctx: discord.ext.commands.Context,
num: int = None,
):
"""Unusual Options
Parameters
-----------
ticker: str
ticker
"""
async with ctx.typing():
await asyncio.sleep(0.2)
await unu_command(ctx, num)
@discord.ext.commands.command(name="stocks.opt.exp", usage="[ticker]")
async def expirations(self, ctx: discord.ext.commands.Context, ticker=""):
"""Get available expirations [yfinance]
@@ -28,10 +65,11 @@ class OptionsCommands(discord.ext.commands.Cog):
await expirations_command(ctx, ticker)
@discord.ext.commands.command(
name="stocks.opt.calls", usage="[ticker] [expiration]"
name="stocks.opt.calls",
usage="[ticker] [expiration 0 - 9 (weeks out) or YYYY-MM-DD]",
)
async def calls(
self, ctx: discord.ext.commands.Context, ticker="", expiration: str = ""
self, ctx: discord.ext.commands.Context, ticker: str = None, expiry: str = None
):
"""Get call options for ticker and given expiration
@@ -39,14 +77,27 @@ class OptionsCommands(discord.ext.commands.Cog):
----------
ticker: str
Stock ticker
expiration: str
Expiration date
expiry: str
accepts 0-9 or YYYY-MM-DD
0 weeklies, 1+ for weeks out
prompts reaction helper if empty
"""
await calls_command(ctx, ticker, expiration)
async with ctx.typing():
await asyncio.sleep(0.2)
@discord.ext.commands.command(name="stocks.opt.puts", usage="[ticker] [expiration]")
if cfg.DEBUG:
print(f"!stocks.opt.calls {ticker} {expiry}")
func_cmd = calls_command
await expiry_dates_reaction(ctx, ticker, expiry, func_cmd)
@discord.ext.commands.command(
name="stocks.opt.puts",
usage="[ticker] [expiration 0 - 9 (weeks out) or YYYY-MM-DD]",
)
async def puts(
self, ctx: discord.ext.commands.Context, ticker="", expiration: str = ""
self, ctx: discord.ext.commands.Context, ticker: str = None, expiry: str = None
):
"""Get put options for ticker and given expiration
@@ -54,25 +105,160 @@ class OptionsCommands(discord.ext.commands.Cog):
----------
ticker: str
Stock ticker
expiration: str
Expiration date
expiry: str
accepts 0-9 or YYYY-MM-DD
0 weeklies, 1+ for weeks out
prompts reaction helper if empty
"""
await puts_command(ctx, ticker, expiration)
async with ctx.typing():
await asyncio.sleep(0.2)
@discord.ext.commands.command(name="stocks.opt.oi", usage="[ticker] [expiration]")
if cfg.DEBUG:
print(f"!stocks.opt.puts {ticker} {expiry}")
func_cmd = puts_command
await expiry_dates_reaction(ctx, ticker, expiry, func_cmd)
@discord.ext.commands.command(
name="stocks.opt.oi",
usage="[ticker] [expiration 0 - 9 (weeks out) or YYYY-MM-DD] [min strike] [max strike]",
)
async def oi(
self, ctx: discord.ext.commands.Context, ticker="", expiration: str = ""
self,
ctx: discord.ext.commands.Context,
ticker: str = None,
expiry: str = None,
min_sp: float = None,
max_sp: float = None,
):
"""Get put options for ticker and given expiration
"""Display options open interest for ticker and given expiration [Max Pain]
Parameters
----------
-----------
ticker: str
Stock ticker
expiration: str
Expiration date
ticker
strike: float
strike
expiry: str
accepts 0-9 or YYYY-MM-DD
min_sp: float
min strike price
max_sp:float
max strike price
Sends a message to the discord user with the expiry dates if empty.
The user can then select a reaction to trigger the selected date.
"""
await oi_command(ctx, ticker, expiration)
async with ctx.typing():
await asyncio.sleep(0.2)
if cfg.DEBUG:
print(f"!stocks.opt.oi {ticker} {expiry} {min_sp} {max_sp}")
call_arg = (min_sp, max_sp)
func_cmd = oi_command
await expiry_dates_reaction(ctx, ticker, expiry, func_cmd, call_arg)
@discord.ext.commands.command(
name="stocks.opt.hist",
usage="[ticker] [strike] [c or p (call/put)] [expiration 0 - 9 (weeks out) or YYYY-MM-DD]",
)
async def hist(
self,
ctx: discord.ext.commands.Context,
ticker: str = None,
strike: float = None,
put="",
expiry: str = None,
):
"""Display chart of given option historical price [Tradier]
Parameters
-----------
ticker: str
ticker
strike: float
strike
put: bool
c for call
p for put
expiry: str
accepts 0-9 or YYYY-MM-DD
Sends a message to the discord user with the expiry dates if empty.
The user can then select a reaction to trigger the selected date.
"""
async with ctx.typing():
await asyncio.sleep(0.2)
if cfg.DEBUG:
print(f"!stocks.opt.hist {ticker} {strike} {put} {expiry}")
if strike is None or put == "":
embed = discord.Embed(
title="ERROR Options: History",
colour=cfg.COLOR,
description='A strike and c/p is required\n```bash\n"!stocks.opt.hist {ticker} {strike} {c/p}"```',
)
await ctx.send(embed=embed)
return
if put == "p":
put = bool(True)
if put == "c":
put = bool(False)
call_arg = (
strike,
put,
)
func_cmd = hist_command
await expiry_dates_reaction(ctx, ticker, expiry, func_cmd, call_arg)
@discord.ext.commands.command(
name="stocks.opt.vol",
usage="[ticker] [expiration 0 - 9 (weeks out) or YYYY-MM-DD] [min strike] [max strike]",
)
async def vol(
self,
ctx: discord.ext.commands.Context,
ticker: str = None,
expiry: str = None,
min_sp: float = None,
max_sp: float = None,
):
"""Display options volume for ticker and given expiration
Parameters
-----------
ticker: str
ticker
strike: float
strike
expiry: str
accepts 0-9 or YYYY-MM-DD
min_sp: float
min strike price
max_sp:float
max strike price
Sends a message to the discord user with the expiry dates if empty.
The user can then select a reaction to trigger the selected date.
"""
async with ctx.typing():
await asyncio.sleep(0.2)
if cfg.DEBUG:
print(f"!stocks.opt.vol {ticker} {expiry} {min_sp} {max_sp}")
call_arg = (min_sp, max_sp)
func_cmd = vol_command
await expiry_dates_reaction(ctx, ticker, expiry, func_cmd, call_arg)
@discord.ext.commands.command(name="stocks.opt")
async def opt(self, ctx: discord.ext.commands.Context, ticker="", expiration=""):
@@ -161,7 +347,7 @@ class OptionsCommands(discord.ext.commands.Cog):
embed = discord.Embed(
description="Error timeout - you snooze you lose! 😋",
colour=cfg.COLOR,
title="TIMEOUT Stocks: Government (GOV) Menu",
title="TIMEOUT Stocks: Options Menu",
).set_author(
name=cfg.AUTHOR_NAME,
icon_url=cfg.AUTHOR_ICON_URL,

View File

@@ -0,0 +1,109 @@
import discord
import numpy as np
import pandas as pd
import requests
from tabulate import tabulate
import discordbot.config_discordbot as cfg
from gamestonk_terminal.helper_funcs import get_user_agent
async def unu_command(ctx, num: int = None):
"""Unusual Options"""
try:
# Debug
if cfg.DEBUG:
print(f"!stocks.opt.unu {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:
print("Error in fdscanner request")
return pd.DataFrame(), "request error"
data_list.append(r.json())
ticker, expiry, option_strike, option_type, ask, bid, oi, vol, voi = (
[],
[],
[],
[],
[],
[],
[],
[],
[],
)
for data in data_list:
for entry in data["data"]:
ticker.append(entry["tk"])
expiry.append(entry["expiry"])
option_strike.append(float(entry["s"]))
option_type.append("Put" if entry["t"] == "P" else "Call")
ask.append(entry["a"])
bid.append(entry["b"])
oi.append(entry["oi"])
vol.append(entry["v"])
voi.append(entry["vol/oi"])
df = pd.DataFrame(
{
"Ticker": ticker,
"Exp": expiry,
"Strike": option_strike,
"Type": option_type,
"Vol/OI": voi,
"Vol": vol,
"OI": oi,
}
)
df = df.replace({"2021-", "2022-"}, "", regex=True)
report = (
"```"
+ tabulate(
df,
headers=["T", "Exp", "ST", "C/P", "V/O", "Vol", "OI"],
tablefmt="fancy_grid",
showindex=False,
floatfmt=["", "", ".1f", "", ".1f", ".0f", ".0f", ".2f", ".2f"],
)
+ "```"
)
embed = discord.Embed(
title="Unusual Options",
description=report,
colour=cfg.COLOR,
)
embed.set_author(
name=cfg.AUTHOR_NAME,
icon_url=cfg.AUTHOR_ICON_URL,
)
await ctx.send(embed=embed)
except Exception as e:
embed = discord.Embed(
title="ERROR Unusual Options",
colour=cfg.COLOR,
description=e,
)
embed.set_author(
name=cfg.AUTHOR_NAME,
icon_url=cfg.AUTHOR_ICON_URL,
)
await ctx.send(embed=embed)

View File

@@ -0,0 +1,113 @@
import os
import discord
import matplotlib.pyplot as plt
import discordbot.config_discordbot as cfg
from gamestonk_terminal import config_plot as cfp
from gamestonk_terminal.helper_funcs import plot_autoscale
from gamestonk_terminal.stocks.options import yfinance_model
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"!stocks.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.90 * current_price
else:
max_strike = max_sp
calls = options.calls
puts = options.puts
call_v = calls.set_index("strike")["volume"] / 1000
put_v = puts.set_index("strike")["volume"] / 1000
plt.style.use("seaborn")
fig, ax = plt.subplots(figsize=plot_autoscale(), dpi=cfp.PLOT_DPI)
put_v.plot(
x="strike",
y="volume",
label="Puts",
ax=ax,
marker="o",
ls="-",
c="r",
)
call_v.plot(
x="strike",
y="volume",
label="Calls",
ax=ax,
marker="o",
ls="-",
c="g",
)
ax.axvline(
current_price, lw=2, c="k", ls="--", label="Current Price", alpha=0.7
)
ax.grid("on")
ax.set_xlabel("Strike Price")
ax.set_ylabel("Volume (1k) ")
ax.set_xlim(min_strike, max_strike)
ax.set_title(f"Volume for {ticker.upper()} expiring {expiry}")
plt.legend(loc=0)
fig.tight_layout(pad=1)
imagefile = "opt_vol.png"
plt.savefig("opt_vol.png")
image = discord.File(imagefile)
if cfg.DEBUG:
print(f"Image: {imagefile}")
title = " " + ticker.upper() + " Options: Volume"
embed = discord.Embed(title=title, colour=cfg.COLOR)
embed.set_image(url="attachment://opt_vol.png")
embed.set_author(
name=cfg.AUTHOR_NAME,
icon_url=cfg.AUTHOR_ICON_URL,
)
os.remove("opt_vol.png")
await ctx.send(embed=embed, file=image)
except Exception as e:
embed = discord.Embed(
title="ERROR Options: Volume",
colour=cfg.COLOR,
description=e,
)
embed.set_author(
name=cfg.AUTHOR_NAME,
icon_url=cfg.AUTHOR_ICON_URL,
)
await ctx.send(embed=embed)