From 8fe51328d9a19e2bd452f41a981b9b18eb1355c9 Mon Sep 17 00:00:00 2001 From: teh_coderer Date: Fri, 25 Mar 2022 15:39:31 -0500 Subject: [PATCH] Refactor/multi img (#1535) * few changes * import fix * missed removing test config * column order fix * import fix * removed df2img add new deps * req * update readme * add dep for image export, fix * get rid of yahoo-fin, add image export lib * import issues in some machines fix * images dir fix * init fix * fix? * test * test * Fixed text handling * missed a tbl * refactor * poetry * update dict/ fix slack image upload * Update config_discordbot.py * fixes * black * fix * import * fix nan on smile * added env settings * add cmds_text dict, some chgs * make own file for help_text * better feargreed handling * plt close Co-authored-by: Colin Delahunty <72827203+colin99d@users.noreply.github.com> Co-authored-by: DjangoServer Co-authored-by: Chavithra --- bots/cmds/cmds.py | 130 +++------------------ bots/cmds/economy_cmds.py | 4 +- bots/cmds/options_cmds.py | 23 ++++ bots/common/commands_dict.py | 113 +++++++++++++++--- bots/common/help_text.py | 124 ++++++++++++++++++++ bots/config_discordbot.py | 20 ++-- bots/economy/energy.py | 2 +- bots/economy/feargreed.py | 48 ++++---- bots/economy/futures.py | 12 +- bots/economy/performance.py | 12 +- bots/economy/reverse_repo.py | 19 ++- bots/economy/valuation.py | 12 +- bots/etf/holdings.py | 12 +- bots/etf/tops.py | 14 +-- bots/etf/whatetf.py | 12 +- bots/helpers.py | 61 +++++++--- bots/load_candle.py | 12 +- bots/run_discordbot.py | 2 +- bots/stocks/dark_pool_shorts/dpotc.py | 6 +- bots/stocks/dark_pool_shorts/pos.py | 72 ++++++------ bots/stocks/dark_pool_shorts/psi.py | 12 +- bots/stocks/dark_pool_shorts/shorted.py | 59 +++++++--- bots/stocks/disc/active.py | 12 +- bots/stocks/disc/ford.py | 12 +- bots/stocks/disc/topgainers.py | 12 +- bots/stocks/disc/toplosers.py | 12 +- bots/stocks/disc/ugs.py | 12 +- bots/stocks/disc/upcoming.py | 12 +- bots/stocks/due_diligence/arktrades.py | 12 +- bots/stocks/due_diligence/borrowed.py | 14 +-- bots/stocks/due_diligence/est.py | 28 ++--- bots/stocks/government/contracts.py | 1 + bots/stocks/government/gtrades.py | 1 + bots/stocks/government/histcont.py | 1 + bots/stocks/government/qtrcontracts.py | 1 + bots/stocks/government/topbuys.py | 1 + bots/stocks/government/toplobbying.py | 2 +- bots/stocks/government/topsells.py | 1 + bots/stocks/insider/lins.py | 12 +- bots/stocks/options/oi.py | 4 +- bots/stocks/options/opt_chain.py | 12 +- bots/stocks/options/overview.py | 37 ++---- bots/stocks/options/smile.py | 127 ++++++++++++++++++++ bots/stocks/options/unu.py | 12 +- bots/stocks/options/vol.py | 4 +- bots/stocks/screener/financial.py | 12 +- bots/stocks/screener/historical.py | 1 + bots/stocks/screener/overview.py | 12 +- bots/stocks/screener/ownership.py | 12 +- bots/stocks/screener/performance.py | 12 +- bots/stocks/screener/technical.py | 12 +- bots/stocks/screener/valuation.py | 12 +- bots/stocks/technical_analysis/ad.py | 3 +- bots/stocks/technical_analysis/adosc.py | 3 +- bots/stocks/technical_analysis/adx.py | 8 +- bots/stocks/technical_analysis/aroon.py | 8 +- bots/stocks/technical_analysis/bbands.py | 8 +- bots/stocks/technical_analysis/cci.py | 11 +- bots/stocks/technical_analysis/cg.py | 1 + bots/stocks/technical_analysis/donchian.py | 1 + bots/stocks/technical_analysis/fib.py | 2 +- bots/stocks/technical_analysis/fisher.py | 10 +- bots/stocks/technical_analysis/kc.py | 8 +- bots/stocks/technical_analysis/ma.py | 4 +- bots/stocks/technical_analysis/macd.py | 8 +- bots/stocks/technical_analysis/obv.py | 3 +- bots/stocks/technical_analysis/rsi.py | 3 +- bots/stocks/technical_analysis/stoch.py | 6 +- bots/stocks/technical_analysis/view.py | 1 + poetry.lock | 9 +- 70 files changed, 731 insertions(+), 562 deletions(-) create mode 100644 bots/common/help_text.py create mode 100644 bots/stocks/options/smile.py diff --git a/bots/cmds/cmds.py b/bots/cmds/cmds.py index 227c8ddeba8..67439936fdf 100644 --- a/bots/cmds/cmds.py +++ b/bots/cmds/cmds.py @@ -3,6 +3,7 @@ import disnake from disnake.ext import commands from bots import config_discordbot as cfg +from bots.common.help_text import cmds_text from bots.menus.menu import Menu @@ -15,124 +16,21 @@ class CmdsCommands(commands.Cog): @commands.slash_command(name="cmds") async def cmds(self, ctx: disnake.AppCmdInter): """Stocks Command List""" - siatext = ( - "```md\n[sia metrics](ticker) \n" - "[sia cps]() \n" - "[sia cpic]() \n```" - ) - etftext = ( - "```md\n[etfs disc-tops]() \n" - "[etfs holdings by-etf](etf) \n" - "[etfs holdings by-ticker](ticker) \n```" - ) - disctext = ( - "```md\n[disc fidelity]()\n" - "[disc ugs]() \n" - "[disc tops]() \n```" - ) - misctext = ( - "```md\n[futures]()\n" - "[quote](ticker)\n" - "[support]() *Mods Only\n" - "[ins-last](ticker) \n" - "[btc]() \n" - "[eth]() \n" - "[sol]() \n" - "[candle](ticker) \n```" - ) - opttext = ( - "```md\n[opt unu]()\n" - "[opt info](ticker)\n" - "[opt vsurf](ticker) \n" - "[opt oi](ticker) \n" - "[opt vol](ticker) \n" - "[opt overview](ticker) \n" - "[opt hist](ticker) \n" - "[opt grhist](ticker) \n" - "[opt chain](ticker) \n```" - ) + siatext = f"```md{cmds_text['sia']}```" + etftext = f"```md{cmds_text['etf']}```" + disctext = f"```md{cmds_text['disc']}```" + misctext = f"```md{cmds_text['misc']}```" + opttext = f"```md{cmds_text['opt']}```" tatext = ( - "```md\n[ta summary](ticker)\n" - "[ta view](ticker)\n" - "[ta recom](ticker)\n" - "[ta fib](ticker) \n```" - "```md\n[ta-vol obv](ticker) \n" - "[ta-vol ad](ticker) \n" - "[ta-mom cg](ticker) \n" - "[ta-mom fisher](ticker) \n" - "[ta-mom cci](ticker) \n" - "[ta ma](ticker) \n" - "[ta-trend aroon](ticker) \n" - "[ta-vol adosc](ticker) \n" - "[ta-mom macd](ticker) \n" - "[ta-vlt kc](ticker) \n" - "[ta-trend adx](ticker) \n" - "[ta-mom rsi](ticker) \n" - "[ta-mom stoch](ticker) \n" - "[ta-vlt bbands](ticker) \n" - "[ta-vlt donchian](ticker) \n```" - "```md\nšŸ‘† šŸ‘†\n```" - ) - ddtext = ( - "```md\n[dd est](ticker)\n" - "[dd sec](ticker)\n" - "[dd analyst](ticker)\n" - "[dd supplier](ticker)\n" - "[dd customer](ticker)\n" - "[dd arktrades](ticker)\n" - "[dd pt](ticker) \n```" - ) - dpstext = ( - "```md\n[dps hsi]() \n" - "[dps shorted](NUM)\n" - "[dps psi](ticker)\n" - "[dps spos](ticker)\n" - "[dps dpotc](ticker)\n" - "[dps pos]() \n" - "[dps sidtc]() \n" - "[dps ftd](ticker) \n```" - ) - scrtext = ( - "```md\n[scr presets_default]()\n" - "[scr presets_custom]()\n" - "[scr historical](SIGNAL) \n" - "[scr overview](PRESET) \n" - "[scr technical](PRESET) \n" - "[scr valuation](PRESET) \n" - "[scr financial](PRESET) \n" - "[scr ownership](PRESET) \n" - "[scr performance](PRESET) \n```" - ) - govtext = ( - "```md\n[gov histcont](ticker)\n" - "[gov lobbying](ticker) \n" - "[gov toplobbying]() \n" - "[gov lastcontracts]() \n" - "[gov contracts](ticker) \n" - "[gov qtrcontracts]() \n" - "[gov lasttrades]() \n" - "[gov gtrades](ticker) \n" - "[gov topbuys]() \n" - "[gov topsells]() \n```" - "\n` = Past Transaction Days`\n" - "` = Past Transaction Months`" - ) - econtext = ( - "```md\n[econ softs]()\n" - "[econ meats]()\n" - "[econ energy]()\n" - "[econ metals]()\n" - "[econ grains]()\n" - "[econ futures]()\n" - "[econ usbonds]()\n" - "[econ glbonds]()\n" - "[econ indices]()\n" - "[econ overview]()\n" - "[econ feargreed]()\n" - "[econ currencies]()\n" - "[econ valuation]() \n" - "[econ performance]() \n```" + f"```md{cmds_text['ta']}```" + f"```md{cmds_text['ta_candle']}```" + f"```md{cmds_text['ta_ext']}```" ) + ddtext = f"```md{cmds_text['dd']}```" + dpstext = f"```md{cmds_text['dps']}```" + scrtext = f"```md{cmds_text['scr']}```" + govtext = f"```md{cmds_text['gov']}```" f"{cmds_text['gov_ext']}" + econtext = f"```md{cmds_text['econ']}```" options = [disnake.SelectOption(label="Home", value="0", emoji="🟢")] embeds = [ disnake.Embed( diff --git a/bots/cmds/economy_cmds.py b/bots/cmds/economy_cmds.py index 1bfef52f4b8..bab1e09b6b6 100755 --- a/bots/cmds/economy_cmds.py +++ b/bots/cmds/economy_cmds.py @@ -137,13 +137,13 @@ class EconomyCommands(commands.Cog): async def repo( self, inter: disnake.AppCmdInter, - days: int = 100, + days: int = 50, ): """Displays Reverse Repo [Stocksera] Parameters ----------- - days: Number of days to display. Default: 100 + days: Number of days to display. Default: 50 """ await ShowView().discord(reverse_repo_command, inter, "econ repo", days) diff --git a/bots/cmds/options_cmds.py b/bots/cmds/options_cmds.py index 9a688ce06da..c4b5e059ff9 100644 --- a/bots/cmds/options_cmds.py +++ b/bots/cmds/options_cmds.py @@ -11,6 +11,7 @@ from bots.stocks.options.iv import iv_command from bots.stocks.options.oi import oi_command from bots.stocks.options.opt_chain import chain_command from bots.stocks.options.overview import overview_command +from bots.stocks.options.smile import smile_command from bots.stocks.options.unu import unu_command from bots.stocks.options.vol import vol_command from bots.stocks.options.vsurf import vsurf_command @@ -72,6 +73,28 @@ class SlashCommands(commands.Cog): oi_command, inter, "opt oi", ticker, expiry, min_sp, max_sp ) + @opt.sub_command(name="smile") + async def smile( + self, + inter: disnake.AppCmdInter, + ticker: str = commands.Param(autocomplete=ticker_autocomp), + expiry: str = commands.Param(autocomplete=expiry_autocomp), + min_sp: float = None, + max_sp: float = None, + ): + """Displays Options Volatility Smile [Yahoo Finance] + + Parameters + ---------- + ticker: Stock Ticker + expiry: Expiration Date + min_sp: Minimum Strike Price + max_sp: Maximum Strike Price + """ + await ShowView().discord( + smile_command, inter, "opt smile", ticker, expiry, min_sp, max_sp + ) + @opt.sub_command(name="info") async def iv( self, diff --git a/bots/common/commands_dict.py b/bots/common/commands_dict.py index 25819eebd85..634bbf9ae49 100644 --- a/bots/common/commands_dict.py +++ b/bots/common/commands_dict.py @@ -8,6 +8,7 @@ from bots.economy.currencies import currencies_command from bots.economy.energy import energy_command from bots.economy.feargreed import feargreed_command from bots.economy.futures import futures_command +from bots.economy.futures_coms import futures_coms_command from bots.economy.glbonds import glbonds_command from bots.economy.grains import grains_command from bots.economy.indices import indices_command @@ -15,9 +16,13 @@ from bots.economy.meats import meats_command from bots.economy.metals import metals_command from bots.economy.overview import overview_command from bots.economy.performance import performance_command +from bots.economy.reverse_repo import reverse_repo_command from bots.economy.softs import softs_command from bots.economy.usbonds import usbonds_command from bots.economy.valuation import valuation_command +from bots.etf.holdings import holdings_command +from bots.etf.tops import etfs_disc_command +from bots.etf.whatetf import by_ticker_command from bots.stocks.candle import candle_command from bots.stocks.dark_pool_shorts.dpotc import dpotc_command from bots.stocks.dark_pool_shorts.ftd import ftd_command @@ -27,9 +32,14 @@ from bots.stocks.dark_pool_shorts.psi import psi_command from bots.stocks.dark_pool_shorts.shorted import shorted_command from bots.stocks.dark_pool_shorts.sidtc import sidtc_command from bots.stocks.dark_pool_shorts.spos import spos_command +from bots.stocks.disc.active import active_command from bots.stocks.disc.ford import ford_command +from bots.stocks.disc.topgainers import gainers_command +from bots.stocks.disc.toplosers import losers_command +from bots.stocks.disc.ugs import ugs_command from bots.stocks.due_diligence.analyst import analyst_command from bots.stocks.due_diligence.arktrades import arktrades_command +from bots.stocks.due_diligence.borrowed import borrowed_command from bots.stocks.due_diligence.customer import customer_command from bots.stocks.due_diligence.est import est_command from bots.stocks.due_diligence.pt import pt_command @@ -52,6 +62,7 @@ from bots.stocks.options.iv import iv_command from bots.stocks.options.oi import oi_command from bots.stocks.options.opt_chain import chain_command from bots.stocks.options.overview import overview_command as overview_opt_command +from bots.stocks.options.smile import smile_command from bots.stocks.options.unu import unu_command from bots.stocks.options.vol import vol_command from bots.stocks.options.vsurf import vsurf_command @@ -88,11 +99,11 @@ from bots.stocks.technical_analysis.stoch import stoch_command from bots.stocks.technical_analysis.summary import summary_command from bots.stocks.technical_analysis.view import view_command -re_date = re.compile(r"/^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$/") re_int = re.compile(r"^[1-9]\d*$") re_float = re.compile(r"^[+-]?([0-9]+([.][0-9]*)?|[.][0-9]+)$") re_name = re.compile(r"(?s).*") re_window = re.compile(r"(?s).*") +re_date = re_name gov_type = ["congress", "senate", "house"] @@ -352,7 +363,7 @@ def get_tickers() -> List[str]: return df.tolist() -tickers = get_tickers() +tickers = re_name commands = { "dd_analyst": { "function": analyst_command, @@ -369,6 +380,10 @@ commands = { "function": supplier_command, "required": {"ticker": tickers}, }, + "dd_borrowed": { + "function": borrowed_command, + "required": {"ticker": tickers}, + }, "dd_customer": { "function": customer_command, "required": {"ticker": tickers}, @@ -413,7 +428,7 @@ commands = { "function": indices_command, }, "econ_futures": { - "function": futures_command, + "function": futures_coms_command, }, "econ_usbonds": { "function": usbonds_command, @@ -436,6 +451,10 @@ commands = { "econ_softs": { "function": softs_command, }, + "econ_repo": { + "function": reverse_repo_command, + "required": {"days": re_int}, + }, "econ_currencies": { "function": currencies_command, }, @@ -447,6 +466,23 @@ commands = { "function": performance_command, "required": {"economy_group": econ_group}, }, + "etf_tops": { + "function": etfs_disc_command, + "required": {"sort": ["gainers", "decliners", "active"]}, + }, + "etf_holdings": { + "function": holdings_command, + "required": {"etf": re_name}, + "optional": {"num": re_int}, + }, + "etf_byticker": { + "function": by_ticker_command, + "required": {"ticker": re_name, "sort": ["fund_percent", "mkt_value"]}, + "optional": {"num": re_int}, + }, + "futures": { + "function": futures_command, + }, "gov_lasttrades": { "function": lasttrades_command, "required": {"gov_type": gov_type}, @@ -527,12 +563,29 @@ commands = { "function": iv_command, "required": {"ticker": tickers}, }, + "opt_smile": { + "function": smile_command, + "required": {"ticker": tickers, "expiry": re_date}, + "optional": {"min_sp": re_float, "max_sp": re_float}, + }, + "opt_unu": { + "function": unu_command, + }, "q": {"function": quote_command, "required": {"ticker": tickers}}, "disc_ford": { "function": ford_command, }, - "opt_unu": { - "function": unu_command, + "disc_active": { + "function": active_command, + }, + "disc_gainers": { + "function": gainers_command, + }, + "disc_losers": { + "function": losers_command, + }, + "disc_ugs": { + "function": ugs_command, }, "ins_last": { "function": lins_command, @@ -541,8 +594,8 @@ commands = { }, "candle": { "function": candle_command, - "required": {"ticker": tickers, "interval": opt_intervals}, - "optional": {"past_days": re_int, "start": re_date, "end": re_date}, + "required": {"ticker": tickers, "interval": opt_intervals, "past_days": re_int}, + "optional": {"start": re_date, "end": re_date}, }, "opt_overview": { "function": overview_opt_command, @@ -560,7 +613,7 @@ commands = { "function": vsurf_command, "required": {"ticker": tickers, "z": options_vsurf_choices.values()}, }, - "opt_hist": { + "opt_grhist": { "function": hist_command, "required": { "ticker": tickers, @@ -621,7 +674,7 @@ commands = { "optional": {"limit": re_int, "ascend": [True, False]}, }, # TODO Add ta candle args - "ta-ma": { + "ta_ma": { "function": ma_command, "required": {"ticker": tickers, "interval": opt_intervals, "ma_mode": ma_mode}, "optional": { @@ -636,12 +689,15 @@ commands = { }, "ta_cci": { "function": cci_command, - "required": {"ticker": tickers}, + "required": {"ticker": tickers, "interval": opt_intervals}, "optional": { + "past_days": re_int, "length": re_int, "scalar": re_float, "start": re_date, "end": re_date, + "extended_hours": [True, False], + "heikin_candles": [True, False], }, }, "ta_macd": { @@ -674,19 +730,29 @@ commands = { }, "ta_stoch": { "function": stoch_command, - "required": {"ticker": tickers}, + "required": {"ticker": tickers, "interval": opt_intervals}, "optional": { + "past_days": re_int, "fast_k": re_int, "slow_k": re_int, "slow_d": re_int, "start": re_date, "end": re_date, + "extended_hours": [True, False], + "heikin_candles": [True, False], }, }, "ta_fisher": { "function": fisher_command, - "required": {"ticker": tickers}, - "optional": {"length": re_int, "start": re_date, "end": re_date}, + "required": {"ticker": tickers, "interval": opt_intervals}, + "optional": { + "past_days": re_int, + "length": re_int, + "start": re_date, + "end": re_date, + "extended_hours": [True, False], + "heikin_candles": [True, False], + }, }, "ta_cg": { "function": fisher_command, @@ -759,8 +825,15 @@ commands = { }, "ta_ad": { "function": ad_command, - "required": {"ticker": tickers}, - "optional": {"is_open": ["True", "False"], "start": re_date, "end": re_date}, + "required": {"ticker": tickers, "interval": opt_intervals}, + "optional": { + "past_days": re_int, + "is_open": [True, False], + "start": re_date, + "end": re_date, + "extended_hours": [True, False], + "heikin_candles": [True, False], + }, }, "ta_adosc": { "function": adosc_command, @@ -789,8 +862,14 @@ commands = { }, "ta_fib": { "function": fib_command, - "required": {"ticker": tickers}, - "optional": {"start": re_date, "end": re_date}, + "required": {"ticker": tickers, "interval": opt_intervals}, + "optional": { + "past_days": re_int, + "start": re_date, + "end": re_date, + "extended_hours": [True, False], + "heikin_candles": [True, False], + }, }, "ta_view": {"function": view_command, "required": {"ticker": tickers}}, "ta_summary": {"function": summary_command, "required": {"ticker": tickers}}, diff --git a/bots/common/help_text.py b/bots/common/help_text.py new file mode 100644 index 00000000000..972b6749977 --- /dev/null +++ b/bots/common/help_text.py @@ -0,0 +1,124 @@ +cmds_text = { + "sia": ( + "\n[sia metrics](ticker) \n" + "[sia cps]() \n" + "[sia cpic]() \n" + ), + "etf": ( + "\n[etfs disc-tops]() \n" + "[etfs holdings by-etf](etf) \n" + "[etfs holdings by-ticker](ticker) \n" + ), + "disc": ( + "\n[disc fidelity]()\n" "[disc ugs]() \n" "[disc tops]() \n" + ), + "misc": ( + "\n[futures]()\n" + "[quote](ticker)\n" + "[support]() *Mods Only*\n" + "[ins-last](ticker) \n" + "[btc]() \n" + "[eth]() \n" + "[sol]() \n" + "[candle](ticker) \n" + ), + "opt": ( + "\n[opt unu]()\n" + "[opt info](ticker)\n" + "[opt vsurf](ticker) \n" + "[opt oi](ticker) \n" + "[opt vol](ticker) \n" + "[opt smile](ticker) \n" + "[opt overview](ticker) \n" + "[opt hist](ticker) \n" + "[opt grhist](ticker) \n" + "[opt chain](ticker) \n" + ), + "ta": ( + "\n[ta summary](ticker)\n" + "[ta view](ticker)\n" + "[ta recom](ticker)\n" + "[ta-mom cg](ticker) \n" + "[ta-vlt donchian](ticker) \n" + ), + "ta_candle": ( + "\n[ta-vol obv](ticker) \n" + "[ta fib](ticker) \n" + "[ta-vol ad](ticker) \n" + "[ta-mom fisher](ticker) \n" + "[ta-mom cci](ticker) \n" + "[ta ma](ticker) \n" + "[ta-trend aroon](ticker) \n" + "[ta-vol adosc](ticker) \n" + "[ta-mom macd](ticker) \n" + "[ta-vlt kc](ticker) \n" + "[ta-trend adx](ticker) \n" + "[ta-mom rsi](ticker) \n" + "[ta-mom stoch](ticker) \n" + "[ta-vlt bbands](ticker) \n" + ), + "ta_ext": ("\nšŸ‘† šŸ‘†\n"), + "dd": ( + "\n[dd est](ticker)\n" + "[dd sec](ticker)\n" + "[dd borrowed](ticker)\n" + "[dd analyst](ticker)\n" + "[dd supplier](ticker)\n" + "[dd customer](ticker)\n" + "[dd arktrades](ticker)\n" + "[dd pt](ticker) \n" + ), + "dps": ( + "\n[dps hsi]() \n" + "[dps shorted](NUM)\n" + "[dps psi](ticker)\n" + "[dps spos](ticker)\n" + "[dps dpotc](ticker)\n" + "[dps pos]() \n" + "[dps sidtc]() \n" + "[dps ftd](ticker) \n" + ), + "scr": ( + "\n[scr presets_default]()\n" + "[scr presets_custom]()\n" + "[scr historical](SIGNAL) \n" + "[scr overview](PRESET) \n" + "[scr technical](PRESET) \n" + "[scr valuation](PRESET) \n" + "[scr financial](PRESET) \n" + "[scr ownership](PRESET) \n" + "[scr performance](PRESET) \n" + ), + "gov": ( + "\n[gov histcont](ticker)\n" + "[gov lobbying](ticker) \n" + "[gov toplobbying]() \n" + "[gov lastcontracts]() \n" + "[gov contracts](ticker) \n" + "[gov qtrcontracts]() \n" + "[gov lasttrades]() \n" + "[gov gtrades](ticker) \n" + "[gov topbuys]() \n" + "[gov topsells]() \n" + ), + "gov_ext": ( + "\n` = Past Transaction Days`\n` = Past Transaction Months`\n" + ), + "econ": ( + "\n[econ softs]()\n" + "[econ meats]()\n" + "[econ energy]()\n" + "[econ metals]()\n" + "[econ grains]()\n" + "[econ futures]()\n" + "[econ usbonds]()\n" + "[econ glbonds]()\n" + "[econ indices]()\n" + "[econ repo](DAYS)\n" + "[econ overview]()\n" + "[econ feargreed]()\n" + "[econ currencies]()\n" + "[econ valuation]() \n" + "[econ performance]() \n" + ), +} diff --git a/bots/config_discordbot.py b/bots/config_discordbot.py index 73ecae748e4..9bdfe63946a 100755 --- a/bots/config_discordbot.py +++ b/bots/config_discordbot.py @@ -8,9 +8,9 @@ import pyimgur from dotenv import load_dotenv # Path to bots -bots_path = Path(__file__).parent.absolute() +bots_path = Path(__file__).parent.resolve() -env_files = [f for f in bots_path.iterdir() if f.as_posix().endswith(".env")] +env_files = [f for f in bots_path.iterdir() if f.__str__().endswith(".env")] if env_files: load_dotenv(env_files[0]) @@ -41,21 +41,25 @@ SLASH_TESTING_SERVERS: Optional[ COMMAND_PREFIX = "!" DATE_FORMAT = "%Y-%m-%d" COLOR = disnake.Color.from_rgb(255, 0, 0) -INTERACTIVE = False -INTERACTIVE_DIR = bots_path / "interactive/" + +# Interactive Chart Settings +INTERACTIVE = bool(os.getenv("GT_INTERACTIVE")) or False +INTERACTIVE_DIR = bots_path.joinpath("interactive/") INTERACTIVE_URL = "" -IMG_DIR = bots_path / "interactive/images/" + +# Image Settings +IMG_HOST_ACTIVE = bool(os.getenv("GT_IMG_HOST_ACTIVE")) or True +IMG_DIR = bots_path.joinpath("interactive/images/") IMAGES_URL = "" # Ex. "http://your-site.com/images/" # IMG_BG = bots_path.joinpath("files/bg.png") # Light BG IMG_BG = bots_path.joinpath("files/bg-dark.png") # Dark BG -MENU_TIMEOUT = 30 -DEBUG = False +DEBUG = bool(os.getenv("GT_DEBUG")) or False GST_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), "..")) -gst_imgur = pyimgur.Imgur(IMGUR_CLIENT_ID) if IMGUR_CLIENT_ID != "REPLACE_ME" else None +gst_imgur = pyimgur.Imgur(IMGUR_CLIENT_ID) AUTHOR_NAME = "Gamestonk Terminal" AUTHOR_URL = "https://github.com/GamestonkTerminal/GamestonkTerminal" diff --git a/bots/economy/energy.py b/bots/economy/energy.py index 5c9d03f2a80..785922bac3b 100755 --- a/bots/economy/energy.py +++ b/bots/economy/energy.py @@ -52,7 +52,7 @@ def energy_command(): ) font_color = ["white"] * 3 + [ - ["#e4003a" if boolv else "#00ACFF" for boolv in df["Yld Chg"].str.contains("-")] + ["#e4003a" if boolv else "#00ACFF" for boolv in df["Change"].str.contains("-")] ] fig = imps.plot_df( diff --git a/bots/economy/feargreed.py b/bots/economy/feargreed.py index ce026a4f076..fae4a7321d0 100644 --- a/bots/economy/feargreed.py +++ b/bots/economy/feargreed.py @@ -1,12 +1,14 @@ -import datetime +import io import logging -import os import matplotlib.pyplot as plt from bots import config_discordbot as cfg +from bots.helpers import image_border +from gamestonk_terminal.config_plot import PLOT_DPI from gamestonk_terminal.decorators import log_start_end -from gamestonk_terminal.economy import cnn_model, cnn_view +from gamestonk_terminal.economy import cnn_model +from gamestonk_terminal.helper_funcs import plot_autoscale logger = logging.getLogger(__name__) @@ -26,36 +28,28 @@ def feargreed_command(indicator=""): raise Exception( f"Select a valid indicator from {', '.join(possible_indicators)}" # nosec ) + # Output data - # Retrieve data - fig = plt.figure(figsize=[1, 1], dpi=10) + fig, ax = plt.subplots(figsize=plot_autoscale(), dpi=PLOT_DPI) - report, _ = cnn_model.get_feargreed_report(indicator, fig) - cnn_view.fear_and_greed_index(indicator=indicator, export="png") + report, im = cnn_model.get_feargreed_report(indicator, fig) + ax.axes.xaxis.set_visible(False) + ax.axes.yaxis.set_visible(False) + + if indicator: + ax.imshow(im) + + imagefile = "feargreed.png" + dataBytesIO = io.BytesIO() + + plt.savefig(dataBytesIO) plt.close("all") - # Output data - now = datetime.datetime.now() - image_path = os.path.join( - cfg.GST_PATH, - "exports", - "economy", - f"feargreed_{now.strftime('%Y%m%d_%H%M%S')}.png", - ) - - i = 0 - while not os.path.exists(image_path) and i < 10: - now -= datetime.timedelta(seconds=1) - image_path = os.path.join( - cfg.GST_PATH, - "exports", - "economy", - f"feargreed_{now.strftime('%Y%m%d_%H%M%S')}.png", - ) - i += 1 + dataBytesIO.seek(0) + imagefile = image_border(imagefile, base64=dataBytesIO) return { "title": "Economy: [CNN] Fear Geed Index", - "imagefile": image_path, + "imagefile": imagefile, "description": report, } diff --git a/bots/economy/futures.py b/bots/economy/futures.py index a4385d2eff3..6be9947a414 100755 --- a/bots/economy/futures.py +++ b/bots/economy/futures.py @@ -1,5 +1,4 @@ import logging -import os import disnake import pandas as pd @@ -96,16 +95,11 @@ def futures_command(): imagefile = "econ-futures.png" imagefile = imps.save_image(imagefile, fig) - if imps.IMAGES_URL or imps.IMGUR_CLIENT_ID != "REPLACE_ME": - image_link = imps.IMAGES_URL + imagefile + if imps.IMAGES_URL or not imps.IMG_HOST_ACTIVE: + image_link = imps.multi_image(imagefile) images_list.append(imagefile) else: - imagefile_save = imps.IMG_DIR / imagefile - uploaded_image = imps.gst_imgur.upload_image( - imagefile_save, title="something" - ) - image_link = uploaded_image.link - os.remove(imagefile_save) + image_link = imps.multi_image(imagefile) embeds_img.append( f"{image_link}", diff --git a/bots/economy/performance.py b/bots/economy/performance.py index 67024b0ff8d..fd51ea4b9b0 100755 --- a/bots/economy/performance.py +++ b/bots/economy/performance.py @@ -1,5 +1,4 @@ import logging -import os import disnake import pandas as pd @@ -125,16 +124,11 @@ def performance_command(economy_group="sector"): imagefile = "econ_performance.png" imagefile = imps.save_image(imagefile, fig) - if imps.IMAGES_URL or imps.IMGUR_CLIENT_ID != "REPLACE_ME": - image_link = imps.IMAGES_URL + imagefile + if imps.IMAGES_URL or not imps.IMG_HOST_ACTIVE: + image_link = imps.multi_image(imagefile) images_list.append(imagefile) else: - imagefile_save = imps.IMG_DIR / imagefile - uploaded_image = imps.gst_imgur.upload_image( - imagefile_save, title="something" - ) - image_link = uploaded_image.link - os.remove(imagefile_save) + image_link = imps.multi_image(imagefile) embeds_img.append( f"{image_link}", diff --git a/bots/economy/reverse_repo.py b/bots/economy/reverse_repo.py index 4d95df4ca1e..a942e51c861 100755 --- a/bots/economy/reverse_repo.py +++ b/bots/economy/reverse_repo.py @@ -1,5 +1,4 @@ import logging -import os import disnake import pandas as pd @@ -12,7 +11,7 @@ logger = logging.getLogger(__name__) @log_start_end(log=logger) -def reverse_repo_command(days: int = 100): +def reverse_repo_command(days: int = 50): """Displays Reverse Repo [Stocksera.com]""" # Debug user input @@ -40,6 +39,9 @@ def reverse_repo_command(days: int = 100): for col, value in formats.items(): df[col] = df[col].map(lambda x: value.format(x)) # pylint: disable=W0640 + df = df.drop(columns="Moving Avg") + df = df.sort_values(by="Date", ascending=False) + font_color = ["white"] * 4 + [ [ "#e4003a" if boolv else "#00ACFF" @@ -47,8 +49,6 @@ def reverse_repo_command(days: int = 100): ] # type: ignore ] - df = df.drop(columns="Moving Avg") - df = df.sort_values(by="Date", ascending=False) df.set_index("Date", inplace=True) df.columns = df.columns.str.capitalize() @@ -88,16 +88,11 @@ def reverse_repo_command(days: int = 100): imagefile = "dd_r_repo.png" imagefile = imps.save_image(imagefile, fig) - if imps.IMAGES_URL or imps.IMGUR_CLIENT_ID != "REPLACE_ME": - image_link = imps.IMAGES_URL + imagefile + if imps.IMAGES_URL or not imps.IMG_HOST_ACTIVE: + image_link = imps.multi_image(imagefile) images_list.append(imagefile) else: - imagefile_save = imps.IMG_DIR / imagefile - uploaded_image = imps.gst_imgur.upload_image( - imagefile_save, title="something" - ) - image_link = uploaded_image.link - os.remove(imagefile_save) + image_link = imps.multi_image(imagefile) embeds_img.append( f"{image_link}", diff --git a/bots/economy/valuation.py b/bots/economy/valuation.py index 6e3e8bfe3a4..4c83c5298bd 100755 --- a/bots/economy/valuation.py +++ b/bots/economy/valuation.py @@ -1,5 +1,4 @@ import logging -import os import disnake import pandas as pd @@ -92,16 +91,11 @@ def valuation_command(economy_group="sector"): imagefile = "econ_valuation.png" imagefile = imps.save_image(imagefile, fig) - if imps.IMAGES_URL or imps.IMGUR_CLIENT_ID != "REPLACE_ME": - image_link = imps.IMAGES_URL + imagefile + if imps.IMAGES_URL or not imps.IMG_HOST_ACTIVE: + image_link = imps.multi_image(imagefile) images_list.append(imagefile) else: - imagefile_save = imps.IMG_DIR / imagefile - uploaded_image = imps.gst_imgur.upload_image( - imagefile_save, title="something" - ) - image_link = uploaded_image.link - os.remove(imagefile_save) + image_link = imps.multi_image(imagefile) embeds_img.append( f"{image_link}", diff --git a/bots/etf/holdings.py b/bots/etf/holdings.py index d1224b21651..c8661f32800 100755 --- a/bots/etf/holdings.py +++ b/bots/etf/holdings.py @@ -1,5 +1,4 @@ import logging -import os import disnake @@ -48,16 +47,11 @@ def holdings_command(etf="", num: int = 15): imagefile = "etf-holdings.png" imagefile = imps.save_image(imagefile, fig) - if imps.IMAGES_URL or imps.IMGUR_CLIENT_ID != "REPLACE_ME": - image_link = imps.IMAGES_URL + imagefile + if imps.IMAGES_URL or not imps.IMG_HOST_ACTIVE: + image_link = imps.multi_image(imagefile) images_list.append(imagefile) else: - imagefile_save = imps.IMG_DIR / imagefile - uploaded_image = imps.gst_imgur.upload_image( - imagefile_save, title="something" - ) - image_link = uploaded_image.link - os.remove(imagefile_save) + image_link = imps.multi_image(imagefile) embeds_img.append( f"{image_link}", diff --git a/bots/etf/tops.py b/bots/etf/tops.py index da085399049..cd9d1e8c9b6 100755 --- a/bots/etf/tops.py +++ b/bots/etf/tops.py @@ -1,5 +1,4 @@ import logging -import os import disnake import pandas as pd @@ -12,7 +11,7 @@ logger = logging.getLogger(__name__) @log_start_end(log=logger) -def etfs_disc_command(sort=""): +def etfs_disc_command(sort="gainers"): """Displays ETF's Top Gainers/Decliners, Most Active [Wall Street Journal]""" # Debug @@ -69,16 +68,11 @@ def etfs_disc_command(sort=""): imagefile = "disc-etfs.png" imagefile = imps.save_image(imagefile, fig) - if imps.IMAGES_URL or imps.IMGUR_CLIENT_ID != "REPLACE_ME": - image_link = imps.IMAGES_URL + imagefile + if imps.IMAGES_URL or not imps.IMG_HOST_ACTIVE: + image_link = imps.multi_image(imagefile) images_list.append(imagefile) else: - imagefile_save = imps.IMG_DIR / imagefile - uploaded_image = imps.gst_imgur.upload_image( - imagefile_save, title="something" - ) - image_link = uploaded_image.link - os.remove(imagefile_save) + image_link = imps.multi_image(imagefile) embeds_img.append( f"{image_link}", diff --git a/bots/etf/whatetf.py b/bots/etf/whatetf.py index 704da0e1b68..a28f210bbc1 100755 --- a/bots/etf/whatetf.py +++ b/bots/etf/whatetf.py @@ -1,5 +1,4 @@ import logging -import os import time import bs4 @@ -104,16 +103,11 @@ def by_ticker_command(ticker="", sort="fund_percent", num: int = 15): imagefile = "etf-byticker.png" imagefile = imps.save_image(imagefile, fig) - if imps.IMAGES_URL or imps.IMGUR_CLIENT_ID != "REPLACE_ME": - image_link = imps.IMAGES_URL + imagefile + if imps.IMAGES_URL or not imps.IMG_HOST_ACTIVE: + image_link = imps.multi_image(imagefile) images_list.append(imagefile) else: - imagefile_save = imps.IMG_DIR / imagefile - uploaded_image = imps.gst_imgur.upload_image( - imagefile_save, title="something" - ) - image_link = uploaded_image.link - os.remove(imagefile_save) + image_link = imps.multi_image(imagefile) embeds_img.append( f"{image_link}", diff --git a/bots/helpers.py b/bots/helpers.py index 6be0d5067f8..357b1d166b9 100755 --- a/bots/helpers.py +++ b/bots/helpers.py @@ -365,7 +365,7 @@ def inter_chart(fig: plotly.graph_objects, filename: str, **data) -> str: """ # Write out HTML file - with open(f"{imps.INTERACTIVE_DIR / filename}", "w") as f: + with open(f"{imps.INTERACTIVE_DIR.joinpath(filename)}", "w") as f: f.write(html_str) plt_link = f"[Interactive]({imps.INTERACTIVE_URL}/{filename})" return plt_link @@ -387,11 +387,12 @@ def save_image(filename: str, fig: plotly.graph_objects) -> str: filename with UUID added to use for bot processing """ imagefile = f"{filename.replace('.png', '')}_{uuid_get()}.png" - filesave = imps.IMG_DIR / imagefile + filesave = imps.IMG_DIR.joinpath(imagefile) fig.write_image(filesave) image = Image.open(filesave) image = autocrop_image(image, 0) image.save(filesave, "PNG", quality=100) + image.close() return imagefile @@ -412,7 +413,7 @@ def image_border(filename: str, **kwargs) -> str: filename with UUID added to use for bot processing """ imagefile = f"{filename.replace('.png', '')}_{uuid_get()}.png" - filesave = imps.IMG_DIR / imagefile + filesave = imps.IMG_DIR.joinpath(imagefile) if "fig" in kwargs: fig = kwargs["fig"] fig.write_image(filesave) @@ -434,13 +435,40 @@ def image_border(filename: str, **kwargs) -> str: 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)) + img.close() im_bg.save(filesave, "PNG", quality=100) + im_bg.close() image = Image.open(filesave) image = autocrop_image(image, 0) image.save(filesave, "PNG", quality=100) + image.close() return imagefile +def multi_image(filename: str, **kwargs) -> str: + """Uploads to an image host and returns image url. + + Parameters + ---------- + filename : str + Image filename + + Returns + ------- + str + Image url + """ + if imps.IMAGES_URL or not imps.IMG_HOST_ACTIVE: + image_link = imps.IMAGES_URL + filename + else: + imagefile_save = imps.IMG_DIR.joinpath(filename) + uploaded_image = imps.gst_imgur.upload_image(imagefile_save, title="something") + image_link = uploaded_image.link + os.remove(imagefile_save) + + return image_link + + class ShowView: async def run_discord(self, func, inter, *args, **kwargs): data = func(*args, **kwargs) @@ -462,11 +490,12 @@ class ShowView: ) if "imagefile" in data: filename = data["imagefile"] - imagefile = (imps.IMG_DIR / filename).as_posix() + imagefile = imps.IMG_DIR.joinpath(filename) image = disnake.File(imagefile, filename=filename) embed.set_image(url=f"attachment://{filename}") - os.remove(imagefile) await inter.send(embed=embed, file=image) + image.close() + os.remove(imagefile) else: await inter.send(embed=embed) @@ -494,12 +523,12 @@ class ShowView: def groupme(self, func, group_id, name, *args, **kwargs): data = func(*args, **kwargs) if "imagefile" in data: - imagefile = (imps.IMG_DIR / data["imagefile"]).as_posix() + imagefile = imps.IMG_DIR.joinpath(data["imagefile"]) send_image(imagefile, group_id, data.get("description", "")) elif "embeds_img" in data: imagefiles = data["images_list"] for img in imagefiles: - imagefile = (imps.IMG_DIR / img).as_posix() + imagefile = imps.IMG_DIR.joinpath(img) send_image(imagefile, group_id, data.get("description", "")) elif "description" in data: title = data.get("title", "") @@ -523,9 +552,10 @@ class ShowView: .replace(".html)", ".html\n\n") ) message = f"{title}\n{description}" - imagefile = (imps.IMG_DIR / data["imagefile"]).as_posix() + imagefile = imps.IMG_DIR.joinpath(data["imagefile"]).__str__() client.files_upload( file=imagefile, + filename=data["imagefile"], initial_comment=message, channels=channel_id, user_id=user_id, @@ -540,7 +570,7 @@ class ShowView: title = data["title"] if "titles" not in data else data["titles"][0] N = 0 for img in data["images_list"]: - imagefile = (imps.IMG_DIR / img).as_posix() + imagefile = imps.IMG_DIR.joinpath(img).__str__() if N == 0: message = f"{title}\n{description}" payload = { @@ -550,10 +580,11 @@ class ShowView: } client.chat_postMessage(**payload) title = "" - if N < len(data["titles"]) and N != 0: - title = data["titles"][N] + if N < len(title) and N != 0: + title = data["titles"][N] if "titles" in data else "" client.files_upload( file=imagefile, + filename=img, initial_comment=title, channels=channel_id, user_id=user_id, @@ -574,7 +605,7 @@ class ShowView: def telegram(self, func, message, bot, cmd, *args, **kwargs): data = func(*args, **kwargs) if "imagefile" in data: - imagefile = (imps.IMG_DIR / data["imagefile"]).as_posix() + imagefile = imps.IMG_DIR.joinpath(data["imagefile"]) title = data["title"] description = ( data.get("description", "") @@ -591,7 +622,7 @@ class ShowView: res_title = data["title"] if "titles" not in data else data["titles"][0] N = 0 for img in data["images_list"]: - imagefile = (imps.IMG_DIR / img).as_posix() + imagefile = imps.IMG_DIR.joinpath(img) if N == 0: description = ( data.get("description", "") @@ -599,8 +630,8 @@ class ShowView: .replace(".html)", ".html\n\n") ) res_title = f"{res_title}\n{description}" - if N < len(data["titles"]) and N != 0: - res_title = data["titles"][N] + if N < len(res_title) and N != 0: + res_title = data["titles"][N] if "titles" in data else "" with open(imagefile, "rb") as image: bot.reply_to(message, res_title) bot.send_photo(message.chat.id, image) diff --git a/bots/load_candle.py b/bots/load_candle.py index 4acca9abd10..e705ad98954 100755 --- a/bots/load_candle.py +++ b/bots/load_candle.py @@ -224,14 +224,8 @@ def stock_data( df_stock = df_stock.set_index( pd.to_datetime(df_stock["date"], unit="ms", utc=True) ).drop("date", axis=1) - df_stock["date_id"] = ( - df_stock.index.date - df_stock.index.date.min() - ).astype("timedelta64[D]") - df_stock["date_id"] = df_stock["date_id"].dt.days + 1 - - df_stock["OC_High"] = df_stock[["Open", "Close"]].max(axis=1) - df_stock["OC_Low"] = df_stock[["Open", "Close"]].min(axis=1) + df_stock["Adj Close"] = df_stock["Close"].copy() # For Technical Analysis else: d_granularity = { "1m": past_days, @@ -423,7 +417,9 @@ def candle_fig( for article in articles: dt_at = article["publishedAt"].replace("T", " ").replace("Z", "-05:00") - df_date.append(f"{datetime.strptime(dt_at, '%Y-%m-%d %H:%M:%S%z')}") + df_date.append( + f"{datetime.strptime(dt_at, '%Y-%m-%d %H:%M:%S%z').astimezone(est_tz)}" + ) df_title.append(article["title"]) grab_price = df_stock.iloc[ df_stock.index.get_loc(dt_at, method="nearest") diff --git a/bots/run_discordbot.py b/bots/run_discordbot.py index 7f357217457..0f1272b44c1 100755 --- a/bots/run_discordbot.py +++ b/bots/run_discordbot.py @@ -13,7 +13,7 @@ import disnake from disnake.ext import commands from fastapi import FastAPI, Request -from bots import config_discordbot as cfg +import config_discordbot as cfg from bots.groupme.run_groupme import handle_groupme from gamestonk_terminal.decorators import log_start_end from gamestonk_terminal.loggers import setup_logging diff --git a/bots/stocks/dark_pool_shorts/dpotc.py b/bots/stocks/dark_pool_shorts/dpotc.py index b65fb25573b..8886dd46c85 100644 --- a/bots/stocks/dark_pool_shorts/dpotc.py +++ b/bots/stocks/dark_pool_shorts/dpotc.py @@ -147,8 +147,6 @@ def dpotc_command(ticker: str = ""): ) if imps.PLT_WATERMARK: fig.add_layout_image(imps.PLT_WATERMARK) - fig.update_xaxes(showspikes=True, spikesnap="cursor", spikemode="across") - fig.update_yaxes(showspikes=True, spikethickness=2) fig.update_layout( margin=dict(l=20, r=0, t=10, b=20), template=imps.PLT_CANDLE_STYLE_TEMPLATE, @@ -187,8 +185,8 @@ def dpotc_command(ticker: str = ""): bargroupgap=0, dragmode="pan", hovermode="x unified", - spikedistance=1000, - hoverdistance=100, + spikedistance=1, + hoverdistance=1, ) imagefile = "dps_dpotc.png" diff --git a/bots/stocks/dark_pool_shorts/pos.py b/bots/stocks/dark_pool_shorts/pos.py index 8af12ce4c08..f5afd1a5cd9 100644 --- a/bots/stocks/dark_pool_shorts/pos.py +++ b/bots/stocks/dark_pool_shorts/pos.py @@ -1,10 +1,10 @@ import logging -import os import disnake from bots import imps from gamestonk_terminal.decorators import log_start_end +from gamestonk_terminal.helper_funcs import lambda_long_number_format from gamestonk_terminal.stocks.dark_pool_shorts import stockgrid_model logger = logging.getLogger(__name__) @@ -41,33 +41,36 @@ def pos_command(sort="dpp_dollar", ascending: bool = False, num: int = 10): # Output data title = "Stocks: [Stockgrid] Dark Pool Short Position" - + df = df.applymap(lambda x: lambda_long_number_format(x, 2)) df = df.drop(columns=["Date"]) - df["Net Short Volume $"] = df["Net Short Volume $"] / 1_000_000 - df["Short Volume"] = df["Short Volume"] / 1_000_000 - df["Net Short Volume"] = df["Net Short Volume"] / 1_000_000 - df["Short Volume %"] = df["Short Volume %"] * 100 - df["Dark Pools Position $"] = df["Dark Pools Position $"] / (1_000_000_000) - df["Dark Pools Position"] = df["Dark Pools Position"] / 1_000_000 - df.columns = [ - "Ticker", - "Short Vol.", - "Short Vol. %", - "Net Short Vol.", - "Net Short Vol. ($)", - "DP Position", - "DP Position ($)", - ] formats = { - "Short Vol.": "{:.2f}M", - "Short Vol. %": "{:.2f}%", - "Net Short Vol.": "{:.2f}M", - "Net Short Vol. ($)": "${:.2f}M", - "DP Position": "{:.2f}M", - "DP Position ($)": "${:.2f}B", + "Short Volume %": "{}%", + "Net Short Volume $": "${}", + "Dark Pools Position $": "${}", } for col, f in formats.items(): df[col] = df[col].map(lambda x: f.format(x)) # pylint: disable=W0640 + + df["Short Volume"] = df.apply( + lambda x: f"{x['Short Volume']} ({x['Short Volume %']})", axis=1 + ) + df["Net Short Volume"] = df.apply( + lambda x: f"{x['Net Short Volume']:>9} ({x['Net Short Volume $']:>9})", + axis=1, + ) + df["Dark Pools Position"] = df.apply( + lambda x: f"{x['Dark Pools Position']:>9} ({x['Dark Pools Position $']:>9})", + axis=1, + ) + df = df.drop( + columns=["Short Volume %", "Net Short Volume $", "Dark Pools Position $"] + ) + df.columns = [ + "Ticker", + "Short Vol.", + "Net Short Vol.", + "DP Position", + ] df.set_index("Ticker", inplace=True) dindex = len(df.index) if dindex > 15: @@ -80,28 +83,23 @@ def pos_command(sort="dpp_dollar", ascending: bool = False, num: int = 10): df_pg.append(df_pg) fig = imps.plot_df( df_pg, - fig_size=(900, (40 * dindex)), - col_width=[2, 3, 4, 3.5, 5, 4, 5], + fig_size=(720, (40 * dindex)), + col_width=[2, 4, 4, 4], tbl_header=imps.PLT_TBL_HEADER, tbl_cells=imps.PLT_TBL_CELLS, font=imps.PLT_TBL_FONT, row_fill_color=imps.PLT_TBL_ROW_COLORS, paper_bgcolor="rgba(0, 0, 0, 0)", ) - fig.update_traces(cells=(dict(align=["center", "left"]))) + fig.update_traces(cells=(dict(align=["center", "right"]))) imagefile = "dps-pos.png" imagefile = imps.save_image(imagefile, fig) - if imps.IMAGES_URL or imps.IMGUR_CLIENT_ID != "REPLACE_ME": - image_link = imps.IMAGES_URL + imagefile + if imps.IMAGES_URL or not imps.IMG_HOST_ACTIVE: + image_link = imps.multi_image(imagefile) images_list.append(imagefile) else: - imagefile_save = imps.IMG_DIR / imagefile - uploaded_image = imps.gst_imgur.upload_image( - imagefile_save, title="something" - ) - image_link = uploaded_image.link - os.remove(imagefile_save) + image_link = imps.multi_image(imagefile) embeds_img.append( f"{image_link}", @@ -149,15 +147,15 @@ def pos_command(sort="dpp_dollar", ascending: bool = False, num: int = 10): else: fig = imps.plot_df( df, - fig_size=(900, (40 * dindex)), - col_width=[2, 3, 4, 3.5, 5, 4, 5], + fig_size=(720, (40 * dindex)), + col_width=[2, 4, 4, 4], tbl_header=imps.PLT_TBL_HEADER, tbl_cells=imps.PLT_TBL_CELLS, font=imps.PLT_TBL_FONT, row_fill_color=imps.PLT_TBL_ROW_COLORS, paper_bgcolor="rgba(0, 0, 0, 0)", ) - fig.update_traces(cells=(dict(align=["center", "left"]))) + fig.update_traces(cells=(dict(align=["center", "right"]))) imagefile = imps.save_image("dps-pos.png", fig) output = { diff --git a/bots/stocks/dark_pool_shorts/psi.py b/bots/stocks/dark_pool_shorts/psi.py index a2389f9cc19..bbc94227efc 100644 --- a/bots/stocks/dark_pool_shorts/psi.py +++ b/bots/stocks/dark_pool_shorts/psi.py @@ -96,14 +96,13 @@ def psi_command(ticker: str = ""): if imps.PLT_WATERMARK: fig.add_layout_image(imps.PLT_WATERMARK) fig.update_traces(hovertemplate="%{y:.2f}") - fig.update_xaxes(showspikes=True, spikesnap="cursor", spikemode="across") - fig.update_yaxes(showspikes=True, spikethickness=2) fig.update_layout( margin=dict(l=10, r=0, t=40, b=20), template=imps.PLT_TA_STYLE_TEMPLATE, colorway=imps.PLT_TA_COLORWAY, - title=f"Price vs Short Volume Interest for {ticker}", - title_x=0.45, + title=f"Price vs Short Volume Interest for {ticker}", + title_x=0.025, + title_font_size=14, yaxis_title="Stock Price ($)", yaxis2_title="FINRA Volume [M]", yaxis3_title="Short Vol. %", @@ -111,6 +110,7 @@ def psi_command(ticker: str = ""): yaxis=dict( side="right", fixedrange=False, + showgrid=False, titlefont=dict(color="#fdc708"), tickfont=dict(color="#fdc708"), nticks=20, @@ -137,8 +137,8 @@ def psi_command(ticker: str = ""): dragmode="pan", legend=dict(orientation="h", yanchor="bottom", y=1.02, xanchor="right", x=1), hovermode="x unified", - spikedistance=1000, - hoverdistance=100, + spikedistance=1, + hoverdistance=1, ) imagefile = "dps_psi.png" diff --git a/bots/stocks/dark_pool_shorts/shorted.py b/bots/stocks/dark_pool_shorts/shorted.py index c56092e2684..3eac85cd5ed 100644 --- a/bots/stocks/dark_pool_shorts/shorted.py +++ b/bots/stocks/dark_pool_shorts/shorted.py @@ -1,10 +1,11 @@ import logging -import os import disnake +import pandas as pd from bots import imps from gamestonk_terminal.decorators import log_start_end +from gamestonk_terminal.helper_funcs import lambda_long_number_format from gamestonk_terminal.stocks.dark_pool_shorts import yahoofinance_model logger = logging.getLogger(__name__) @@ -26,6 +27,7 @@ def shorted_command(num: int = 10): df = yahoofinance_model.get_most_shorted().head(num) if df.empty: raise Exception("No available data found") + # Debug user output if imps.DEBUG: logger.debug(df.to_string()) @@ -34,9 +36,37 @@ def shorted_command(num: int = 10): title = "Stocks: [Yahoo Finance] Most Shorted" df.dropna(how="all", axis=1, inplace=True) df = df.replace(float("NaN"), "") - df = df.drop(columns=["PE Ratio (TTM)"]) - df.set_index("Symbol", inplace=True) + # Convert and format: str into float + for col in ["Volume", "Avg Vol (3 month)"]: + df[col] = [imps.unit_finder.sub(imps.unit_replacer, x) for x in df[col]] + df[col] = pd.to_numeric(df[col].astype(float)) + df[col] = df[col].map(lambda x: lambda_long_number_format(x, 2)) + + for col in ["Price (Intraday)", "Change"]: + df[col] = df[col].apply(lambda x: f"${x:.2f}") + + # Format "%% Change" columns then combine it into "Change" + df["% Change"] = df.apply(lambda x: f"({x['% Change']})", axis=1) + df["Change"] = df.apply(lambda x: f"{x['Change']} {x['% Change']}", axis=1) + + # Combine "Volume" columns + df["Volume"] = df.apply( + lambda x: f"{x['Volume']:>8} ({x['Avg Vol (3 month)']:>8})", + axis=1, + ) + + df = df.drop(columns=["% Change", "Avg Vol (3 month)", "PE Ratio (TTM)"]) + df.columns = [ + "Ticker", + "Name", + "Price", + "Change", + "Volume (Avg)", + "Mkt Cap", + ] + + df.set_index("Ticker", inplace=True) dindex = len(df.index) if dindex > 15: embeds: list = [] @@ -48,28 +78,23 @@ def shorted_command(num: int = 10): df_pg.append(df_pg) fig = imps.plot_df( df_pg, - fig_size=(900, (45 * dindex)), - col_width=[2, 9, 2.5, 2.5, 2.5, 3, 3, 3], + fig_size=(950, (45 * dindex)), + col_width=[2.1, 10, 2.5, 5, 5.2, 3], tbl_header=imps.PLT_TBL_HEADER, tbl_cells=imps.PLT_TBL_CELLS, font=imps.PLT_TBL_FONT, row_fill_color=imps.PLT_TBL_ROW_COLORS, paper_bgcolor="rgba(0, 0, 0, 0)", ) - fig.update_traces(cells=(dict(align=["center", "left"]))) + fig.update_traces(cells=(dict(align=["center", "center", "right"]))) imagefile = "etf-holdings.png" imagefile = imps.save_image(imagefile, fig) - if imps.IMAGES_URL or imps.IMGUR_CLIENT_ID != "REPLACE_ME": - image_link = imps.IMAGES_URL + imagefile + if imps.IMAGES_URL or not imps.IMG_HOST_ACTIVE: + image_link = imps.multi_image(imagefile) images_list.append(imagefile) else: - imagefile_save = imps.IMG_DIR / imagefile - uploaded_image = imps.gst_imgur.upload_image( - imagefile_save, title="something" - ) - image_link = uploaded_image.link - os.remove(imagefile_save) + image_link = imps.multi_image(imagefile) embeds_img.append( f"{image_link}", @@ -117,15 +142,15 @@ def shorted_command(num: int = 10): else: fig = imps.plot_df( df, - fig_size=(900, (45 * dindex)), - col_width=[2, 9, 2.5, 2.5, 2.5, 3, 3, 3], + fig_size=(950, (45 * dindex)), + col_width=[2.1, 10, 2.5, 5, 5.2, 3], tbl_header=imps.PLT_TBL_HEADER, tbl_cells=imps.PLT_TBL_CELLS, font=imps.PLT_TBL_FONT, row_fill_color=imps.PLT_TBL_ROW_COLORS, paper_bgcolor="rgba(0, 0, 0, 0)", ) - fig.update_traces(cells=(dict(align=["left", "center"]))) + fig.update_traces(cells=(dict(align=["center", "center", "right"]))) imagefile = imps.save_image("etf-holdings.png", fig) output = { diff --git a/bots/stocks/disc/active.py b/bots/stocks/disc/active.py index 0e822d0184d..28094fa73c5 100644 --- a/bots/stocks/disc/active.py +++ b/bots/stocks/disc/active.py @@ -1,5 +1,4 @@ import logging -import os import disnake import pandas as pd @@ -91,16 +90,11 @@ def active_command(num: int = 10): imagefile = "disc-active.png" imagefile = imps.save_image(imagefile, fig) - if imps.IMAGES_URL or imps.IMGUR_CLIENT_ID != "REPLACE_ME": - image_link = imps.IMAGES_URL + imagefile + if imps.IMAGES_URL or not imps.IMG_HOST_ACTIVE: + image_link = imps.multi_image(imagefile) images_list.append(imagefile) else: - imagefile_save = imps.IMG_DIR / imagefile - uploaded_image = imps.gst_imgur.upload_image( - imagefile_save, title="something" - ) - image_link = uploaded_image.link - os.remove(imagefile_save) + image_link = imps.multi_image(imagefile) embeds_img.append( f"{image_link}", diff --git a/bots/stocks/disc/ford.py b/bots/stocks/disc/ford.py index 9a5caaced6c..0935737811d 100755 --- a/bots/stocks/disc/ford.py +++ b/bots/stocks/disc/ford.py @@ -1,5 +1,4 @@ import logging -import os import disnake @@ -69,16 +68,11 @@ def ford_command(): imagefile = "disc-ford.png" imagefile = imps.save_image(imagefile, fig) - if imps.IMAGES_URL or imps.IMGUR_CLIENT_ID != "REPLACE_ME": - image_link = imps.IMAGES_URL + imagefile + if imps.IMAGES_URL or not imps.IMG_HOST_ACTIVE: + image_link = imps.multi_image(imagefile) images_list.append(imagefile) else: - imagefile_save = imps.IMG_DIR / imagefile - uploaded_image = imps.gst_imgur.upload_image( - imagefile_save, title="something" - ) - image_link = uploaded_image.link - os.remove(imagefile_save) + image_link = imps.multi_image(imagefile) embeds_img.append( f"{image_link}", diff --git a/bots/stocks/disc/topgainers.py b/bots/stocks/disc/topgainers.py index b3ca1bff522..ca211f7b4f5 100755 --- a/bots/stocks/disc/topgainers.py +++ b/bots/stocks/disc/topgainers.py @@ -1,5 +1,4 @@ import logging -import os import disnake import pandas as pd @@ -91,16 +90,11 @@ def gainers_command(num: int = 10): imagefile = "disc-gainers.png" imagefile = imps.save_image(imagefile, fig) - if imps.IMAGES_URL or imps.IMGUR_CLIENT_ID != "REPLACE_ME": - image_link = imps.IMAGES_URL + imagefile + if imps.IMAGES_URL or not imps.IMG_HOST_ACTIVE: + image_link = imps.multi_image(imagefile) images_list.append(imagefile) else: - imagefile_save = imps.IMG_DIR / imagefile - uploaded_image = imps.gst_imgur.upload_image( - imagefile_save, title="something" - ) - image_link = uploaded_image.link - os.remove(imagefile_save) + image_link = imps.multi_image(imagefile) embeds_img.append( f"{image_link}", diff --git a/bots/stocks/disc/toplosers.py b/bots/stocks/disc/toplosers.py index 1d03b31cc51..572c65836a9 100755 --- a/bots/stocks/disc/toplosers.py +++ b/bots/stocks/disc/toplosers.py @@ -1,5 +1,4 @@ import logging -import os import disnake import pandas as pd @@ -91,16 +90,11 @@ def losers_command(num: int = 10): imagefile = "disc-losers.png" imagefile = imps.save_image(imagefile, fig) - if imps.IMAGES_URL or imps.IMGUR_CLIENT_ID != "REPLACE_ME": - image_link = imps.IMAGES_URL + imagefile + if imps.IMAGES_URL or not imps.IMG_HOST_ACTIVE: + image_link = imps.multi_image(imagefile) images_list.append(imagefile) else: - imagefile_save = imps.IMG_DIR / imagefile - uploaded_image = imps.gst_imgur.upload_image( - imagefile_save, title="something" - ) - image_link = uploaded_image.link - os.remove(imagefile_save) + image_link = imps.multi_image(imagefile) embeds_img.append( f"{image_link}", diff --git a/bots/stocks/disc/ugs.py b/bots/stocks/disc/ugs.py index b0e1412dc5a..1f1d46cc6b8 100755 --- a/bots/stocks/disc/ugs.py +++ b/bots/stocks/disc/ugs.py @@ -1,5 +1,4 @@ import logging -import os import disnake import pandas as pd @@ -91,16 +90,11 @@ def ugs_command(num: int = 10): imagefile = "disc-ugs.png" imagefile = imps.save_image(imagefile, fig) - if imps.IMAGES_URL or imps.IMGUR_CLIENT_ID != "REPLACE_ME": - image_link = imps.IMAGES_URL + imagefile + if imps.IMAGES_URL or not imps.IMG_HOST_ACTIVE: + image_link = imps.multi_image(imagefile) images_list.append(imagefile) else: - imagefile_save = imps.IMG_DIR / imagefile - uploaded_image = imps.gst_imgur.upload_image( - imagefile_save, title="something" - ) - image_link = uploaded_image.link - os.remove(imagefile_save) + image_link = imps.multi_image(imagefile) embeds_img.append( f"{image_link}", diff --git a/bots/stocks/disc/upcoming.py b/bots/stocks/disc/upcoming.py index ec6a2f67c12..854e2226a5a 100644 --- a/bots/stocks/disc/upcoming.py +++ b/bots/stocks/disc/upcoming.py @@ -1,5 +1,4 @@ import logging -import os import disnake @@ -54,16 +53,11 @@ def earnings_command(): imagefile = "disc-upcoming.png" imagefile = imps.save_image(imagefile, fig) - if imps.IMAGES_URL or imps.IMGUR_CLIENT_ID != "REPLACE_ME": - image_link = imps.IMAGES_URL + imagefile + if imps.IMAGES_URL or not imps.IMG_HOST_ACTIVE: + image_link = imps.multi_image(imagefile) images_list.append(imagefile) else: - imagefile_save = imps.IMG_DIR / imagefile - uploaded_image = imps.gst_imgur.upload_image( - imagefile_save, title="something" - ) - image_link = uploaded_image.link - os.remove(imagefile_save) + image_link = imps.multi_image(imagefile) embeds_img.append( f"{image_link}", diff --git a/bots/stocks/due_diligence/arktrades.py b/bots/stocks/due_diligence/arktrades.py index c3c53d813bf..025a8081e9a 100644 --- a/bots/stocks/due_diligence/arktrades.py +++ b/bots/stocks/due_diligence/arktrades.py @@ -1,5 +1,4 @@ import logging -import os import disnake import pandas as pd @@ -73,16 +72,11 @@ def arktrades_command(ticker: str = "", num: int = 30): ) imagefile = imps.save_image("dd-arktrades.png", fig) - if imps.IMAGES_URL or imps.IMGUR_CLIENT_ID != "REPLACE_ME": - image_link = imps.IMAGES_URL + imagefile + if imps.IMAGES_URL or not imps.IMG_HOST_ACTIVE: + image_link = imps.multi_image(imagefile) images_list.append(imagefile) else: - imagefile_save = imps.IMG_DIR / imagefile - uploaded_image = imps.gst_imgur.upload_image( - imagefile_save, title="something" - ) - image_link = uploaded_image.link - os.remove(imagefile_save) + image_link = imps.multi_image(imagefile) embeds_img.append( f"{image_link}", diff --git a/bots/stocks/due_diligence/borrowed.py b/bots/stocks/due_diligence/borrowed.py index 9416406e3e8..67e2c4e2f29 100755 --- a/bots/stocks/due_diligence/borrowed.py +++ b/bots/stocks/due_diligence/borrowed.py @@ -1,5 +1,4 @@ import logging -import os import disnake import pandas as pd @@ -34,7 +33,7 @@ def borrowed_command(ticker: str = ""): title = f"{ticker.upper()} Shares Available to Borrow [Stocksera]" - df = df.head(1000) + df = df.head(200) df["changed"] = df["available"].astype(int).diff() df = df[df["changed"] != 0.0] df = df.drop(columns="changed") @@ -72,16 +71,11 @@ def borrowed_command(ticker: str = ""): imagefile = "dd_borrowed.png" imagefile = imps.save_image(imagefile, fig) - if imps.IMAGES_URL or imps.IMGUR_CLIENT_ID != "REPLACE_ME": - image_link = imps.IMAGES_URL + imagefile + if imps.IMAGES_URL or not imps.IMG_HOST_ACTIVE: + image_link = imps.multi_image(imagefile) images_list.append(imagefile) else: - imagefile_save = imps.IMG_DIR / imagefile - uploaded_image = imps.gst_imgur.upload_image( - imagefile_save, title="something" - ) - image_link = uploaded_image.link - os.remove(imagefile_save) + image_link = imps.multi_image(imagefile) embeds_img.append( f"{image_link}", diff --git a/bots/stocks/due_diligence/est.py b/bots/stocks/due_diligence/est.py index b82d7092906..99bcb557e57 100644 --- a/bots/stocks/due_diligence/est.py +++ b/bots/stocks/due_diligence/est.py @@ -1,5 +1,4 @@ import logging -import os import disnake @@ -55,14 +54,11 @@ def est_command(ticker: str = ""): ) imagefile = imps.save_image("estimates.png", fig) - if imps.IMAGES_URL or imps.IMGUR_CLIENT_ID != "REPLACE_ME": - link_estimates = imps.IMAGES_URL + imagefile + if imps.IMAGES_URL or not imps.IMG_HOST_ACTIVE: + link_estimates = imps.multi_image(imagefile) images_list.append(imagefile) else: - imagefile_save = imps.IMG_DIR / imagefile - uploaded_image = imps.gst_imgur.upload_image(imagefile_save, title="something") - link_estimates = uploaded_image.link - os.remove(imagefile_save) + link_estimates = imps.multi_image(imagefile) fig = imps.plot_df( df_quarter_earnings, @@ -76,14 +72,11 @@ def est_command(ticker: str = ""): ) imagefile = imps.save_image("earnings.png", fig) - if imps.IMAGES_URL or imps.IMGUR_CLIENT_ID != "REPLACE_ME": - link_earnings = imps.IMAGES_URL + imagefile + if imps.IMAGES_URL or not imps.IMG_HOST_ACTIVE: + link_earnings = imps.multi_image(imagefile) images_list.append(imagefile) else: - imagefile_save = imps.IMG_DIR / imagefile - uploaded_image = imps.gst_imgur.upload_image(imagefile_save, title="something") - link_earnings = uploaded_image.link - os.remove(imagefile_save) + link_earnings = imps.multi_image(imagefile) fig = imps.plot_df( df_quarter_revenues, @@ -97,14 +90,11 @@ def est_command(ticker: str = ""): ) imagefile = imps.save_image("revenues.png", fig) - if imps.IMAGES_URL or imps.IMGUR_CLIENT_ID != "REPLACE_ME": - link_revenues = imps.IMAGES_URL + imagefile + if imps.IMAGES_URL or not imps.IMG_HOST_ACTIVE: + link_revenues = imps.multi_image(imagefile) images_list.append(imagefile) else: - imagefile_save = imps.IMG_DIR / imagefile - uploaded_image = imps.gst_imgur.upload_image(imagefile_save, title="something") - link_revenues = uploaded_image.link - os.remove(imagefile_save) + link_revenues = imps.multi_image(imagefile) embeds = [ disnake.Embed( diff --git a/bots/stocks/government/contracts.py b/bots/stocks/government/contracts.py index e5ba66753b4..34a84aef597 100644 --- a/bots/stocks/government/contracts.py +++ b/bots/stocks/government/contracts.py @@ -55,6 +55,7 @@ def contracts_command( imagefile = "gov_contracts.png" dataBytesIO = io.BytesIO() plt.savefig(dataBytesIO) + plt.close("all") dataBytesIO.seek(0) imagefile = imps.image_border(imagefile, base64=dataBytesIO) diff --git a/bots/stocks/government/gtrades.py b/bots/stocks/government/gtrades.py index c68e40bf344..6f7302ae8ea 100644 --- a/bots/stocks/government/gtrades.py +++ b/bots/stocks/government/gtrades.py @@ -113,6 +113,7 @@ def gtrades_command( dataBytesIO = io.BytesIO() plt.savefig(dataBytesIO) dataBytesIO.seek(0) + plt.close("all") imagefile = imps.image_border(imagefile, base64=dataBytesIO) diff --git a/bots/stocks/government/histcont.py b/bots/stocks/government/histcont.py index f68e519cff1..e4531046ea9 100644 --- a/bots/stocks/government/histcont.py +++ b/bots/stocks/government/histcont.py @@ -59,6 +59,7 @@ def histcont_command(ticker=""): dataBytesIO = io.BytesIO() plt.savefig(dataBytesIO) dataBytesIO.seek(0) + plt.close("all") imagefile = imps.image_border(imagefile, base64=dataBytesIO) diff --git a/bots/stocks/government/qtrcontracts.py b/bots/stocks/government/qtrcontracts.py index f56eede4429..698628cc0d5 100644 --- a/bots/stocks/government/qtrcontracts.py +++ b/bots/stocks/government/qtrcontracts.py @@ -86,6 +86,7 @@ def qtrcontracts_command(num: int = 20, analysis=""): dataBytesIO = io.BytesIO() plt.savefig(dataBytesIO) dataBytesIO.seek(0) + plt.close("all") imagefile = imps.image_border(imagefile, base64=dataBytesIO) output = { diff --git a/bots/stocks/government/topbuys.py b/bots/stocks/government/topbuys.py index b7cf69e0140..49760d4f79b 100644 --- a/bots/stocks/government/topbuys.py +++ b/bots/stocks/government/topbuys.py @@ -108,6 +108,7 @@ def topbuys_command( dataBytesIO = io.BytesIO() plt.savefig(dataBytesIO) dataBytesIO.seek(0) + plt.close("all") imagefile = imps.image_border(imagefile, base64=dataBytesIO) diff --git a/bots/stocks/government/toplobbying.py b/bots/stocks/government/toplobbying.py index e1862e9fe39..9cb91b8e3d4 100644 --- a/bots/stocks/government/toplobbying.py +++ b/bots/stocks/government/toplobbying.py @@ -41,8 +41,8 @@ def toplobbying_command(num: int = 10, raw: bool = False): dataBytesIO = io.BytesIO() plt.savefig(dataBytesIO) - plt.close("all") dataBytesIO.seek(0) + plt.close("all") imagefile = imps.image_border(imagefile, base64=dataBytesIO) diff --git a/bots/stocks/government/topsells.py b/bots/stocks/government/topsells.py index 80a6b84f4df..4e4ed41bf62 100644 --- a/bots/stocks/government/topsells.py +++ b/bots/stocks/government/topsells.py @@ -119,6 +119,7 @@ def topsells_command( dataBytesIO = io.BytesIO() plt.savefig(dataBytesIO) dataBytesIO.seek(0) + plt.close("all") imagefile = imps.image_border(imagefile, base64=dataBytesIO) diff --git a/bots/stocks/insider/lins.py b/bots/stocks/insider/lins.py index 95f46f96cb3..cb1745ef85d 100644 --- a/bots/stocks/insider/lins.py +++ b/bots/stocks/insider/lins.py @@ -1,5 +1,4 @@ import logging -import os import disnake import pandas as pd @@ -84,16 +83,11 @@ def lins_command(ticker: str = "", num: int = 30): ) imagefile = imps.save_image("disc-insider.png", fig) - if imps.IMAGES_URL or imps.IMGUR_CLIENT_ID != "REPLACE_ME": - image_link = imps.IMAGES_URL + imagefile + if imps.IMAGES_URL or not imps.IMG_HOST_ACTIVE: + image_link = imps.multi_image(imagefile) images_list.append(imagefile) else: - imagefile_save = imps.IMG_DIR / imagefile - uploaded_image = imps.gst_imgur.upload_image( - imagefile_save, title="something" - ) - image_link = uploaded_image.link - os.remove(imagefile_save) + image_link = imps.multi_image(imagefile) embeds_img.append( f"{image_link}", diff --git a/bots/stocks/options/oi.py b/bots/stocks/options/oi.py index 76b9d31b079..b372f2016c1 100644 --- a/bots/stocks/options/oi.py +++ b/bots/stocks/options/oi.py @@ -70,7 +70,7 @@ def oi_command( y=df_opt["OI_call"], name="Calls", mode="lines+markers", - line=dict(color="green", width=3), + line=dict(color="#00ACFF", width=3), ) ) @@ -80,7 +80,7 @@ def oi_command( y=df_opt["OI_put"], name="Puts", mode="lines+markers", - line=dict(color="red", width=3), + line=dict(color="#e4003a", width=3), ) ) fig.add_trace( diff --git a/bots/stocks/options/opt_chain.py b/bots/stocks/options/opt_chain.py index 2e642b2920d..4efb85f8218 100755 --- a/bots/stocks/options/opt_chain.py +++ b/bots/stocks/options/opt_chain.py @@ -1,5 +1,4 @@ import logging -import os import disnake import numpy as np @@ -102,16 +101,11 @@ def chain_command( imagefile = "opt-chain.png" imagefile = imps.save_image(imagefile, fig) - if imps.IMAGES_URL or imps.IMGUR_CLIENT_ID != "REPLACE_ME": - image_link = imps.IMAGES_URL + imagefile + if imps.IMAGES_URL or not imps.IMG_HOST_ACTIVE: + image_link = imps.multi_image(imagefile) images_list.append(imagefile) else: - imagefile_save = imps.IMG_DIR / imagefile - uploaded_image = imps.gst_imgur.upload_image( - imagefile_save, title="something" - ) - image_link = uploaded_image.link - os.remove(imagefile_save) + image_link = imps.multi_image(imagefile) embeds_img.append( f"{image_link}", diff --git a/bots/stocks/options/overview.py b/bots/stocks/options/overview.py index 58b62d4ece7..7167ecf1459 100644 --- a/bots/stocks/options/overview.py +++ b/bots/stocks/options/overview.py @@ -65,7 +65,7 @@ def options_run( y=df_opt["OI_call"], name="Calls", mode="lines+markers", - line=dict(color="green", width=3), + line=dict(color="#00ACFF", width=3), ) ) @@ -75,7 +75,7 @@ def options_run( y=df_opt["OI_put"], name="Puts", mode="lines+markers", - line=dict(color="red", width=3), + line=dict(color="#e4003a", width=3), ) ) fig.add_trace( @@ -132,16 +132,11 @@ def options_run( imagefile = imps.image_border(imagefile, fig=fig) - if imps.IMAGES_URL or imps.IMGUR_CLIENT_ID != "REPLACE_ME": - image_link_oi = imps.IMAGES_URL + imagefile + if imps.IMAGES_URL or not imps.IMG_HOST_ACTIVE: + image_link_oi = imps.multi_image(imagefile) images_list.append(imagefile) else: - imagefile_save = imps.IMG_DIR / imagefile - uploaded_image_oi = imps.gst_imgur.upload_image( - imagefile_save, title="something" - ) - image_link_oi = uploaded_image_oi.link - os.remove(imagefile_save) + image_link_oi = imps.multi_image(imagefile) calls_df = calls[columns].rename(columns=column_map) calls_df = calls_df[calls_df["strike"] >= min_strike2] @@ -211,16 +206,11 @@ def options_run( imagefile = "opt-calls.png" imagefile = imps.save_image(imagefile, figc) - if imps.IMAGES_URL or imps.IMGUR_CLIENT_ID != "REPLACE_ME": - image_link = imps.IMAGES_URL + imagefile + if imps.IMAGES_URL or not imps.IMG_HOST_ACTIVE: + image_link = imps.multi_image(imagefile) images_list.append(imagefile) else: - imagefile_save = imps.IMG_DIR / imagefile - uploaded_image = imps.gst_imgur.upload_image( - imagefile_save, title="something" - ) - image_link = uploaded_image.link - os.remove(imagefile_save) + image_link = imps.multi_image(imagefile) embeds_img.append( f"{image_link}", @@ -290,16 +280,11 @@ def options_run( imagefile = "opt-puts.png" imagefile = imps.save_image(imagefile, figp) - if imps.IMAGES_URL or imps.IMGUR_CLIENT_ID != "REPLACE_ME": - image_link = imps.IMAGES_URL + imagefile + if imps.IMAGES_URL or not imps.IMG_HOST_ACTIVE: + image_link = imps.multi_image(imagefile) images_list.append(imagefile) else: - imagefile_save = imps.IMG_DIR / imagefile - uploaded_image = imps.gst_imgur.upload_image( - imagefile_save, title="something" - ) - image_link = uploaded_image.link - os.remove(imagefile_save) + image_link = imps.multi_image(imagefile) embeds_img.append( f"{image_link}", diff --git a/bots/stocks/options/smile.py b/bots/stocks/options/smile.py new file mode 100644 index 00000000000..8328cfe29bd --- /dev/null +++ b/bots/stocks/options/smile.py @@ -0,0 +1,127 @@ +import logging + +import plotly.graph_objects as go + +from bots import imps +from gamestonk_terminal.decorators import log_start_end +from gamestonk_terminal.stocks.options import yfinance_model + +logger = logging.getLogger(__name__) + + +@log_start_end(log=logger) +def smile_command( + ticker: str = None, + expiry: str = "", + min_sp: float = None, + max_sp: float = None, +): + """Options Smile""" + + # Debug + if imps.DEBUG: + logger.debug("opt smile %s %s %s %s", ticker, expiry, min_sp, max_sp) + + # Check for argument + if ticker is None: + raise Exception("Stock ticker is required") + + dates = yfinance_model.option_expirations(ticker) + + if not dates: + raise Exception("Stock ticker is invalid") + + options = yfinance_model.get_option_chain(ticker, expiry) + calls = options.calls.fillna(0.0) + puts = options.puts.fillna(0.0) + current_price = yfinance_model.get_price(ticker) + + min_strike = 0.60 * current_price + max_strike = 1.95 * current_price + + if len(calls) > 40: + min_strike = 0.60 * current_price + max_strike = 1.50 * current_price + + if min_sp: + min_strike = min_sp + if max_sp: + max_strike = max_sp + + fig = go.Figure() + + fig.add_trace( + go.Scatter( + x=calls["strike"], + y=calls["impliedVolatility"].interpolate(method="nearest"), + name="Calls", + mode="lines+markers", + marker=dict( + color="#00ACFF", + size=4.5, + ), + line=dict(color="#00ACFF", width=2, dash="dash"), + ) + ) + + fig.add_trace( + go.Scatter( + x=puts["strike"], + y=puts["impliedVolatility"].interpolate(method="nearest"), + name="Puts", + mode="lines+markers", + marker=dict( + color="#e4003a", + size=4.5, + ), + line=dict(color="#e4003a", width=2, dash="dash"), + ) + ) + + if imps.PLT_WATERMARK: + fig.add_layout_image(imps.PLT_WATERMARK) + fig.update_xaxes( + range=[min_strike, max_strike], + constrain="domain", + ) + fig.update_layout( + margin=dict(l=20, r=0, t=60, b=20), + template=imps.PLT_SCAT_STYLE_TEMPLATE, + font=imps.PLT_FONT, + title=f"Implied Volatility vs. Strike for {ticker.upper()} expiring {expiry}", + title_x=0.5, + legend_title="", + xaxis_title="Strike", + yaxis_title="Implied Volatility", + yaxis=dict( + side="right", + fixedrange=False, + nticks=20, + ), + xaxis=dict( + rangeslider=dict(visible=False), + nticks=20, + ), + legend=dict(yanchor="top", y=0.99, xanchor="left", x=0.01), + dragmode="pan", + ) + + imagefile = "opt_smile.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"Implied Volatility vs. Stirke for {ticker.upper()} expiring {expiry}", + "description": plt_link, + "imagefile": imagefile, + } diff --git a/bots/stocks/options/unu.py b/bots/stocks/options/unu.py index 1f488d4d4f1..bef28900c77 100755 --- a/bots/stocks/options/unu.py +++ b/bots/stocks/options/unu.py @@ -1,5 +1,4 @@ import logging -import os import disnake import numpy as np @@ -102,16 +101,11 @@ def unu_command(num: int = 20): imagefile = "opt-unu.png" imagefile = imps.save_image(imagefile, fig) - if imps.IMAGES_URL or imps.IMGUR_CLIENT_ID != "REPLACE_ME": - image_link = imps.IMAGES_URL + imagefile + if imps.IMAGES_URL or not imps.IMG_HOST_ACTIVE: + image_link = imps.multi_image(imagefile) images_list.append(imagefile) else: - imagefile_save = imps.IMG_DIR / imagefile - uploaded_image = imps.gst_imgur.upload_image( - imagefile_save, title="something" - ) - image_link = uploaded_image.link - os.remove(imagefile_save) + image_link = imps.multi_image(imagefile) embeds_img.append( f"{image_link}", diff --git a/bots/stocks/options/vol.py b/bots/stocks/options/vol.py index 4ae4e7f5f98..57089cda52c 100644 --- a/bots/stocks/options/vol.py +++ b/bots/stocks/options/vol.py @@ -62,7 +62,7 @@ def vol_command( y=call_v.values, name="Calls", mode="lines+markers", - line=dict(color="green", width=3), + line=dict(color="#00ACFF", width=3), ) ) fig.add_trace( @@ -71,7 +71,7 @@ def vol_command( y=put_v.values, name="Puts", mode="lines+markers", - line=dict(color="red", width=3), + line=dict(color="#e4003a", width=3), ) ) fig.add_trace( diff --git a/bots/stocks/screener/financial.py b/bots/stocks/screener/financial.py index 5912e33d6b3..bcc8e7648f1 100644 --- a/bots/stocks/screener/financial.py +++ b/bots/stocks/screener/financial.py @@ -1,6 +1,5 @@ import difflib import logging -import os import disnake import pandas as pd @@ -94,16 +93,11 @@ def financial_command(preset="template", sort="", limit: int = 5, ascend: bool = imagefile = "scr_financial.png" imagefile = imps.save_image(imagefile, fig) - if imps.IMAGES_URL or imps.IMGUR_CLIENT_ID != "REPLACE_ME": - image_link = imps.IMAGES_URL + imagefile + if imps.IMAGES_URL or not imps.IMG_HOST_ACTIVE: + image_link = imps.multi_image(imagefile) images_list.append(imagefile) else: - imagefile_save = imps.IMG_DIR / imagefile - uploaded_image = imps.gst_imgur.upload_image( - imagefile_save, title="something" - ) - image_link = uploaded_image.link - os.remove(imagefile_save) + image_link = imps.multi_image(imagefile) embeds_img.append( f"{image_link}", diff --git a/bots/stocks/screener/historical.py b/bots/stocks/screener/historical.py index e6351a22d08..8a8e189dc69 100644 --- a/bots/stocks/screener/historical.py +++ b/bots/stocks/screener/historical.py @@ -135,6 +135,7 @@ def historical_command(signal: str = "", start=""): dataBytesIO = io.BytesIO() plt.savefig(dataBytesIO) dataBytesIO.seek(0) + plt.close("all") imagefile = imps.image_border(imagefile, base64=dataBytesIO) diff --git a/bots/stocks/screener/overview.py b/bots/stocks/screener/overview.py index 6ab85ec0702..0decb831d0a 100644 --- a/bots/stocks/screener/overview.py +++ b/bots/stocks/screener/overview.py @@ -1,6 +1,5 @@ import difflib import logging -import os import disnake import pandas as pd @@ -100,16 +99,11 @@ def overview_command( imagefile = "scr_overview.png" imagefile = imps.save_image(imagefile, fig) - if imps.IMAGES_URL or imps.IMGUR_CLIENT_ID != "REPLACE_ME": - image_link = imps.IMAGES_URL + imagefile + if imps.IMAGES_URL or not imps.IMG_HOST_ACTIVE: + image_link = imps.multi_image(imagefile) images_list.append(imagefile) else: - imagefile_save = imps.IMG_DIR / imagefile - uploaded_image = imps.gst_imgur.upload_image( - imagefile_save, title="something" - ) - image_link = uploaded_image.link - os.remove(imagefile_save) + image_link = imps.multi_image(imagefile) embeds_img.append( f"{image_link}", diff --git a/bots/stocks/screener/ownership.py b/bots/stocks/screener/ownership.py index e78dc14d17d..d4c30f67a7e 100644 --- a/bots/stocks/screener/ownership.py +++ b/bots/stocks/screener/ownership.py @@ -1,6 +1,5 @@ import difflib import logging -import os import disnake import pandas as pd @@ -100,16 +99,11 @@ def ownership_command( imagefile = "scr_ownership.png" imagefile = imps.save_image(imagefile, fig) - if imps.IMAGES_URL or imps.IMGUR_CLIENT_ID != "REPLACE_ME": - image_link = imps.IMAGES_URL + imagefile + if imps.IMAGES_URL or not imps.IMG_HOST_ACTIVE: + image_link = imps.multi_image(imagefile) images_list.append(imagefile) else: - imagefile_save = imps.IMG_DIR / imagefile - uploaded_image = imps.gst_imgur.upload_image( - imagefile_save, title="something" - ) - image_link = uploaded_image.link - os.remove(imagefile_save) + image_link = imps.multi_image(imagefile) embeds_img.append( f"{image_link}", diff --git a/bots/stocks/screener/performance.py b/bots/stocks/screener/performance.py index 820c0ebe961..c10be86e7c4 100644 --- a/bots/stocks/screener/performance.py +++ b/bots/stocks/screener/performance.py @@ -1,6 +1,5 @@ import difflib import logging -import os import disnake import pandas as pd @@ -120,16 +119,11 @@ def performance_command( imagefile = "scr_performance.png" imagefile = imps.save_image(imagefile, fig) - if imps.IMAGES_URL or imps.IMGUR_CLIENT_ID != "REPLACE_ME": - image_link = imps.IMAGES_URL + imagefile + if imps.IMAGES_URL or not imps.IMG_HOST_ACTIVE: + image_link = imps.multi_image(imagefile) images_list.append(imagefile) else: - imagefile_save = imps.IMG_DIR / imagefile - uploaded_image = imps.gst_imgur.upload_image( - imagefile_save, title="something" - ) - image_link = uploaded_image.link - os.remove(imagefile_save) + image_link = imps.multi_image(imagefile) embeds_img.append( f"{image_link}", diff --git a/bots/stocks/screener/technical.py b/bots/stocks/screener/technical.py index 8d677b9fb8d..57478ca0536 100644 --- a/bots/stocks/screener/technical.py +++ b/bots/stocks/screener/technical.py @@ -1,6 +1,5 @@ import difflib import logging -import os import disnake import pandas as pd @@ -99,16 +98,11 @@ def technical_command( imagefile = "scr_technical.png" imagefile = imps.save_image(imagefile, fig) - if imps.IMAGES_URL or imps.IMGUR_CLIENT_ID != "REPLACE_ME": - image_link = imps.IMAGES_URL + imagefile + if imps.IMAGES_URL or not imps.IMG_HOST_ACTIVE: + image_link = imps.multi_image(imagefile) images_list.append(imagefile) else: - imagefile_save = imps.IMG_DIR / imagefile - uploaded_image = imps.gst_imgur.upload_image( - imagefile_save, title="something" - ) - image_link = uploaded_image.link - os.remove(imagefile_save) + image_link = imps.multi_image(imagefile) embeds_img.append( f"{image_link}", diff --git a/bots/stocks/screener/valuation.py b/bots/stocks/screener/valuation.py index bb75cf2139b..d30ce52ee68 100644 --- a/bots/stocks/screener/valuation.py +++ b/bots/stocks/screener/valuation.py @@ -1,6 +1,5 @@ import difflib import logging -import os import disnake import pandas as pd @@ -100,16 +99,11 @@ def valuation_command( imagefile = "scr_valuation.png" imagefile = imps.save_image(imagefile, fig) - if imps.IMAGES_URL or imps.IMGUR_CLIENT_ID != "REPLACE_ME": - image_link = imps.IMAGES_URL + imagefile + if imps.IMAGES_URL or not imps.IMG_HOST_ACTIVE: + image_link = imps.multi_image(imagefile) images_list.append(imagefile) else: - imagefile_save = imps.IMG_DIR / imagefile - uploaded_image = imps.gst_imgur.upload_image( - imagefile_save, title="something" - ) - image_link = uploaded_image.link - os.remove(imagefile_save) + image_link = imps.multi_image(imagefile) embeds_img.append( f"{image_link}", diff --git a/bots/stocks/technical_analysis/ad.py b/bots/stocks/technical_analysis/ad.py index 87a0385702a..7e39d48d124 100755 --- a/bots/stocks/technical_analysis/ad.py +++ b/bots/stocks/technical_analysis/ad.py @@ -65,6 +65,7 @@ def ad_command( # 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, @@ -91,7 +92,7 @@ def ad_command( go.Scatter( name="A/D", x=df_ta.index, - y=df_ta.iloc[:, 6].values, + y=df_ta.iloc[:, 6].values if interval != 1440 else df_ta.iloc[:, 11].values, mode="lines", line=dict(width=2), opacity=1, diff --git a/bots/stocks/technical_analysis/adosc.py b/bots/stocks/technical_analysis/adosc.py index 0f4e642f9b1..40d3a006bda 100755 --- a/bots/stocks/technical_analysis/adosc.py +++ b/bots/stocks/technical_analysis/adosc.py @@ -75,6 +75,7 @@ def adosc_command( # 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, @@ -102,7 +103,7 @@ def adosc_command( name="AD Osc [M]", mode="lines", x=df_ta.index, - y=df_ta.iloc[:, 6].values, + y=df_ta.iloc[:, 6].values if interval != 1440 else df_ta.iloc[:, 11].values, line=dict(width=2), opacity=1, ), diff --git a/bots/stocks/technical_analysis/adx.py b/bots/stocks/technical_analysis/adx.py index def99bcc846..2b0c326eee6 100755 --- a/bots/stocks/technical_analysis/adx.py +++ b/bots/stocks/technical_analysis/adx.py @@ -90,6 +90,7 @@ def adx_command( # 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, @@ -108,13 +109,14 @@ def adx_command( ) title = f"{plot['plt_title']} Average Directional Movement Index" fig = plot["fig"] + idx = 6 if interval != 1440 else 11 fig.add_trace( go.Scatter( name=f"ADX ({length})", mode="lines", x=df_ta.index, - y=df_ta.iloc[:, 6].values, + y=df_ta.iloc[:, idx].values, opacity=1, line=dict(width=2), ), @@ -127,7 +129,7 @@ def adx_command( name=f"+DI ({length})", mode="lines", x=df_ta.index, - y=df_ta.iloc[:, 7].values, + y=df_ta.iloc[:, (idx + 1)].values, opacity=1, line=dict(width=1), ), @@ -140,7 +142,7 @@ def adx_command( name=f"-DI ({length})", mode="lines", x=df_ta.index, - y=df_ta.iloc[:, 8].values, + y=df_ta.iloc[:, (idx + 2)].values, opacity=1, line=dict(width=1), ), diff --git a/bots/stocks/technical_analysis/aroon.py b/bots/stocks/technical_analysis/aroon.py index 25dfe76ec5f..e0fa6ca1fac 100755 --- a/bots/stocks/technical_analysis/aroon.py +++ b/bots/stocks/technical_analysis/aroon.py @@ -75,6 +75,7 @@ def aroon_command( # 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, @@ -97,12 +98,13 @@ def aroon_command( ) title = f"{plot['plt_title']} Aroon ({length})" fig = plot["fig"] + idx = 6 if interval != 1440 else 11 fig.add_trace( go.Scatter( name="Aroon DOWN", x=df_ta.index, - y=df_ta.iloc[:, 6].values, + y=df_ta.iloc[:, idx].values, opacity=1, ), row=2, @@ -113,7 +115,7 @@ def aroon_command( go.Scatter( name="Aroon UP", x=df_ta.index, - y=df_ta.iloc[:, 7].values, + y=df_ta.iloc[:, (idx + 1)].values, opacity=1, ), row=2, @@ -124,7 +126,7 @@ def aroon_command( go.Scatter( name="Aroon OSC", x=df_ta.index, - y=df_ta.iloc[:, 8].values, + y=df_ta.iloc[:, (idx + 2)].values, opacity=1, ), row=3, diff --git a/bots/stocks/technical_analysis/bbands.py b/bots/stocks/technical_analysis/bbands.py index 8e67f2fbfb6..ac0f4cb0d84 100755 --- a/bots/stocks/technical_analysis/bbands.py +++ b/bots/stocks/technical_analysis/bbands.py @@ -97,16 +97,18 @@ def bbands_command( # 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) title = f"{plot['plt_title']} Bollinger Bands ({ma_mode.upper()})" fig = plot["fig"] + idx = 6 if interval != 1440 else 11 fig.add_trace( go.Scatter( name=f"BBU_{length}_{n_std}", x=df_ta.index, - y=df_ta.iloc[:, 8].values, + y=df_ta.iloc[:, (idx + 2)].values, opacity=1, mode="lines", line_color="indigo", @@ -119,7 +121,7 @@ def bbands_command( go.Scatter( name=f"BBL_{length}_{n_std}", x=df_ta.index, - y=df_ta.iloc[:, 6].values, + y=df_ta.iloc[:, idx].values, opacity=1, mode="lines", line_color="indigo", @@ -134,7 +136,7 @@ def bbands_command( go.Scatter( name=f"BBM_{length}_{n_std}", x=df_ta.index, - y=df_ta.iloc[:, 7].values, + y=df_ta.iloc[:, (idx + 1)].values, opacity=1, line=dict( width=1.5, diff --git a/bots/stocks/technical_analysis/cci.py b/bots/stocks/technical_analysis/cci.py index 463ff41695e..37ed6cdef7a 100755 --- a/bots/stocks/technical_analysis/cci.py +++ b/bots/stocks/technical_analysis/cci.py @@ -82,6 +82,7 @@ def cci_command( # 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, @@ -100,15 +101,19 @@ def cci_command( ) title = f"{plot['plt_title']} Commodity-Channel-Index" fig = plot["fig"] + ta_values = ( + df_ta.iloc[:, 6].values if interval != 1440 else df_ta.iloc[:, 11].values + ) + + dmin = ta_values.min() + dmax = ta_values.max() - dmin = df_ta.iloc[:, 6].values.values.min() - dmax = df_ta.iloc[:, 6].values.values.max() fig.add_trace( go.Scatter( name=f"CCI ({length}) ({scalar})", mode="lines", x=df_ta.index, - y=df_ta.iloc[:, 6].values, + y=ta_values, opacity=1, ), row=2, diff --git a/bots/stocks/technical_analysis/cg.py b/bots/stocks/technical_analysis/cg.py index 49b96659aaf..bcce3f708f3 100755 --- a/bots/stocks/technical_analysis/cg.py +++ b/bots/stocks/technical_analysis/cg.py @@ -57,6 +57,7 @@ def cg_command(ticker="", length="14", start="", end=""): df_close = df_stock["Adj Close"] df_close.columns = ["values"] df_ta = momentum_model.cg(df_close, length) + df_ta = df_ta.fillna(0.0) # Output Data fig, axes = plt.subplots(2, 1, figsize=plot_autoscale(), dpi=PLOT_DPI) diff --git a/bots/stocks/technical_analysis/donchian.py b/bots/stocks/technical_analysis/donchian.py index 58bde040c32..ebf13adf03f 100755 --- a/bots/stocks/technical_analysis/donchian.py +++ b/bots/stocks/technical_analysis/donchian.py @@ -63,6 +63,7 @@ def donchian_command( df_ta = volatility_model.donchian( df_stock["High"], df_stock["Low"], upper_length, lower_length ) + df_ta = df_ta.fillna(0.0) # Output Data fig, ax = plt.subplots(figsize=plot_autoscale(), dpi=PLOT_DPI) diff --git a/bots/stocks/technical_analysis/fib.py b/bots/stocks/technical_analysis/fib.py index 281dfdd1eb4..09ff19fcfac 100755 --- a/bots/stocks/technical_analysis/fib.py +++ b/bots/stocks/technical_analysis/fib.py @@ -37,7 +37,7 @@ def fib_command( news, ) - past_days = past_days if (interval != 1440) or (start != "") else 365 + past_days = (past_days + 1) if (interval != 1440) or (start != "") else 365 # Retrieve Data (df_stock, start, end, bar_start,) = load_candle.stock_data( diff --git a/bots/stocks/technical_analysis/fisher.py b/bots/stocks/technical_analysis/fisher.py index 3dc8ab7c090..6a7c4de28ee 100755 --- a/bots/stocks/technical_analysis/fisher.py +++ b/bots/stocks/technical_analysis/fisher.py @@ -71,6 +71,7 @@ def fisher_command( # 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, @@ -89,15 +90,16 @@ def fisher_command( ) title = f"{plot['plt_title']} Fisher Transform" fig = plot["fig"] + idx = 6 if interval != 1440 else 11 - dmin = df_ta.iloc[:, 7].values.min() - dmax = df_ta.iloc[:, 7].values.max() + dmin = df_ta.iloc[:, (idx + 1)].values.min() + dmax = df_ta.iloc[:, (idx + 1)].values.max() fig.add_trace( go.Scatter( name="Fisher", mode="lines", x=df_ta.index, - y=df_ta.iloc[:, 6].values, + y=df_ta.iloc[:, idx].values, opacity=1, ), row=2, @@ -108,7 +110,7 @@ def fisher_command( name="Signal", mode="lines", x=df_ta.index, - y=df_ta.iloc[:, 7].values, + y=df_ta.iloc[:, (idx + 1)].values, opacity=1, ), row=2, diff --git a/bots/stocks/technical_analysis/kc.py b/bots/stocks/technical_analysis/kc.py index 99a95454ac5..cd4f9b87bfd 100755 --- a/bots/stocks/technical_analysis/kc.py +++ b/bots/stocks/technical_analysis/kc.py @@ -90,6 +90,7 @@ def kc_command( # 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, @@ -104,12 +105,13 @@ def kc_command( ) title = f"{plot['plt_title']} Keltner Channels ({ma_mode.upper()})" fig = plot["fig"] + idx = 6 if interval != 1440 else 11 fig.add_trace( go.Scatter( name="upper", x=df_ta.index, - y=df_ta.iloc[:, 8].values, + y=df_ta.iloc[:, (idx + 2)].values, opacity=1, mode="lines", line_color="indigo", @@ -123,7 +125,7 @@ def kc_command( go.Scatter( name="lower", x=df_ta.index, - y=df_ta.iloc[:, 6].values, + y=df_ta.iloc[:, idx].values, opacity=1, mode="lines", line_color="indigo", @@ -139,7 +141,7 @@ def kc_command( go.Scatter( name="mid", x=df_ta.index, - y=df_ta.iloc[:, 7].values, + y=df_ta.iloc[:, (idx + 1)].values, opacity=1, line=dict( width=1.5, diff --git a/bots/stocks/technical_analysis/ma.py b/bots/stocks/technical_analysis/ma.py index 553f6ab0e9b..ffffb8528bc 100755 --- a/bots/stocks/technical_analysis/ma.py +++ b/bots/stocks/technical_analysis/ma.py @@ -94,6 +94,7 @@ def ma_command( # 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, @@ -107,7 +108,8 @@ def ma_command( title = f"{plot['plt_title']} Moving Average ({ma_mode.upper()})" fig = plot["fig"] - for i in range(6, df_ta.shape[1]): + i2 = 6 if interval != 1440 else 11 + for i in range(i2, df_ta.shape[1]): fig.add_trace( go.Scatter( name=f"{df_ta.iloc[:, i].name}", diff --git a/bots/stocks/technical_analysis/macd.py b/bots/stocks/technical_analysis/macd.py index 05ab56b9b9e..4e286b47931 100755 --- a/bots/stocks/technical_analysis/macd.py +++ b/bots/stocks/technical_analysis/macd.py @@ -83,6 +83,7 @@ def macd_command( # 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, @@ -101,12 +102,13 @@ def macd_command( ) title = f"{plot['plt_title']} MACD {fast} {slow} {signal}" fig = plot["fig"] + idx = 6 if interval != 1440 else 11 fig.add_trace( go.Bar( name="MACD Histogram", x=df_ta.index, - y=df_ta.iloc[:, 7].values, + y=df_ta.iloc[:, (idx + 1)].values, opacity=(plot["bar_opacity"] + 0.3), marker_color="#d81aea", ), @@ -119,7 +121,7 @@ def macd_command( name="MACD Line", mode="lines", x=df_ta.index, - y=df_ta.iloc[:, 6].values, + y=df_ta.iloc[:, idx].values, opacity=0.8, line=dict(color="#00e6c3"), ), @@ -132,7 +134,7 @@ def macd_command( name="Signal Line", mode="lines", x=df_ta.index, - y=df_ta.iloc[:, 8].values, + y=df_ta.iloc[:, (idx + 2)].values, opacity=1, line=dict(color="#9467bd"), ), diff --git a/bots/stocks/technical_analysis/obv.py b/bots/stocks/technical_analysis/obv.py index 24981fb9654..5bdc76c7646 100755 --- a/bots/stocks/technical_analysis/obv.py +++ b/bots/stocks/technical_analysis/obv.py @@ -59,6 +59,7 @@ def obv_command( # 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, @@ -86,7 +87,7 @@ def obv_command( name="OBV", mode="lines", x=df_ta.index, - y=df_ta.iloc[:, 6].values, + y=df_ta.iloc[:, 6].values if interval != 1440 else df_ta.iloc[:, 11].values, line=dict(width=2), opacity=1, ), diff --git a/bots/stocks/technical_analysis/rsi.py b/bots/stocks/technical_analysis/rsi.py index fefea6bf1fd..a3591345386 100755 --- a/bots/stocks/technical_analysis/rsi.py +++ b/bots/stocks/technical_analysis/rsi.py @@ -77,6 +77,7 @@ def rsi_command( # 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, @@ -104,7 +105,7 @@ def rsi_command( name=f"RSI {length}", mode="lines", x=df_ta.index, - y=df_ta.iloc[:, 6].values, + y=df_ta.iloc[:, 6].values if interval != 1440 else df_ta.iloc[:, 11].values, opacity=1, ), row=2, diff --git a/bots/stocks/technical_analysis/stoch.py b/bots/stocks/technical_analysis/stoch.py index 5b2acb3ddab..c127265b616 100755 --- a/bots/stocks/technical_analysis/stoch.py +++ b/bots/stocks/technical_analysis/stoch.py @@ -87,6 +87,7 @@ def stoch_command( # 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, @@ -105,12 +106,13 @@ def stoch_command( ) title = f"{plot['plt_title']} STOCH RSI" 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[:, 6].values, + y=df_ta.iloc[:, idx].values, line=dict(width=1.8), mode="lines", opacity=1, @@ -122,7 +124,7 @@ def stoch_command( go.Scatter( name=f"%D {fast_k}, {slow_d}, {slow_k}", x=df_ta.index, - y=df_ta.iloc[:, 7].values, + y=df_ta.iloc[:, (idx + 1)].values, line=dict(width=1.8, dash="dash"), opacity=1, ), diff --git a/bots/stocks/technical_analysis/view.py b/bots/stocks/technical_analysis/view.py index 7867572d0a8..23a62f22d55 100755 --- a/bots/stocks/technical_analysis/view.py +++ b/bots/stocks/technical_analysis/view.py @@ -32,6 +32,7 @@ def view_command(ticker=""): im.save(dataBytesIO, "PNG", quality=100) dataBytesIO.seek(0) imagefile = image_border(imagefile, base64=dataBytesIO) + im.close() return { "title": f"Stocks: [Finviz] Trendlines & Data {ticker.upper()}", diff --git a/poetry.lock b/poetry.lock index a97e59d4e54..21077da677b 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1653,7 +1653,7 @@ python-versions = ">=3.6" [[package]] name = "kaleido" -version = "0.2.1.post1" +version = "0.2.1" description = "Static image export for web-based visualization libraries with zero dependencies" category = "main" optional = true @@ -5366,7 +5366,12 @@ jupyterlab-widgets = [ {file = "jupyterlab_widgets-1.1.0.tar.gz", hash = "sha256:d5f41bc1713795385f718d44dcba47e1e1473c6289f28a95aa6b2c0782ee372a"}, ] kaleido = [ - {file = "kaleido-0.2.1.post1-py2.py3-none-manylinux2014_armv7l.whl", hash = "sha256:d313940896c24447fc12c74f60d46ea826195fc991f58569a6e73864d53e5c20"}, + {file = "kaleido-0.2.1-py2.py3-none-macosx_10_11_x86_64.whl", hash = "sha256:ca6f73e7ff00aaebf2843f73f1d3bacde1930ef5041093fe76b83a15785049a7"}, + {file = "kaleido-0.2.1-py2.py3-none-macosx_11_0_arm64.whl", hash = "sha256:bb9a5d1f710357d5d432ee240ef6658a6d124c3e610935817b4b42da9c787c05"}, + {file = "kaleido-0.2.1-py2.py3-none-manylinux1_x86_64.whl", hash = "sha256:aa21cf1bf1c78f8fa50a9f7d45e1003c387bd3d6fe0a767cfbbf344b95bdc3a8"}, + {file = "kaleido-0.2.1-py2.py3-none-manylinux2014_aarch64.whl", hash = "sha256:845819844c8082c9469d9c17e42621fbf85c2b237ef8a86ec8a8527f98b6512a"}, + {file = "kaleido-0.2.1-py2.py3-none-win32.whl", hash = "sha256:ecc72635860be616c6b7161807a65c0dbd9b90c6437ac96965831e2e24066552"}, + {file = "kaleido-0.2.1-py2.py3-none-win_amd64.whl", hash = "sha256:4670985f28913c2d063c5734d125ecc28e40810141bdb0a46f15b76c1d45f23c"}, ] keras = [ {file = "keras-2.8.0-py2.py3-none-any.whl", hash = "sha256:744d39dc6577dcd80ff4a4d41549e92b77d6a17e0edd58a431d30656e29bc94e"},