Discordbot screener (#1087)

* improve screener on discordbot

* improve screener code of discordbot

* linter

* line length
This commit is contained in:
Didier Rodrigues Lopes
2021-12-23 12:04:11 +00:00
committed by GitHub
parent 52d9c29242
commit 2d14890c41
12 changed files with 404 additions and 405 deletions

View File

@@ -2,18 +2,18 @@ import difflib
import discord
import pandas as pd
from gamestonk_terminal.stocks.screener.finviz_model import get_screener_data
import discordbot.config_discordbot as cfg
from discordbot.helpers import pagination
from gamestonk_terminal.stocks.screener.finviz_model import get_screener_data
from discordbot.stocks.screener import screener_options as so
async def financial_command(
ctx, preset="template", sort="", limit="25", ascend="False"
):
async def financial_command(ctx, preset="template", sort="", limit="5", ascend="False"):
"""Displays returned results from preset by financial metrics [Finviz]"""
try:
preset_error = False
# Check for argument
if preset == "template" or preset not in so.all_presets:
raise Exception("Invalid preset selected!")
# Debug
if cfg.DEBUG:
@@ -36,39 +36,14 @@ async def financial_command(
raise Exception("ascend argument has to be true or false")
# Output Data
preset_error = True
df_screen = get_screener_data(
preset,
"overview",
"financial",
limit,
ascend,
)
preset_error = False
d_cols_to_sort = {
"financial": [
"Ticker",
"Market Cap",
"Dividend",
"ROA",
"ROE",
"ROI",
"Curr R",
"Quick R",
"LTDebt/Eq",
"Debt/Eq",
"Gross M",
"Oper M",
"Profit M",
"Earnings",
"Price",
"Change",
"Volume",
],
}
description = ""
if isinstance(df_screen, pd.DataFrame):
if df_screen.empty:
return []
@@ -76,7 +51,7 @@ async def financial_command(
df_screen = df_screen.dropna(axis="columns", how="all")
if sort:
if " ".join(sort) in d_cols_to_sort["financial"]:
if " ".join(sort) in so.d_cols_to_sort["financial"]:
df_screen = df_screen.sort_values(
by=[" ".join(sort)],
ascending=ascend,
@@ -85,7 +60,7 @@ async def financial_command(
else:
similar_cmd = difflib.get_close_matches(
" ".join(sort),
d_cols_to_sort["financial"],
so.d_cols_to_sort["financial"],
n=1,
cutoff=0.7,
)
@@ -98,7 +73,7 @@ async def financial_command(
)
else:
raise ValueError(
f"Wrong sort column provided! Provide one of these: {', '.join(d_cols_to_sort['financial'])}"
f"Wrong sort column provided! Select from: {', '.join(so.d_cols_to_sort['financial'])}"
)
df_screen = df_screen.fillna("")
@@ -140,19 +115,11 @@ async def financial_command(
await pagination(columns, ctx)
except Exception as e:
if not preset_error:
embed = discord.Embed(
title="ERROR Stocks: [Finviz] Financial Screener",
colour=cfg.COLOR,
description=e,
)
else:
embed = discord.Embed(
title="ERROR Stocks: [Finviz] Financial Screener",
colour=cfg.COLOR,
description=f"Wrong preset parameter entered. Use the command '{cfg.COMMAND_PREFIX}stocks.scr.presets' "
"in order to see the available presets.",
)
embed = discord.Embed(
title="ERROR Stocks: [Finviz] Financial Screener",
colour=cfg.COLOR,
description=e,
)
embed.set_author(
name=cfg.AUTHOR_NAME,
icon_url=cfg.AUTHOR_ICON_URL,

View File

@@ -7,19 +7,19 @@ from matplotlib import pyplot as plt
import yfinance as yf
from pandas.plotting import register_matplotlib_converters
from finvizfinance.screener import ticker
import discordbot.config_discordbot as cfg
from discordbot.run_discordbot import gst_imgur
from gamestonk_terminal.config_plot import PLOT_DPI
from gamestonk_terminal.stocks.screener import finviz_view
from gamestonk_terminal.stocks.screener import finviz_model
from gamestonk_terminal.helper_funcs import plot_autoscale
import discordbot.config_discordbot as cfg
from discordbot.run_discordbot import gst_imgur
from discordbot.stocks.screener import screener_options as so
# pylint:disable=no-member
async def historical_command(ctx, signal="most_volatile", start=""):
async def historical_command(ctx, signal="", start=""):
"""Displays historical price comparison between similar companies [Yahoo Finance]"""
try:
@@ -27,9 +27,11 @@ async def historical_command(ctx, signal="most_volatile", start=""):
if cfg.DEBUG:
print(f"!stocks.scr.historical {signal} {start}")
register_matplotlib_converters()
# Check for argument
if signal == "" or signal not in list(so.d_signals_desc.keys):
raise Exception("Invalid preset selected!")
presets_path = os.path.join(cfg.GST_PATH, "stocks", "screener", "presets", "")
register_matplotlib_converters()
screen = ticker.Ticker()
@@ -39,7 +41,7 @@ async def historical_command(ctx, signal="most_volatile", start=""):
else:
preset_filter = configparser.RawConfigParser()
preset_filter.optionxform = str # type: ignore
preset_filter.read(presets_path + signal + ".ini")
preset_filter.read(so.presets_path + signal + ".ini")
d_general = preset_filter["General"]
d_filters = {
@@ -118,7 +120,7 @@ async def historical_command(ctx, signal="most_volatile", start=""):
if signal:
plt.title(
f"Screener Historical Price using {finviz_view.d_signals[signal]} signal"
f"Screener Historical Price using {finviz_model.d_signals[signal]} signal"
)
else:
plt.title(f"Screener Historical Price using {signal} preset")

View File

@@ -2,16 +2,18 @@ import difflib
import discord
import pandas as pd
from gamestonk_terminal.stocks.screener.finviz_model import get_screener_data
import discordbot.config_discordbot as cfg
from discordbot.helpers import pagination
from gamestonk_terminal.stocks.screener.finviz_model import get_screener_data
from discordbot.stocks.screener import screener_options as so
async def overview_command(ctx, preset="template", sort="", limit="25", ascend="False"):
async def overview_command(ctx, preset="template", sort="", limit="5", ascend="False"):
"""Displays stocks with overview data such as Sector and Industry [Finviz]"""
try:
preset_error = False
# Check for argument
if preset == "template" or preset not in so.all_presets:
raise Exception("Invalid preset selected!")
# Debug
if cfg.DEBUG:
@@ -34,29 +36,12 @@ async def overview_command(ctx, preset="template", sort="", limit="25", ascend="
raise Exception("ascend argument has to be true or false")
# Output Data
preset_error = True
df_screen = get_screener_data(
preset,
"overview",
limit,
ascend,
)
preset_error = False
d_cols_to_sort = {
"overview": [
"Ticker",
"Company",
"Sector",
"Industry",
"Country",
"Market Cap",
"P/E",
"Price",
"Change",
"Volume",
],
}
description = ""
@@ -67,7 +52,7 @@ async def overview_command(ctx, preset="template", sort="", limit="25", ascend="
df_screen = df_screen.dropna(axis="columns", how="all")
if sort:
if " ".join(sort) in d_cols_to_sort["overview"]:
if " ".join(sort) in so.d_cols_to_sort["overview"]:
df_screen = df_screen.sort_values(
by=[" ".join(sort)],
ascending=ascend,
@@ -76,7 +61,7 @@ async def overview_command(ctx, preset="template", sort="", limit="25", ascend="
else:
similar_cmd = difflib.get_close_matches(
" ".join(sort),
d_cols_to_sort["overview"],
so.d_cols_to_sort["overview"],
n=1,
cutoff=0.7,
)
@@ -89,7 +74,7 @@ async def overview_command(ctx, preset="template", sort="", limit="25", ascend="
)
else:
raise ValueError(
f"Wrong sort column provided! Provide one of these: {', '.join(d_cols_to_sort['overview'])}"
f"Wrong sort column provided! Select from: {', '.join(so.d_cols_to_sort['overview'])}"
)
df_screen = df_screen.fillna("")
@@ -131,19 +116,11 @@ async def overview_command(ctx, preset="template", sort="", limit="25", ascend="
await pagination(columns, ctx)
except Exception as e:
if not preset_error:
embed = discord.Embed(
title="ERROR Stocks: [Finviz] Overview Screener",
colour=cfg.COLOR,
description=e,
)
else:
embed = discord.Embed(
title="ERROR Stocks: [Finviz] Overview Screener",
colour=cfg.COLOR,
description=f"Wrong preset parameter entered. Use the command '{cfg.COMMAND_PREFIX}stocks.scr.presets' "
"in order to see the available presets.",
)
embed = discord.Embed(
title="ERROR Stocks: [Finviz] Overview Screener",
colour=cfg.COLOR,
description=e,
)
embed.set_author(
name=cfg.AUTHOR_NAME,
icon_url=cfg.AUTHOR_ICON_URL,

View File

@@ -2,18 +2,18 @@ import difflib
import discord
import pandas as pd
from gamestonk_terminal.stocks.screener.finviz_model import get_screener_data
import discordbot.config_discordbot as cfg
from discordbot.helpers import pagination
from gamestonk_terminal.stocks.screener.finviz_model import get_screener_data
from discordbot.stocks.screener import screener_options as so
async def ownership_command(
ctx, preset="template", sort="", limit="25", ascend="False"
):
async def ownership_command(ctx, preset="template", sort="", limit="5", ascend="False"):
"""Displays stocks based on own share float and ownership data [Finviz]"""
try:
preset_error = False
# Check for argument
if preset == "template" or preset not in so.all_presets:
raise Exception("Invalid preset selected!")
# Debug
if cfg.DEBUG:
@@ -36,33 +36,12 @@ async def ownership_command(
raise Exception("ascend argument has to be true or false")
# Output Data
preset_error = True
df_screen = get_screener_data(
preset,
"overview",
"ownership",
limit,
ascend,
)
preset_error = False
d_cols_to_sort = {
"ownership": [
"Ticker",
"Market Cap",
"Outstanding",
"Float",
"Insider Own",
"Insider Trans",
"Inst Own",
"Inst Trans",
"Float Short",
"Short Ratio",
"Avg Volume",
"Price",
"Change",
"Volume",
],
}
description = ""
@@ -73,7 +52,7 @@ async def ownership_command(
df_screen = df_screen.dropna(axis="columns", how="all")
if sort:
if " ".join(sort) in d_cols_to_sort["ownership"]:
if " ".join(sort) in so.d_cols_to_sort["ownership"]:
df_screen = df_screen.sort_values(
by=[" ".join(sort)],
ascending=ascend,
@@ -82,7 +61,7 @@ async def ownership_command(
else:
similar_cmd = difflib.get_close_matches(
" ".join(sort),
d_cols_to_sort["ownership"],
so.d_cols_to_sort["ownership"],
n=1,
cutoff=0.7,
)
@@ -95,7 +74,7 @@ async def ownership_command(
)
else:
raise ValueError(
f"Wrong sort column provided! Provide one of these: {', '.join(d_cols_to_sort['ownership'])}"
f"Wrong sort column provided! Select from: {', '.join(so.d_cols_to_sort['ownership'])}"
)
df_screen = df_screen.fillna("")
@@ -137,19 +116,11 @@ async def ownership_command(
await pagination(columns, ctx)
except Exception as e:
if not preset_error:
embed = discord.Embed(
title="ERROR Stocks: [Finviz] Ownership Screener",
colour=cfg.COLOR,
description=e,
)
else:
embed = discord.Embed(
title="ERROR Stocks: [Finviz] Ownership Screener",
colour=cfg.COLOR,
description=f"Wrong preset parameter entered. Use the command '{cfg.COMMAND_PREFIX}stocks.scr.presets' "
"in order to see the available presets.",
)
embed = discord.Embed(
title="ERROR Stocks: [Finviz] Ownership Screener",
colour=cfg.COLOR,
description=e,
)
embed.set_author(
name=cfg.AUTHOR_NAME,
icon_url=cfg.AUTHOR_ICON_URL,

View File

@@ -2,18 +2,20 @@ import difflib
import discord
import pandas as pd
from gamestonk_terminal.stocks.screener.finviz_model import get_screener_data
import discordbot.config_discordbot as cfg
from discordbot.helpers import pagination
from gamestonk_terminal.stocks.screener.finviz_model import get_screener_data
from discordbot.stocks.screener import screener_options as so
async def performance_command(
ctx, preset="template", sort="", limit="25", ascend="False"
ctx, preset="template", sort="", limit="5", ascend="False"
):
"""Displays stocks and sort by performance categories [Finviz]"""
try:
preset_error = False
# Check for argument
if preset == "template" or preset not in so.all_presets:
raise Exception("Invalid preset selected!")
# Debug
if cfg.DEBUG:
@@ -36,14 +38,12 @@ async def performance_command(
raise Exception("ascend argument has to be true or false")
# Output Data
preset_error = True
df_screen = get_screener_data(
preset,
"overview",
"performance",
limit,
ascend,
)
preset_error = False
d_cols_to_sort = {
"performance": [
@@ -139,19 +139,11 @@ async def performance_command(
await pagination(columns, ctx)
except Exception as e:
if not preset_error:
embed = discord.Embed(
title="ERROR Stocks: [Finviz] Performance Screener",
colour=cfg.COLOR,
description=e,
)
else:
embed = discord.Embed(
title="ERROR Stocks: [Finviz] Performance Screener",
colour=cfg.COLOR,
description=f"Wrong preset parameter entered. Use the command '{cfg.COMMAND_PREFIX}stocks.scr.presets' "
"in order to see the available presets.",
)
embed = discord.Embed(
title="ERROR Stocks: [Finviz] Performance Screener",
colour=cfg.COLOR,
description=e,
)
embed.set_author(
name=cfg.AUTHOR_NAME,
icon_url=cfg.AUTHOR_ICON_URL,

View File

@@ -1,126 +0,0 @@
import os
import discord
import discordbot.config_discordbot as cfg
from discordbot.helpers import pagination
async def presets_command(ctx):
"""Displays every preset"""
try:
# Debug
if cfg.DEBUG:
print("!stocks.scr.presets")
presets_path = os.path.join(
cfg.GST_PATH, "gamestonk_terminal", "stocks", "screener", "presets", ""
)
d_signals_desc = {
"top_gainers": "stocks with the highest %% price gain today",
"top_losers": "stocks with the highest %% price loss today",
"new_high": "stocks making 52-week high today",
"new_low": "stocks making 52-week low today",
"most_volatile": "stocks with the highest widest high/low trading range today",
"most_active": "stocks with the highest trading volume today",
"unusual_volume": "stocks with unusually high volume today - the highest relative volume ratio",
"overbought": "stock is becoming overvalued and may experience a pullback.",
"oversold": "oversold stocks may represent a buying opportunity for investors",
"downgrades": "stocks downgraded by analysts today",
"upgrades": "stocks upgraded by analysts today",
"earnings_before": "companies reporting earnings today, before market open",
"earnings_after": "companies reporting earnings today, after market close",
"recent_insider_buying": "stocks with recent insider buying activity",
"recent_insider_selling": "stocks with recent insider selling activity",
"major_news": "stocks with the highest news coverage today",
"horizontal_sr": "horizontal channel of price range between support and resistance trendlines",
"tl_resistance": "once a rising trendline is broken",
"tl_support": "once a falling trendline is broken",
"wedge_up": "upward trendline support and upward trendline resistance (reversal)",
"wedge_down": "downward trendline support and downward trendline resistance (reversal)",
"wedge": "upward trendline support, downward trendline resistance (contiunation)",
"triangle_ascending": "upward trendline support and horizontal trendline resistance",
"triangle_descending": "horizontal trendline support and downward trendline resistance",
"channel_up": "both support and resistance trendlines slope upward",
"channel_down": "both support and resistance trendlines slope downward",
"channel": "both support and resistance trendlines are horizontal",
"double_top": "stock with 'M' shape that indicates a bearish reversal in trend",
"double_bottom": "stock with 'W' shape that indicates a bullish reversal in trend",
"multiple_top": "same as double_top hitting more highs",
"multiple_bottom": "same as double_bottom hitting more lows",
"head_shoulders": "chart formation that predicts a bullish-to-bearish trend reversal",
"head_shoulders_inverse": "chart formation that predicts a bearish-to-bullish trend reversal",
}
presets = [
preset.split(".")[0]
for preset in os.listdir(presets_path)
if preset[-4:] == ".ini"
]
description = "***Custom Presets:***\n"
for preset in presets:
with open(
presets_path + preset + ".ini",
encoding="utf8",
) as f:
preset_line = ""
for line in f:
if line.strip() == "[General]":
break
preset_line += line.strip()
description += f"**{preset}:** *{preset_line.split('Description: ')[1].replace('#', '')}*\n"
description += "\n\n***Default Presets:***\n"
for signame, sigdesc in d_signals_desc.items():
description += f"**{signame}:** *{sigdesc}*\n"
if len(description) <= 4000:
embed = discord.Embed(
title="Stocks: Screener Presets",
description=description,
colour=cfg.COLOR,
)
embed.set_author(
name=cfg.AUTHOR_NAME,
icon_url=cfg.AUTHOR_ICON_URL,
)
await ctx.send(embed=embed)
else:
i = 0
str_start = 0
str_end = 4000
columns = []
while i <= len(description) / 4000:
columns.append(
discord.Embed(
title="Stocks: Screener Presets",
description=description[str_start:str_end],
colour=cfg.COLOR,
).set_author(
name=cfg.AUTHOR_NAME,
icon_url=cfg.AUTHOR_ICON_URL,
)
)
str_end = str_start
str_start += 4000
i += 1
await pagination(columns, ctx)
except Exception as e:
embed = discord.Embed(
title="ERROR Stocks: Screener Presets",
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,52 @@
import discord
import discordbot.config_discordbot as cfg
from discordbot.stocks.screener import screener_options as so
async def presets_custom_command(ctx):
"""Displays every custom preset"""
try:
# Debug
if cfg.DEBUG:
print("!stocks.scr.presets")
description = ""
for preset in so.presets:
with open(
so.presets_path + preset + ".ini",
encoding="utf8",
) as f:
preset_line = ""
for line in f:
if line.strip() == "[General]":
break
preset_line += line.strip()
description += f"**{preset}:** *{preset_line.split('Description: ')[1].replace('#', '')}*\n"
embed = discord.Embed(
title="Stocks: Screener Custom Presets",
description=description,
colour=cfg.COLOR,
)
embed.set_author(
name=cfg.AUTHOR_NAME,
icon_url=cfg.AUTHOR_ICON_URL,
)
await ctx.send(embed=embed)
except Exception as e:
embed = discord.Embed(
title="ERROR Stocks: Screener Presets",
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,42 @@
import discord
import discordbot.config_discordbot as cfg
from discordbot.stocks.screener import screener_options as so
async def presets_default_command(ctx):
"""Displays default presets"""
try:
# Debug
if cfg.DEBUG:
print("!stocks.scr.presets")
description = ""
for signame, sigdesc in so.d_signals_desc.items():
description += f"**{signame}:** *{sigdesc}*\n"
embed = discord.Embed(
title="Stocks: Screener Default Presets",
description=description,
colour=cfg.COLOR,
)
embed.set_author(
name=cfg.AUTHOR_NAME,
icon_url=cfg.AUTHOR_ICON_URL,
)
await ctx.send(embed=embed)
except Exception as e:
embed = discord.Embed(
title="ERROR Stocks: Screener Presets",
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

@@ -5,14 +5,19 @@ import discordbot.config_discordbot as cfg
from discordbot.run_discordbot import gst_bot
from discordbot.stocks.screener.presets import presets_command
from discordbot.stocks.screener.historical import historical_command
from discordbot.stocks.screener.overview import overview_command
from discordbot.stocks.screener.presets_custom import presets_custom_command
from discordbot.stocks.screener.presets_default import presets_default_command
from discordbot.stocks.screener.valuation import valuation_command
from discordbot.stocks.screener.financial import financial_command
from discordbot.stocks.screener.ownership import ownership_command
from discordbot.stocks.screener.performance import performance_command
from discordbot.stocks.screener.technical import technical_command
from discordbot.stocks.screener import screener_options as so
# pylint: disable=R0912
class ScreenerCommands(discord.ext.commands.Cog):
@@ -21,10 +26,15 @@ class ScreenerCommands(discord.ext.commands.Cog):
def __init__(self, bot: discord.ext.commands.Bot):
self.bot = bot
@discord.ext.commands.command(name="stocks.scr.presets")
async def presets(self, ctx: discord.ext.commands.Context):
@discord.ext.commands.command(name="stocks.scr.presets_default")
async def presets_default(self, ctx: discord.ext.commands.Context):
"""Displays every available preset"""
await presets_command(ctx)
await presets_default_command(ctx)
@discord.ext.commands.command(name="stocks.scr.presets_custom")
async def presets_custom(self, ctx: discord.ext.commands.Context):
"""Displays every available preset"""
await presets_custom_command(ctx)
@discord.ext.commands.command(name="stocks.scr.historical")
async def historical(
@@ -50,7 +60,7 @@ class ScreenerCommands(discord.ext.commands.Cog):
ctx: discord.ext.commands.Context,
preset="template",
sort="",
limit="25",
limit="5",
ascend="False",
):
"""Displays stocks with overview data such as Sector and Industry [Finviz]
@@ -74,7 +84,7 @@ class ScreenerCommands(discord.ext.commands.Cog):
ctx: discord.ext.commands.Context,
preset="template",
sort="",
limit="25",
limit="5",
ascend="False",
):
"""Displays results from chosen preset focusing on valuation metrics [Finviz]
@@ -98,7 +108,7 @@ class ScreenerCommands(discord.ext.commands.Cog):
ctx: discord.ext.commands.Context,
preset="template",
sort="",
limit="25",
limit="5",
ascend="False",
):
"""Displays returned results from preset by financial metrics [Finviz]
@@ -122,7 +132,7 @@ class ScreenerCommands(discord.ext.commands.Cog):
ctx: discord.ext.commands.Context,
preset="template",
sort="",
limit="25",
limit="5",
ascend="False",
):
"""Displays stocks based on own share float and ownership data [Finviz]
@@ -146,7 +156,7 @@ class ScreenerCommands(discord.ext.commands.Cog):
ctx: discord.ext.commands.Context,
preset="template",
sort="",
limit="25",
limit="5",
ascend="False",
):
"""Displays stocks and sort by performance categories [Finviz]
@@ -170,7 +180,7 @@ class ScreenerCommands(discord.ext.commands.Cog):
ctx: discord.ext.commands.Context,
preset="template",
sort="",
limit="25",
limit="5",
ascend="False",
):
"""Displays stocks according to chosen preset, sorting by technical factors [Finviz]
@@ -189,7 +199,7 @@ class ScreenerCommands(discord.ext.commands.Cog):
await technical_command(ctx, preset, sort, limit, ascend)
@discord.ext.commands.command(name="stocks.scr")
async def scr(self, ctx: discord.ext.commands.Context):
async def scr(self, ctx: discord.ext.commands.Context, preset=""):
"""Screener Context Menu
Returns
@@ -198,19 +208,36 @@ class ScreenerCommands(discord.ext.commands.Cog):
The user can then select a reaction to trigger a command.
"""
if preset != "" and preset not in so.all_presets:
raise Exception("Invalid preset selected!")
if cfg.DEBUG:
print("!stocks.scr")
text = (
"0️⃣ !stocks.scr.presets\n"
"1️⃣ !stocks.scr.historical <SIGNAL> <START>\n"
"2️⃣ !stocks.scr.overview <PRESET> <SORT> <LIMIT> <ASCEND>\n"
"3️⃣ !stocks.scr.valuation <PRESET> <SORT> <LIMIT> <ASCEND>\n"
"4️⃣ !stocks.scr.financial <PRESET> <SORT> <LIMIT> <ASCEND>\n"
"5️⃣ !stocks.scr.ownership <PRESET> <SORT> <LIMIT> <ASCEND>\n"
"6️⃣ !stocks.scr.performance <PRESET> <SORT> <LIMIT> <ASCEND>\n"
"7️⃣ !stocks.scr.technical <PRESET> <SORT> <LIMIT> <ASCEND>"
)
if preset:
text = (
"0️⃣ !stocks.scr.presets_default\n"
"1️⃣ !stocks.scr.presets_custom\n"
"2️⃣ !stocks.scr.historical <SIGNAL> <START>\n"
f"3️⃣ !stocks.scr.overview {preset} <SORT> <LIMIT> <ASCEND>\n"
f"4️⃣ !stocks.scr.valuation {preset} <SORT> <LIMIT> <ASCEND>\n"
f"5️⃣ !stocks.scr.financial {preset} <SORT> <LIMIT> <ASCEND>\n"
f"6️⃣ !stocks.scr.ownership {preset} <SORT> <LIMIT> <ASCEND>\n"
f"7️⃣ !stocks.scr.performance {preset} <SORT> <LIMIT> <ASCEND>\n"
f"8️⃣ !stocks.scr.technical {preset} <SORT> <LIMIT> <ASCEND>"
)
else:
text = (
"0️⃣ !stocks.scr.presets_default\n"
"1️⃣ !stocks.scr.presets_custom\n"
"2️⃣ !stocks.scr.historical <SIGNAL> <START>\n"
"3️⃣ !stocks.scr.overview <PRESET> <SORT> <LIMIT> <ASCEND>\n"
"4️⃣ !stocks.scr.valuation <PRESET> <SORT> <LIMIT> <ASCEND>\n"
"5️⃣ !stocks.scr.financial <PRESET> <SORT> <LIMIT> <ASCEND>\n"
"6️⃣ !stocks.scr.ownership <PRESET> <SORT> <LIMIT> <ASCEND>\n"
"7️⃣ !stocks.scr.performance <PRESET> <SORT> <LIMIT> <ASCEND>\n"
"8️⃣ !stocks.scr.technical <PRESET> <SORT> <LIMIT> <ASCEND>"
)
title = "Screener Menu"
embed = discord.Embed(title=title, description=text, colour=cfg.COLOR)
@@ -220,7 +247,7 @@ class ScreenerCommands(discord.ext.commands.Cog):
)
msg = await ctx.send(embed=embed)
emoji_list = ["0️⃣", "1️⃣", "2️⃣", "3️⃣", "4️⃣", "5️⃣", "6️⃣", "7️⃣"]
emoji_list = ["0️⃣", "1️⃣", "2️⃣", "3️⃣", "4️⃣", "5️⃣", "6️⃣", "7️⃣", "8️⃣"]
for emoji in emoji_list:
await msg.add_reaction(emoji)
@@ -235,35 +262,39 @@ class ScreenerCommands(discord.ext.commands.Cog):
if reaction.emoji == "0️⃣":
if cfg.DEBUG:
print("Reaction selected: 0")
await presets_command(ctx)
await presets_default_command(ctx)
elif reaction.emoji == "1️⃣":
if cfg.DEBUG:
print("Reaction selected: 1")
await historical_command(ctx)
await presets_custom_command(ctx)
elif reaction.emoji == "2️⃣":
if cfg.DEBUG:
print("Reaction selected: 2")
await overview_command(ctx)
await historical_command(ctx, preset)
elif reaction.emoji == "3️⃣":
if cfg.DEBUG:
print("Reaction selected: 3")
await valuation_command(ctx)
await overview_command(ctx, preset)
elif reaction.emoji == "4️⃣":
if cfg.DEBUG:
print("Reaction selected: 4")
await financial_command(ctx)
await valuation_command(ctx, preset)
elif reaction.emoji == "5️⃣":
if cfg.DEBUG:
print("Reaction selected: 5")
await ownership_command(ctx)
await financial_command(ctx, preset)
elif reaction.emoji == "6️⃣":
if cfg.DEBUG:
print("Reaction selected: 6")
await performance_command(ctx)
await ownership_command(ctx, preset)
elif reaction.emoji == "7️⃣":
if cfg.DEBUG:
print("Reaction selected: 7")
await technical_command(ctx)
await performance_command(ctx, preset)
elif reaction.emoji == "8️⃣":
if cfg.DEBUG:
print("Reaction selected: 8")
await technical_command(ctx, preset)
for emoji in emoji_list:
await msg.remove_reaction(emoji, ctx.bot.user)

View File

@@ -0,0 +1,152 @@
import os
import discordbot.config_discordbot as cfg
presets_path = os.path.join(
cfg.GST_PATH, "gamestonk_terminal", "stocks", "screener", "presets", ""
)
d_signals_desc = {
"top_gainers": "stocks with the highest %% price gain today",
"top_losers": "stocks with the highest %% price loss today",
"new_high": "stocks making 52-week high today",
"new_low": "stocks making 52-week low today",
"most_volatile": "stocks with the highest widest high/low trading range today",
"most_active": "stocks with the highest trading volume today",
"unusual_volume": "stocks with unusually high volume today - the highest relative volume ratio",
"overbought": "stock is becoming overvalued and may experience a pullback.",
"oversold": "oversold stocks may represent a buying opportunity for investors",
"downgrades": "stocks downgraded by analysts today",
"upgrades": "stocks upgraded by analysts today",
"earnings_before": "companies reporting earnings today, before market open",
"earnings_after": "companies reporting earnings today, after market close",
"recent_insider_buying": "stocks with recent insider buying activity",
"recent_insider_selling": "stocks with recent insider selling activity",
"major_news": "stocks with the highest news coverage today",
"horizontal_sr": "horizontal channel of price range between support and resistance trendlines",
"tl_resistance": "once a rising trendline is broken",
"tl_support": "once a falling trendline is broken",
"wedge_up": "upward trendline support and upward trendline resistance (reversal)",
"wedge_down": "downward trendline support and downward trendline resistance (reversal)",
"wedge": "upward trendline support, downward trendline resistance (contiunation)",
"triangle_ascending": "upward trendline support and horizontal trendline resistance",
"triangle_descending": "horizontal trendline support and downward trendline resistance",
"channel_up": "both support and resistance trendlines slope upward",
"channel_down": "both support and resistance trendlines slope downward",
"channel": "both support and resistance trendlines are horizontal",
"double_top": "stock with 'M' shape that indicates a bearish reversal in trend",
"double_bottom": "stock with 'W' shape that indicates a bullish reversal in trend",
"multiple_top": "same as double_top hitting more highs",
"multiple_bottom": "same as double_bottom hitting more lows",
"head_shoulders": "chart formation that predicts a bullish-to-bearish trend reversal",
"head_shoulders_inverse": "chart formation that predicts a bearish-to-bullish trend reversal",
}
presets = [
preset.split(".")[0] for preset in os.listdir(presets_path) if preset[-4:] == ".ini"
]
all_presets = list(d_signals_desc.keys()) + presets
d_cols_to_sort = {
"overview": [
"Ticker",
"Company",
"Sector",
"Industry",
"Country",
"Market Cap",
"P/E",
"Price",
"Change",
"Volume",
],
"valuation": [
"Ticker",
"Market Cap",
"P/E",
"Fwd P/E",
"PEG",
"P/S",
"P/B",
"P/C",
"P/FCF",
"EPS this Y",
"EPS next Y",
"EPS past 5Y",
"EPS next 5Y",
"Sales past 5Y",
"Price",
"Change",
"Volume",
],
"financial": [
"Ticker",
"Market Cap",
"Dividend",
"ROA",
"ROE",
"ROI",
"Curr R",
"Quick R",
"LTDebt/Eq",
"Debt/Eq",
"Gross M",
"Oper M",
"Profit M",
"Earnings",
"Price",
"Change",
"Volume",
],
"ownership": [
"Ticker",
"Market Cap",
"Outstanding",
"Float",
"Insider Own",
"Insider Trans",
"Inst Own",
"Inst Trans",
"Float Short",
"Short Ratio",
"Avg Volume",
"Price",
"Change",
"Volume",
],
"performance": [
"Ticker",
"Perf Week",
"Perf Month",
"Perf Quart",
"Perf Half",
"Perf Year",
"Perf YTD",
"Volatility W",
"Volatility M",
"Recom",
"Avg Volume",
"Rel Volume",
"Price",
"Change",
"Volume",
],
"technical": [
"Ticker",
"Beta",
"ATR",
"SMA20",
"SMA50",
"SMA200",
"52W High",
"52W Low",
"RSI",
"Price",
"Change",
"from Open",
"Gap",
"Volume",
],
}

View File

@@ -2,18 +2,18 @@ import difflib
import discord
import pandas as pd
from gamestonk_terminal.stocks.screener.finviz_model import get_screener_data
import discordbot.config_discordbot as cfg
from discordbot.helpers import pagination
from gamestonk_terminal.stocks.screener.finviz_model import get_screener_data
from discordbot.stocks.screener import screener_options as so
async def technical_command(
ctx, preset="template", sort="", limit="25", ascend="False"
):
async def technical_command(ctx, preset="template", sort="", limit="5", ascend="False"):
"""Displays stocks according to chosen preset, sorting by technical factors [Finviz]"""
try:
preset_error = False
# Check for argument
if preset == "template" or preset not in so.all_presets:
raise Exception("Invalid preset selected!")
# Debug
if cfg.DEBUG:
@@ -36,33 +36,12 @@ async def technical_command(
raise Exception("ascend argument has to be true or false")
# Output Data
preset_error = True
df_screen = get_screener_data(
preset,
"overview",
"technical",
limit,
ascend,
)
preset_error = False
d_cols_to_sort = {
"technical": [
"Ticker",
"Beta",
"ATR",
"SMA20",
"SMA50",
"SMA200",
"52W High",
"52W Low",
"RSI",
"Price",
"Change",
"from Open",
"Gap",
"Volume",
],
}
description = ""
@@ -73,7 +52,7 @@ async def technical_command(
df_screen = df_screen.dropna(axis="columns", how="all")
if sort:
if " ".join(sort) in d_cols_to_sort["technical"]:
if " ".join(sort) in so.d_cols_to_sort["technical"]:
df_screen = df_screen.sort_values(
by=[" ".join(sort)],
ascending=ascend,
@@ -82,7 +61,7 @@ async def technical_command(
else:
similar_cmd = difflib.get_close_matches(
" ".join(sort),
d_cols_to_sort["technical"],
so.d_cols_to_sort["technical"],
n=1,
cutoff=0.7,
)
@@ -95,7 +74,7 @@ async def technical_command(
)
else:
raise ValueError(
f"Wrong sort column provided! Provide one of these: {', '.join(d_cols_to_sort['technical'])}"
f"Wrong sort column provided! Select from: {', '.join(so.d_cols_to_sort['technical'])}"
)
df_screen = df_screen.fillna("")
@@ -137,19 +116,11 @@ async def technical_command(
await pagination(columns, ctx)
except Exception as e:
if not preset_error:
embed = discord.Embed(
title="ERROR Stocks: [Finviz] Technical Screener",
colour=cfg.COLOR,
description=e,
)
else:
embed = discord.Embed(
title="ERROR Stocks: [Finviz] Technical Screener",
colour=cfg.COLOR,
description=f"Wrong preset parameter entered. Use the command '{cfg.COMMAND_PREFIX}stocks.scr.presets' "
"in order to see the available presets.",
)
embed = discord.Embed(
title="ERROR Stocks: [Finviz] Technical Screener",
colour=cfg.COLOR,
description=e,
)
embed.set_author(
name=cfg.AUTHOR_NAME,
icon_url=cfg.AUTHOR_ICON_URL,

View File

@@ -2,18 +2,18 @@ import difflib
import discord
import pandas as pd
from gamestonk_terminal.stocks.screener.finviz_model import get_screener_data
import discordbot.config_discordbot as cfg
from discordbot.helpers import pagination
from gamestonk_terminal.stocks.screener.finviz_model import get_screener_data
from discordbot.stocks.screener import screener_options as so
async def valuation_command(
ctx, preset="template", sort="", limit="25", ascend="False"
):
async def valuation_command(ctx, preset="template", sort="", limit="5", ascend="False"):
"""Displays results from chosen preset focusing on valuation metrics [Finviz]"""
try:
preset_error = False
# Check for argument
if preset == "template" or preset not in so.all_presets:
raise Exception("Invalid preset selected!")
# Debug
if cfg.DEBUG:
@@ -36,36 +36,12 @@ async def valuation_command(
raise Exception("ascend argument has to be true or false")
# Output Data
preset_error = True
df_screen = get_screener_data(
preset,
"overview",
"valuation",
limit,
ascend,
)
preset_error = False
d_cols_to_sort = {
"valuation": [
"Ticker",
"Market Cap",
"P/E",
"Fwd P/E",
"PEG",
"P/S",
"P/B",
"P/C",
"P/FCF",
"EPS this Y",
"EPS next Y",
"EPS past 5Y",
"EPS next 5Y",
"Sales past 5Y",
"Price",
"Change",
"Volume",
],
}
description = ""
@@ -76,7 +52,7 @@ async def valuation_command(
df_screen = df_screen.dropna(axis="columns", how="all")
if sort:
if " ".join(sort) in d_cols_to_sort["valuation"]:
if " ".join(sort) in so.d_cols_to_sort["valuation"]:
df_screen = df_screen.sort_values(
by=[" ".join(sort)],
ascending=ascend,
@@ -85,7 +61,7 @@ async def valuation_command(
else:
similar_cmd = difflib.get_close_matches(
" ".join(sort),
d_cols_to_sort["valuation"],
so.d_cols_to_sort["valuation"],
n=1,
cutoff=0.7,
)
@@ -98,7 +74,7 @@ async def valuation_command(
)
else:
raise ValueError(
f"Wrong sort column provided! Provide one of these: {', '.join(d_cols_to_sort['valuation'])}"
f"Wrong sort column provided! Select from: {', '.join(so.d_cols_to_sort['valuation'])}"
)
df_screen = df_screen.fillna("")
@@ -140,19 +116,11 @@ async def valuation_command(
await pagination(columns, ctx)
except Exception as e:
if not preset_error:
embed = discord.Embed(
title="ERROR Stocks: [Finviz] Valuation Screener",
colour=cfg.COLOR,
description=e,
)
else:
embed = discord.Embed(
title="ERROR Stocks: [Finviz] Valuation Screener",
colour=cfg.COLOR,
description=f"Wrong preset parameter entered. Use the command '{cfg.COMMAND_PREFIX}stocks.scr.presets' "
"in order to see the available presets.",
)
embed = discord.Embed(
title="ERROR Stocks: [Finviz] Valuation Screener",
colour=cfg.COLOR,
description=e,
)
embed.set_author(
name=cfg.AUTHOR_NAME,
icon_url=cfg.AUTHOR_ICON_URL,