def historical(other_args: List[str], preset_loaded: str): """View historical price of stocks that meet preset Parameters ---------- other_args : List[str] Command line arguments to be processed with argparse ticker : str Loaded preset filter """ parser = argparse.ArgumentParser( add_help=False, prog="historical", description= """Historical price comparison between similar companies [Source: Yahoo Finance] """, ) parser.add_argument( "--start", type=valid_date, default=datetime.datetime.now() - datetime.timedelta(days=6 * 30), dest="start", help= "The starting date (format YYYY-MM-DD) of the historical price to plot", ) parser.add_argument( "-t", "--type", action="store", dest="type_candle", type=check_one_of_ohlca, default="a", # in case it's adjusted close help=( "type of candles: o-open, h-high, l-low, c-close, a-adjusted close." ), ) parser.add_argument( "-s", "--signal", action="store", dest="signal", type=str, default=None, help="Signal", choices=list(finviz_view.d_signals.keys()), ) try: ns_parser = parse_known_args_and_warn(parser, other_args) if not ns_parser: return preset_filter = configparser.RawConfigParser() preset_filter.optionxform = str # type: ignore preset_filter.read("gamestonk_terminal/screener/presets/" + preset_loaded + ".ini") d_general = preset_filter["General"] d_filters = { **preset_filter["Descriptive"], **preset_filter["Fundamental"], **preset_filter["Technical"], } d_filters = {k: v for k, v in d_filters.items() if v} screen = ticker.Ticker() if ns_parser.signal: screen.set_filter(signal=finviz_view.d_signals[ns_parser.signal]) else: if d_general["Signal"]: screen.set_filter(filters_dict=d_filters, signal=d_general["Signal"]) else: screen.set_filter(filters_dict=d_filters) l_min = list() l_leg = list() plt.figure(figsize=plot_autoscale(), dpi=PLOT_DPI) l_stocks = screen.ScreenerView(verbose=0) if len(l_stocks) > 10: print( "\nThe limit of stocks to compare with are 10. Hence, 10 random similar stocks will be displayed.", "\nThe selected list will be:", ) random.shuffle(l_stocks) l_stocks = sorted(l_stocks[:10]) print(", ".join(l_stocks)) while l_stocks: l_parsed_stocks = list() for symbol in l_stocks: try: df_similar_stock = yf.download( symbol, start=datetime.datetime.strftime( ns_parser.start, "%Y-%m-%d"), progress=False, threads=False, ) if not df_similar_stock.empty: plt.plot( df_similar_stock.index, df_similar_stock[d_candle_types[ ns_parser.type_candle]].values, ) l_min.append(df_similar_stock.index[0]) l_leg.append(symbol) l_parsed_stocks.append(symbol) except Exception as e: print("") print(e) print( "Disregard previous error, which is due to API Rate limits from Yahoo Finance." ) print( f"Because we like '{symbol}', and we won't leave without getting data from it." ) for parsed_stock in l_parsed_stocks: l_stocks.remove(parsed_stock) if ns_parser.signal: plt.title( f"Screener Historical Price using {finviz_view.d_signals[ns_parser.signal]} signal" ) else: plt.title( f"Screener Historical Price using {preset_loaded} preset") plt.xlabel("Time") plt.ylabel("Share Price ($)") plt.legend(l_leg) plt.grid(b=True, which="major", color="#666666", linestyle="-") plt.minorticks_on() plt.grid(b=True, which="minor", color="#999999", linestyle="-", alpha=0.2) # ensures that the historical data starts from same datapoint plt.xlim([max(l_min), df_similar_stock.index[-1]]) if gtff.USE_ION: plt.ion() plt.show() print("") return l_parsed_stocks except SystemExit: print("Similar companies need to be provided", "\n") return [] except Exception as e: print(e, "\n") return []
def historical( preset_loaded: str, limit: int = 10, start: datetime.datetime = datetime.datetime.now() - datetime.timedelta(days=6 * 30), type_candle: str = "a", normalize: bool = True, export: str = "", external_axes: Optional[List[plt.Axes]] = None, ) -> List[str]: """View historical price of stocks that meet preset Parameters ---------- preset_loaded: str Preset loaded to filter for tickers limit: int Number of stocks to display start: datetime Start datetime to display historical data type_candle: str Type of candle to display normalize : bool Boolean to normalize all stock prices using MinMax export : str Export dataframe data to csv,json,xlsx file external_axes : Optional[List[plt.Axes]], optional External axes (1 axis is expected in the list), by default None""" screen = ticker.Ticker() if preset_loaded in finviz_model.d_signals: screen.set_filter(signal=finviz_model.d_signals[preset_loaded]) else: preset_filter = configparser.RawConfigParser() preset_filter.optionxform = str # type: ignore preset_filter.read(presets_path + preset_loaded + ".ini") d_general = preset_filter["General"] d_filters = { **preset_filter["Descriptive"], **preset_filter["Fundamental"], **preset_filter["Technical"], } d_filters = {k: v for k, v in d_filters.items() if v} if "Signal" in d_general and d_general["Signal"]: screen.set_filter(filters_dict=d_filters, signal=d_general["Signal"]) else: screen.set_filter(filters_dict=d_filters) l_stocks = screen.ScreenerView(verbose=0) limit_random_stocks = False if l_stocks: if len(l_stocks) > limit: random.shuffle(l_stocks) l_stocks = sorted(l_stocks[:limit]) console.print( "\nThe limit of stocks to compare with are 10. Hence, 10 random similar stocks will be displayed.", f"\nThe selected list will be: {', '.join(l_stocks)}", ) limit_random_stocks = True df_screener = yf.download( l_stocks, start=start, progress=False, threads=False)[d_candle_types[type_candle]][l_stocks] df_screener = df_screener[l_stocks] if np.any(df_screener.isna()): nan_tickers = df_screener.columns[ df_screener.isna().sum() >= 1].to_list() console.print( f"NaN values found in: {', '.join(nan_tickers)}. Replacing with zeros." ) df_screener = df_screener.fillna(0) # This plot has 1 axis if not external_axes: _, ax = plt.subplots(figsize=plot_autoscale(), dpi=PLOT_DPI) else: if len(external_axes) != 1: logger.error("Expected list of one axis item.") console.print("[red]Expected list of one axis item./n[/red]") # Return empty list to be compatible with the other return statement return [] (ax, ) = external_axes # This puts everything on 0-1 scale for visualizing if normalize: mm_scale = MinMaxScaler() df_screener = pd.DataFrame( mm_scale.fit_transform(df_screener), columns=df_screener.columns, index=df_screener.index, ) df_screener.plot(ax=ax) if limit_random_stocks: ax.set_title( f"Screener Historical Price with {preset_loaded}\non 10 random stocks" ) else: ax.set_title(f"Screener Historical Price with {preset_loaded}") ax.set_ylabel( f"{['','Normalized'][normalize]} Share Price {['($)',''][normalize]}" ) ax.legend() # ensures that the historical data starts from same datapoint ax.set_xlim([df_screener.index[0], df_screener.index[-1]]) theme.style_primary_axis(ax) if not external_axes: theme.visualize_output() export_data( export, os.path.dirname(os.path.abspath(__file__)), "historical", df_screener, ) return l_stocks console.print("No screener stocks found with this preset", "\n") return []
def historical( preset_loaded: str, limit: int = 10, start: datetime.datetime = datetime.datetime.now() - datetime.timedelta(days=6 * 30), type_candle: str = "a", normalize: bool = True, export: str = "", ) -> List[str]: """View historical price of stocks that meet preset Parameters ---------- preset_loaded: str Preset loaded to filter for tickers limit: int Number of stocks to display start: datetime Start datetime to display historical data type_candle: str Type of candle to display normalize : bool Boolean to normalize all stock prices using MinMax export : str Export dataframe data to csv,json,xlsx file """ screen = ticker.Ticker() if preset_loaded in finviz_model.d_signals: screen.set_filter(signal=finviz_model.d_signals[preset_loaded]) else: preset_filter = configparser.RawConfigParser() preset_filter.optionxform = str # type: ignore preset_filter.read(presets_path + preset_loaded + ".ini") d_general = preset_filter["General"] d_filters = { **preset_filter["Descriptive"], **preset_filter["Fundamental"], **preset_filter["Technical"], } d_filters = {k: v for k, v in d_filters.items() if v} if "Signal" in d_general and d_general["Signal"]: screen.set_filter(filters_dict=d_filters, signal=d_general["Signal"]) else: screen.set_filter(filters_dict=d_filters) l_stocks = screen.ScreenerView(verbose=0) limit_random_stocks = False if l_stocks: if len(l_stocks) > limit: random.shuffle(l_stocks) l_stocks = sorted(l_stocks[:limit]) console.print( "\nThe limit of stocks to compare with are 10. Hence, 10 random similar stocks will be displayed.", f"\nThe selected list will be: {', '.join(l_stocks)}", ) limit_random_stocks = True df_screener = yf.download(l_stocks, start=start, progress=False, threads=False)[ d_candle_types[type_candle] ][l_stocks] df_screener = df_screener[l_stocks] if np.any(df_screener.isna()): nan_tickers = df_screener.columns[df_screener.isna().sum() >= 1].to_list() console.print( f"NaN values found in: {', '.join(nan_tickers)}. Replacing with zeros." ) df_screener = df_screener.fillna(0) fig, ax = plt.subplots(figsize=plot_autoscale(), dpi=PLOT_DPI) # This puts everything on 0-1 scale for visualizing if normalize: mm_scale = MinMaxScaler() df_screener = pd.DataFrame( mm_scale.fit_transform(df_screener), columns=df_screener.columns, index=df_screener.index, ) df_screener.plot(ax=ax) if limit_random_stocks: ax.set_title( f"Screener Historical Price using {preset_loaded} on 10 of those stocks" ) else: ax.set_title(f"Screener Historical Price using {preset_loaded}") ax.set_xlabel("Time") ax.set_ylabel( f"{['','Normalized'][normalize]} Share Price {['($)',''][normalize]}" ) ax.grid(b=True, which="major", color="#666666", linestyle="-") ax.legend(l_stocks, bbox_to_anchor=(1.04, 1), loc="upper left") # ensures that the historical data starts from same datapoint ax.set_xlim([df_screener.index[0], df_screener.index[-1]]) plt.gcf().autofmt_xdate() fig.tight_layout() if gtff.USE_ION: plt.ion() plt.show() console.print("") export_data( export, os.path.dirname(os.path.abspath(__file__)), "historical", df_screener, ) return l_stocks console.print("No screener stocks found with this preset", "\n") return []
async def historical_command(ctx, signal="", start=""): """Displays historical price comparison between similar companies [Yahoo Finance]""" try: # Debug user input if cfg.DEBUG: logger.debug("!stocks.scr.historical %s %s", signal, start) # Check for argument if signal == "" or signal not in list(so.d_signals_desc.keys): raise Exception("Invalid preset selected!") register_matplotlib_converters() screen = ticker.Ticker() if signal in finviz_model.d_signals: screen.set_filter(signal=finviz_model.d_signals[signal]) else: preset_filter = configparser.RawConfigParser() preset_filter.optionxform = str # type: ignore preset_filter.read(so.presets_path + signal + ".ini") d_general = preset_filter["General"] d_filters = { **preset_filter["Descriptive"], **preset_filter["Fundamental"], **preset_filter["Technical"], } d_filters = {k: v for k, v in d_filters.items() if v} if d_general["Signal"]: screen.set_filter(filters_dict=d_filters, signal=d_general["Signal"]) else: screen.set_filter(filters_dict=d_filters) if start == "": start = datetime.now() - timedelta(days=365) else: start = datetime.strptime(start, cfg.DATE_FORMAT) # Output Data l_min = [] l_leg = [] l_stocks = screen.ScreenerView(verbose=0) if len(l_stocks) > 10: description = ( "\nThe limit of stocks to compare with are 10. Hence, 10 random similar stocks will be displayed." "\nThe selected list will be: ") random.shuffle(l_stocks) l_stocks = sorted(l_stocks[:10]) description = description + (", ".join(l_stocks)) logger.debug(description) plt.figure(figsize=plot_autoscale(), dpi=PLOT_DPI) while l_stocks: l_parsed_stocks = [] for symbol in l_stocks: try: df_similar_stock = yf.download( symbol, start=datetime.strftime(start, "%Y-%m-%d"), progress=False, threads=False, ) if not df_similar_stock.empty: plt.plot( df_similar_stock.index, df_similar_stock["Adj Close"].values, ) l_min.append(df_similar_stock.index[0]) l_leg.append(symbol) l_parsed_stocks.append(symbol) except Exception as e: error = ( f"{e}\nDisregard previous error, which is due to API Rate limits from Yahoo Finance. " f"Because we like '{symbol}', and we won't leave without getting data from it." ) embed = discord.Embed( title= "ERROR Stocks: [Yahoo Finance] Historical Screener", colour=cfg.COLOR, description=error, ) embed.set_author( name=cfg.AUTHOR_NAME, icon_url=cfg.AUTHOR_ICON_URL, ) await ctx.send(embed=embed) for parsed_stock in l_parsed_stocks: l_stocks.remove(parsed_stock) if signal: plt.title( f"Screener Historical Price using {finviz_model.d_signals[signal]} signal" ) else: plt.title(f"Screener Historical Price using {signal} preset") plt.xlabel("Time") plt.ylabel("Share Price ($)") plt.legend(l_leg) plt.grid(b=True, which="major", color="#666666", linestyle="-") plt.minorticks_on() plt.grid(b=True, which="minor", color="#999999", linestyle="-", alpha=0.2) # ensures that the historical data starts from same datapoint plt.xlim([max(l_min), df_similar_stock.index[-1]]) plt.savefig("scr_historical.png") uploaded_image = gst_imgur.upload_image("scr_historical.png", title="something") image_link = uploaded_image.link if cfg.DEBUG: logger.debug("Image URL: %s", image_link) title = "Stocks: [Yahoo Finance] Historical Screener" embed = discord.Embed(title=title, description=description, colour=cfg.COLOR) embed.set_author( name=cfg.AUTHOR_NAME, icon_url=cfg.AUTHOR_ICON_URL, ) embed.set_image(url=image_link) os.remove("scr_historical.png") await ctx.send(embed=embed) except Exception as e: embed = discord.Embed( title="ERROR Stocks: [Yahoo Finance] Historical Screener", colour=cfg.COLOR, description=e, ) embed.set_author( name=cfg.AUTHOR_NAME, icon_url=cfg.AUTHOR_ICON_URL, ) await ctx.send(embed=embed)
def historical_command(signal: str = "", start=""): """Displays historical price comparison between similar companies [Yahoo Finance]""" # Debug user input if imps.DEBUG: logger.debug("scr-historical %s %s", signal, start) # Check for argument if signal not in so.d_signals_desc: raise Exception("Invalid preset selected!") register_matplotlib_converters() screen = ticker.Ticker() if signal in finviz_model.d_signals: screen.set_filter(signal=finviz_model.d_signals[signal]) else: preset_filter = configparser.RawConfigParser() preset_filter.optionxform = str # type: ignore preset_filter.read(so.presets_path + signal + ".ini") d_general = preset_filter["General"] d_filters = { **preset_filter["Descriptive"], **preset_filter["Fundamental"], **preset_filter["Technical"], } d_filters = {k: v for k, v in d_filters.items() if v} if d_general["Signal"]: screen.set_filter(filters_dict=d_filters, signal=d_general["Signal"]) else: screen.set_filter(filters_dict=d_filters) if start == "": start = datetime.now() - timedelta(days=365) else: start = datetime.strptime(start, imps.DATE_FORMAT) # Output Data l_min = [] l_leg = [] l_stocks = screen.screener_view(verbose=0) if len(l_stocks) > 10: description = ( "\nThe limit of stocks to compare with are 10. Hence, 10 random similar stocks will be displayed." "\nThe selected list will be: ") random.shuffle(l_stocks) l_stocks = sorted(l_stocks[:10]) description = description + (", ".join(l_stocks)) logger.debug(description) plt.figure(figsize=plot_autoscale(), dpi=PLOT_DPI) while l_stocks: l_parsed_stocks = [] for symbol in l_stocks: try: df_similar_stock = yf.download( symbol, start=datetime.strftime(start, "%Y-%m-%d"), progress=False, threads=False, ) if not df_similar_stock.empty: plt.plot( df_similar_stock.index, df_similar_stock["Adj Close"].values, ) l_min.append(df_similar_stock.index[0]) l_leg.append(symbol) l_parsed_stocks.append(symbol) except Exception as e: error = ( f"{e}\nDisregard previous error, which is due to API Rate limits from Yahoo Finance. " f"Because we like '{symbol}', and we won't leave without getting data from it." ) return { "title": "ERROR Stocks: [Yahoo Finance] Historical Screener", "description": error, } for parsed_stock in l_parsed_stocks: l_stocks.remove(parsed_stock) if signal: plt.title( f"Screener Historical Price using {finviz_model.d_signals[signal]} signal" ) else: plt.title(f"Screener Historical Price using {signal} preset") plt.xlabel("Time") plt.ylabel("Share Price ($)") plt.legend(l_leg) plt.grid(b=True, which="major", color="#666666", linestyle="-") plt.minorticks_on() plt.grid(b=True, which="minor", color="#999999", linestyle="-", alpha=0.2) # ensures that the historical data starts from same datapoint plt.xlim([max(l_min), df_similar_stock.index[-1]]) imagefile = "scr_historical.png" dataBytesIO = io.BytesIO() plt.savefig(dataBytesIO) dataBytesIO.seek(0) plt.close("all") imagefile = imps.image_border(imagefile, base64=dataBytesIO) return { "title": "Stocks: [Yahoo Finance] Historical Screener", "description": description, "imagefile": imagefile, }