def display_unemployment( start_year: int = 2015, raw: bool = False, export: str = "", external_axes: Optional[List[plt.Axes]] = None, ): """Display US unemployment AlphaVantage Parameters ---------- start_year : int, optional Start year for plot, by default 2010 raw : bool, optional Flag to show raw data, by default False export : str, optional Format to export data, by default "" external_axes : Optional[List[plt.Axes]], optional External axes (1 axis is expected in the list), by default None """ unemp = alphavantage_model.get_unemployment() if unemp.empty: console.print("Error getting data. Check API Key") return un = unemp[unemp.date >= f"{start_year}-01-01"] if external_axes is None: _, ax = plt.subplots(figsize=plot_autoscale(), dpi=cfp.PLOT_DPI) else: if len(external_axes) != 1: console.print("[red]Expected list of 1 axis items./n[/red]") return (ax, ) = external_axes ax.plot(un.date, un.unemp, marker="o") ax.set_title(f"US Unemployment from {start_year}") ax.set_ylabel("US Unemployment ") theme.style_primary_axis(ax) if external_axes is None: theme.visualize_output() export_data( export, os.path.dirname(os.path.abspath(__file__)), "unemp", unemp, ) if raw: print_rich_table( un.head(20), headers=["Date", "GDP"], title="US Unemployment", show_index=False, ) console.print("")
def view(ticker: str, external_axes: Optional[List[plt.Axes]] = None): """View finviz image for ticker Parameters ---------- ticker : str Stock ticker external_axes : Optional[List[plt.Axes]], optional External axes (1 axis is expected in the list), by default None """ image_data = finviz_model.get_finviz_image(ticker) dataBytesIO = io.BytesIO(image_data) im = Image.open(dataBytesIO) # This plot has 1 axis if not external_axes: fig, 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 (ax, ) = external_axes ax.set_axis_off() fig.subplots_adjust(left=0, right=1, top=1, bottom=0) ax.imshow(im) # added for the watermark if not external_axes: theme.visualize_output()
def display_historical( data: pd.DataFrame, fund: str = "", export: str = "", external_axes: Optional[List[plt.Axes]] = None, ): """Display historical fund price Parameters ---------- data: pd.DataFrame Dataframe containing historical data fund: str Fund symbol or name export: str Format to export data external_axes:Optional[List[plt.Axes]]: External axes to plot on """ console.print() if external_axes is None: _, ax = plt.subplots(figsize=plot_autoscale(), dpi=PLOT_DPI) else: ax = external_axes[0] ax.plot(data.index, data.Close) ax.set_xlim([data.index[0], data.index[-1]]) ax.set_xlabel("Date") ax.set_ylabel("Close Price") ax.set_title(f"{fund.title()} Price History") theme.style_primary_axis(ax) if external_axes is None: theme.visualize_output() export_data(export, os.path.dirname(os.path.abspath(__file__)), "historical", data)
def plot_payoff( current_price: float, options: List[Dict[Any, Any]], underlying: int, ticker: str, expiration: str, external_axes: Optional[List[plt.Axes]] = None, ) -> None: """Generate a graph showing the option payoff diagram""" x, yb, ya = generate_data(current_price, options, underlying) if external_axes is None: _, ax = plt.subplots(figsize=plot_autoscale(), dpi=cfp.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 (ax, ) = external_axes if ya: ax.plot(x, yb, label="Payoff Before Premium") ax.plot(x, ya, label="Payoff After Premium") else: ax.plot(x, yb, label="Payoff") ax.set_title(f"Option Payoff Diagram for {ticker} on {expiration}") ax.set_ylabel("Profit") ax.set_xlabel("Underlying Asset Price at Expiration") ax.xaxis.set_major_formatter("${x:.2f}") ax.yaxis.set_major_formatter("${x:.2f}") theme.style_primary_axis(ax) if external_axes is None: theme.visualize_output()
def display_non_zero_addresses( asset: str, since: int, until: int, interval: str, export: str = "", external_axes: Optional[List[plt.Axes]] = None, ) -> None: """Display addresses with non-zero balance of a certain asset [Source: https://glassnode.org] Parameters ---------- asset : str Asset to search (e.g., BTC) since : int Initial date timestamp (e.g., 1_577_836_800) until : int End date timestamp (e.g., 1_609_459_200) interval : str Interval frequency (e.g., 24h) 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 """ df_addresses = get_non_zero_addresses(asset, interval, since, until) if df_addresses.empty: console.print("Error in glassnode request") else: # This plot has 1 axis if not external_axes: _, ax = plt.subplots(figsize=plot_autoscale(), dpi=cfgPlot.PLOT_DPI) else: if len(external_axes) != 1: console.print("[red]Expected list of one axis item./n[/red]") return (ax, ) = external_axes ax.plot(df_addresses.index, df_addresses["v"] / 1_000, linewidth=1.5) ax.set_title(f"{asset} Addresses with non-zero balances") ax.set_ylabel("Number of Addresses") ax.set_xlim(df_addresses.index[0], df_addresses.index[-1]) theme.style_primary_axis(ax) if not external_axes: theme.visualize_output() export_data( export, os.path.dirname(os.path.abspath(__file__)), "nonzero", df_addresses, )
def display_yield_curve(date: datetime, external_axes: Optional[List[plt.Axes]] = None): """Display yield curve based on US Treasury rates for a specified date. Parameters ---------- date: datetime Date to get yield curve for external_axes: Optional[List[plt.Axes]] External axes to plot data on """ rates, date_of_yield = fred_model.get_yield_curve(date) if rates.empty: console.print( f"[red]Yield data not found for {date.strftime('%Y-%m-%d')}[/red].\n" ) return if external_axes is None: _, ax = plt.subplots(figsize=plot_autoscale(), dpi=PLOT_DPI) else: if len(external_axes) != 1: logger.error("Expected list of 3 axis items") console.print("[red]Expected list of 3 axis items./n[/red]") return (ax, ) = external_axes ax.plot(rates.Maturity, rates.Rate, "-o") ax.set_xlabel("Maturity") ax.set_ylabel("Rate (%)") theme.style_primary_axis(ax) if external_axes is None: ax.set_title( f"US Yield Curve for {date_of_yield.strftime('%Y-%m-%d')} ") theme.visualize_output()
def display_returns_vs_bench( portfolio: portfolio_model.Portfolio, benchmark: str = "SPY", external_axes: Optional[plt.Axes] = None, ): """Display portfolio returns vs benchmark Parameters ---------- portfolio: Portfolio Custom portfolio object with trade list benchmark: str Symbol for benchmark. Defaults to SPY external_axes: plt.Axes Optional axes to display plot on """ if external_axes is None: _, ax = plt.subplots(figsize=plot_autoscale(), dpi=PLOT_DPI) else: ax = external_axes portfolio.generate_holdings_from_trades() portfolio.add_benchmark(benchmark) cumulative_returns = (1 + portfolio.returns).cumprod() benchmark_c_returns = (1 + portfolio.benchmark_returns).cumprod() ax.plot(cumulative_returns.index, cumulative_returns, label="Portfolio") ax.plot(benchmark_c_returns.index, benchmark_c_returns, label="Benchmark") ax.set_ylabel("Cumulative Returns") ax.legend(loc="upper left") theme.style_primary_axis(ax) if not external_axes: theme.visualize_output()
def display_candle( data: pd.DataFrame, to_symbol: str, from_symbol: str, external_axes: Optional[List[plt.Axes]] = None, ): """Show candle plot for fx data. Parameters ---------- data : pd.DataFrame Loaded fx historical data to_symbol : str To forex symbol from_symbol : str From forex symbol external_axes: Optional[List[plt.Axes]] External axes (1 axis are expected in the list), by default None """ candle_chart_kwargs = { "type": "candle", "style": theme.mpf_style, "mav": (20, 50), "volume": False, "xrotation": theme.xticks_rotation, "scale_padding": { "left": 0.3, "right": 1, "top": 0.8, "bottom": 0.8 }, "update_width_config": { "candle_linewidth": 0.6, "candle_width": 0.8, "volume_linewidth": 0.8, "volume_width": 0.8, }, "warn_too_much_data": 10000, } # This plot has 2 axes if not external_axes: candle_chart_kwargs["returnfig"] = True candle_chart_kwargs["figratio"] = (10, 7) candle_chart_kwargs["figscale"] = 1.10 candle_chart_kwargs["figsize"] = plot_autoscale() fig, _ = mpf.plot(data, **candle_chart_kwargs) fig.suptitle( f"{from_symbol}/{to_symbol}", x=0.055, y=0.965, horizontalalignment="left", ) theme.visualize_output(force_tight_layout=False) else: if len(external_axes) != 1: console.print("[red]Expected list of 1 axis items./n[/red]") return (ax1, ) = external_axes candle_chart_kwargs["ax"] = ax1 mpf.plot(data, **candle_chart_kwargs)
def display_marketcap_dominance( coin: str, start: str, end: str, interval: str, export: str = "", external_axes: Optional[List[plt.Axes]] = None, ) -> None: """Display market dominance of a coin over time [Source: https://messari.io/] Parameters ---------- coin : str Crypto symbol to check market cap dominance start : int Initial date like string (e.g., 2021-10-01) end : int End date like string (e.g., 2021-10-01) interval : str Interval frequency (e.g., 1d) 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 """ df = get_marketcap_dominance(coin=coin, start=start, end=end, interval=interval) if df.empty: return # This plot has 1 axis if not external_axes: _, ax = plt.subplots(figsize=plot_autoscale(), dpi=cfgPlot.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 (ax,) = external_axes ax.plot(df.index, df["marketcap_dominance"]) ax.set_title(f"{coin}'s Market Cap Dominance over time") ax.set_ylabel(f"{coin} Percentage share") ax.set_xlim(df.index[0], df.index[-1]) theme.style_primary_axis(ax) if not external_axes: theme.visualize_output() export_data( export, os.path.dirname(os.path.abspath(__file__)), "mcapdom", df, )
def display_active_addresses( asset: str, since: int, until: int, interval: str, export: str = "", external_axes: Optional[List[plt.Axes]] = None, ) -> None: """Display active addresses of a certain asset over time [Source: https://glassnode.org] Parameters ---------- asset : str Asset to search active addresses (e.g., BTC) since : int Initial date timestamp (e.g., 1_614_556_800) until : int End date timestamp (e.g., 1_614_556_800) interval : str Interval frequency (e.g., 24h) 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 """ df_addresses = get_active_addresses(asset, interval, since, until) if df_addresses.empty: return # This plot has 1 axis if not external_axes: _, ax = plt.subplots(figsize=plot_autoscale(), dpi=cfgPlot.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 (ax, ) = external_axes ax.plot(df_addresses.index, df_addresses["v"] / 1_000, linewidth=1.5) ax.set_title(f"Active {asset} addresses over time") ax.set_ylabel("Addresses [thousands]") ax.set_xlim(df_addresses.index[0], df_addresses.index[-1]) theme.style_primary_axis(ax) if not external_axes: theme.visualize_output() export_data( export, os.path.dirname(os.path.abspath(__file__)), "active", df_addresses, )
def display_cpi( interval: str, start_year: int = 2010, raw: bool = False, export: str = "", external_axes: Optional[List[plt.Axes]] = None, ): """Display US consumer price index (CPI) from AlphaVantage Parameters ---------- interval : str Interval for GDP. Either "m" or "s" start_year : int, optional Start year for plot, by default 2010 raw : bool, optional Flag to show raw data, by default False export : str, optional Format to export data, by default "" external_axes : Optional[List[plt.Axes]], optional External axes (1 axis is expected in the list), by default None """ cpi_full = alphavantage_model.get_cpi(interval) if cpi_full.empty: console.print("Error getting data. Check API Key") return cpi = cpi_full[cpi_full.date >= f"{start_year}-01-01"] int_string = "Semi-Annual" if interval == "s" else "Monthly" year_str = str(list(cpi.date)[-1].year) if external_axes is None: _, ax = plt.subplots(figsize=plot_autoscale(), dpi=cfp.PLOT_DPI) else: if len(external_axes) != 1: logger.error("Expected list of one axis item.") console.print("[red]Expected list of 1 axis item./n[/red]") return (ax, ) = external_axes ax.plot(cpi.date, cpi.CPI, marker="o") ax.set_title(f"{int_string} Consumer Price Index from {year_str}") ax.set_ylabel("CPI") theme.style_primary_axis(ax) if external_axes is None: theme.visualize_output() export_data( export, os.path.dirname(os.path.abspath(__file__)), "cpi", cpi_full, ) if raw: print_rich_table(cpi.head(20), headers=["Date", "CPI"], show_index=False, title="US CPI") console.print("")
def display_rsi_strategy( ticker: str, df_stock: pd.DataFrame, periods: int, low_rsi: int, high_rsi: int, spy_bt: bool = True, no_bench: bool = False, shortable: bool = True, export: str = "", external_axes: Optional[List[plt.Axes]] = None, ): """Strategy that buys when the stock is less than a threshold and shorts when it exceeds a threshold. Parameters ---------- ticker : str Stock ticker df_stock : pd.Dataframe Dataframe of prices periods : int Number of periods for RSI calculation low_rsi : int Low RSI value to buy high_rsi : int High RSI value to sell spy_bt : bool Boolean to add spy comparison no_bench : bool Boolean to not show buy and hold comparison shortable : bool Boolean to allow for selling of the stock at cross export : str Format to export backtest results external_axes : Optional[List[plt.Axes]], optional External axes (3 axes are expected in the list), by default None """ # 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 (ax, ) = external_axes res = bt_model.rsi_strategy(ticker, df_stock, periods, low_rsi, high_rsi, spy_bt, no_bench, shortable) res.plot(title=f"RSI Strategy between ({low_rsi}, {high_rsi})", ax=ax) theme.style_primary_axis(ax) if not external_axes: theme.visualize_output() export_data(export, os.path.dirname(os.path.abspath(__file__)), "rsi_corss", res.stats)
def display_real_gdp( interval: str, start_year: int = 2010, raw: bool = False, export: str = "", external_axes: Optional[List[plt.Axes]] = None, ): """Display US GDP from AlphaVantage Parameters ---------- interval : str Interval for GDP. Either "a" or "q" start_year : int, optional Start year for plot, by default 2010 raw : bool, optional Flag to show raw data, by default False export : str, optional Format to export data, by default "" external_axes : Optional[List[plt.Axes]], optional External axes (1 axis is expected in the list), by default None """ gdp_full = alphavantage_model.get_real_gdp(interval) if gdp_full.empty: return gdp = gdp_full[gdp_full.date >= f"{start_year}-01-01"] int_string = "Annual" if interval == "a" else "Quarterly" year_str = str(start_year) if interval == "a" else str( list(gdp.date)[-1].year) if external_axes is None: _, ax = plt.subplots(figsize=plot_autoscale(), dpi=cfp.PLOT_DPI) else: if len(external_axes) != 1: logger.error("Expected list of one axis item.") console.print("[red]Expected list of 1 axis items./n[/red]") return (ax, ) = external_axes ax.plot(gdp.date, gdp.GDP, marker="o") ax.set_title(f"{int_string} US GDP ($B) from {year_str}") ax.set_ylabel("US GDP ($B) ") theme.style_primary_axis(ax) if external_axes is None: theme.visualize_output() export_data( export, os.path.dirname(os.path.abspath(__file__)), "gdp", gdp_full, ) if raw: print_rich_table(gdp.head(20), headers=["Date", "GDP"], show_index=False, title="US GDP")
def display_dwat( dependent_variable: pd.Series, residual: pd.DataFrame, plot: bool = False, export: str = "", external_axes: Optional[List[plt.axes]] = None, ): """Show Durbin-Watson autocorrelation tests Parameters ---------- dependent_variable : pd.Series The dependent variable. residual : OLS Model The residual of an OLS model. plot : bool Whether to plot the residuals export : str Format to export data external_axes: Optional[List[plt.axes]] External axes to plot on """ autocorrelation = regression_model.get_dwat(residual) if 1.5 < autocorrelation < 2.5: console.print( f"The result {autocorrelation} is within the range 1.5 and 2.5 which therefore indicates " f"autocorrelation not to be problematic.") else: console.print( f"The result {autocorrelation} is outside the range 1.5 and 2.5 and therefore autocorrelation " f"can be problematic. Please consider lags of the dependent or independent variable." ) if plot: if external_axes is None: _, ax = plt.subplots(figsize=plot_autoscale(), dpi=PLOT_DPI) else: ax = external_axes[0] ax.scatter(dependent_variable, residual) ax.axhline(y=0, color="r", linestyle="-") ax.set_ylabel("Residual") ax.set_xlabel(dependent_variable.name.capitalize()) ax.set_title("Plot of Residuals") theme.style_primary_axis(ax) if external_axes is None: theme.visualize_output() export_data( export, os.path.dirname(os.path.abspath(__file__)), f"{dependent_variable.name}_dwat", autocorrelation, ) console.print()
def display_big_mac_index( country_codes: List[str], raw: bool = False, export: str = "", external_axes: Optional[List[plt.Axes]] = None, ): """Display Big Mac Index for given countries Parameters ---------- country_codes : List[str] List of country codes to get for raw : bool, optional Flag to display raw data, by default False export : str, optional Format data, by default "" external_axes : Optional[List[plt.Axes]], optional External axes (3 axes are expected in the list), by default None """ df_cols = ["Date"] df_cols.extend(country_codes) big_mac = pd.DataFrame(columns=df_cols) for country in country_codes: df1 = nasdaq_model.get_big_mac_index(country) if not df1.empty: big_mac[country] = df1["dollar_price"] big_mac["Date"] = df1["Date"] big_mac.set_index("Date", inplace=True) if not big_mac.empty: if external_axes is None: _, ax = plt.subplots(figsize=plot_autoscale(), dpi=PLOT_DPI) else: if len(external_axes) != 3: console.print("[red]Expected list of 3 axis items./n[/red]") return (ax, ) = external_axes big_mac.plot(ax=ax, marker="o") ax.legend() ax.set_title("Big Mac Index (USD)") ax.set_ylabel("Price of Big Mac in USD") theme.style_primary_axis(ax) if external_axes is None: theme.visualize_output() if raw: print_rich_table(big_mac, headers=list(big_mac.columns), title="Big Mac Index") console.print("") export_data(export, os.path.dirname(os.path.abspath(__file__)), "bigmac", big_mac) console.print("") else: console.print("[red]Unable to get big mac data[/red]\n")
def display_gdp_capita( start_year: int = 2010, raw: bool = False, export: str = "", external_axes: Optional[List[plt.Axes]] = None, ): """Display US GDP per Capita from AlphaVantage Parameters ---------- start_year : int, optional Start year for plot, by default 2010 raw : bool, optional Flag to show raw data, by default False export : str, optional Format to export data, by default external_axes : Optional[List[plt.Axes]], optional External axes (1 axis is expected in the list), by default None """ gdp_capita = alphavantage_model.get_gdp_capita() if gdp_capita.empty: console.print("Error getting data. Check API Key") return gdp = gdp_capita[gdp_capita.date >= f"{start_year}-01-01"] # This plot has 1 axis if not external_axes: _, ax = plt.subplots(figsize=plot_autoscale(), dpi=cfp.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 (ax, ) = external_axes ax.plot(gdp.date, gdp.GDP, marker="o") ax.set_title(f"US GDP per Capita (Chained 2012 USD) from {start_year}") ax.set_ylabel("US GDP (Chained 2012 USD) ") theme.style_primary_axis(ax) if external_axes is None: theme.visualize_output() export_data( export, os.path.dirname(os.path.abspath(__file__)), "gdpc", gdp_capita, ) if raw: print_rich_table( gdp.head(20), headers=["Date", "GDP"], show_index=False, title="US GDP Per Capita", ) console.print("")
def display_mentions( ticker: str, start: str, export: str = "", external_axes: Optional[List[plt.Axes]] = None, ): """Plot weekly bars of stock's interest over time. other users watchlist. [Source: Google] Parameters ---------- ticker : str Ticker start : str Start date as YYYY-MM-DD string export: str Format to export data external_axes : Optional[List[plt.Axes]], optional External axes (1 axis is expected in the list), by default None """ df_interest = google_model.get_mentions(ticker) # This plot has 1 axis if external_axes is None: _, 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 (ax, ) = external_axes ax.set_title(f"Interest over time on {ticker}") if start: df_interest = df_interest[start:] # type: ignore ax.bar(df_interest.index, df_interest[ticker], width=2) ax.bar( df_interest.index[-1], df_interest[ticker].values[-1], width=theme.volume_bar_width, ) else: ax.bar(df_interest.index, df_interest[ticker], width=1) ax.bar( df_interest.index[-1], df_interest[ticker].values[-1], width=theme.volume_bar_width, ) ax.set_ylabel("Interest [%]") ax.set_xlim(df_interest.index[0], df_interest.index[-1]) theme.style_primary_axis(ax) if external_axes is None: theme.visualize_output() export_data(export, os.path.dirname(os.path.abspath(__file__)), "mentions", df_interest)
def display_inflation( start_year: int = 2010, raw: bool = False, export: str = "", external_axes: Optional[List[plt.Axes]] = None, ): """Display US Inflation from AlphaVantage Parameters ---------- start_year : int, optional Start year for plot, by default 2010 raw : bool, optional Flag to show raw data, by default False export : str, optional Format to export data, by default "" external_axes : Optional[List[plt.Axes]], optional External axes (1 axis is expected in the list), by default None """ inflation = alphavantage_model.get_inflation() if inflation.empty: console.print("Error getting data. Check API Key") return inf = inflation[inflation.date >= f"{start_year}-01-01"] if external_axes is None: _, ax = plt.subplots(figsize=plot_autoscale(), dpi=cfp.PLOT_DPI) else: if len(external_axes) != 1: logger.error("Expected list of one axis item.") console.print("[red]Expected list of 1 axis item./n[/red]") return (ax, ) = external_axes ax.plot(inf.date, inf.Inflation, marker="o") ax.set_title(f"US Inflation from {list(inf.date)[-1].year}") ax.set_ylabel("Inflation (%)") theme.style_primary_axis(ax) if external_axes is None: theme.visualize_output() export_data( export, os.path.dirname(os.path.abspath(__file__)), "inf", inflation, ) if raw: print_rich_table( inf.head(20), headers=["Date", "Inflation"], show_index=False, title="US Inflation", ) console.print("")
def display_ema_cross( ticker: str, df_stock: pd.DataFrame, short_ema: int, long_ema: int, spy_bt: bool = True, no_bench: bool = False, shortable: bool = True, export: str = "", external_axes: Optional[List[plt.Axes]] = None, ): # pylint: disable=R0913 """Strategy where we go long/short when EMA(short) is greater than/less than EMA(short) Parameters ---------- ticker : str Stock ticker df_stock : pd.Dataframe Dataframe of prices short_ema : int Length of short ema window long_ema : int Length of long ema window spy_bt : bool Boolean to add spy comparison no_bench : bool Boolean to not show buy and hold comparison shortable : bool Boolean to allow for selling of the stock at cross export : str Format to export data external_axes : Optional[List[plt.Axes]], optional External axes (3 axes are expected in the list), by default None """ # 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 (ax, ) = external_axes res = bt_model.ema_cross_strategy(ticker, df_stock, short_ema, long_ema, spy_bt, no_bench, shortable) res.plot(title=f"EMA Cross for EMA({short_ema})/EMA({long_ema})", ax=ax) theme.style_primary_axis(ax) if not external_axes: theme.visualize_output() export_data(export, os.path.dirname(os.path.abspath(__file__)), "ema_cross", res.stats)
def display_regions( ticker: str, num: int = 5, export: str = "", external_axes: Optional[List[plt.Axes]] = None, ): """Plot bars of regions based on stock's interest. [Source: Google] Parameters ---------- ticker : str Ticker num: int Number of regions to show export: str Format to export data external_axes : Optional[List[plt.Axes]], optional External axes (1 axis is expected in the list), by default None """ df_interest_region = google_model.get_regions(ticker) # This plot has 1 axis if external_axes is None: _, 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 (ax, ) = external_axes if df_interest_region.empty: console.print("No region data found.") console.print("") return df_interest_region = df_interest_region.sort_values( [ticker], ascending=False).head(num) df = df_interest_region.sort_values([ticker], ascending=True) ax.set_title(f"Top's regions interest on {ticker}") ax.barh(y=df.index, width=df[ticker], color=theme.get_colors(reverse=True), zorder=3) ax.set_xlabel("Interest [%]") ax.set_ylabel("Region") theme.style_primary_axis(ax) if external_axes is None: theme.visualize_output() export_data(export, os.path.dirname(os.path.abspath(__file__)), "regions", df)
def display_qqplot( name: str, df: pd.DataFrame, target: str, external_axes: Optional[List[plt.Axes]] = None, ): """Show QQ plot for data against normal quantiles Parameters ---------- name : str Stock ticker df : pd.DataFrame Dataframe target : str Column in data to look at external_axes : Optional[List[plt.Axes]], optional External axes (1 axis is expected in the list), by default None """ # Statsmodels has a UserWarning for marker kwarg-- which we don't use warnings.filterwarnings(category=UserWarning, action="ignore") data = df[target] # This plot has 1 axis if external_axes is None: _, 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 1 axis items./n[/red]") return (ax, ) = external_axes qqplot( data, stats.distributions.norm, fit=True, line="45", color=theme.down_color, ax=ax, ) ax.get_lines()[1].set_color(theme.up_color) ax.set_title(f"Q-Q plot for {name} {target}") ax.set_ylabel("Sample quantiles") ax.set_xlabel("Theoretical quantiles") theme.style_primary_axis(ax) if external_axes is None: theme.visualize_output()
def display_btc_confirmed_transactions( since: int, until: int, export: str, external_axes: Optional[List[plt.Axes]] = None, ) -> None: """Returns BTC confirmed transactions [Source: https://api.blockchain.info/] Parameters ---------- since : int Initial date timestamp (e.g., 1_609_459_200) until : int End date timestamp (e.g., 1_641_588_030) 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 """ df = blockchain_model.get_btc_confirmed_transactions() df = df[ (df["x"] > datetime.fromtimestamp(since)) & (df["x"] < datetime.fromtimestamp(until)) ] # This plot has 1 axis if not external_axes: _, ax = plt.subplots(figsize=plot_autoscale(), dpi=PLOT_DPI) else: if len(external_axes) != 1: console.print("[red]Expected list of one axis item./n[/red]") return (ax,) = external_axes ax.plot(df["x"], df["y"], lw=0.8) ax.set_ylabel("Transactions") ax.set_title("BTC Confirmed Transactions") ax.get_yaxis().set_major_formatter( ticker.FuncFormatter(lambda x, _: lambda_long_number_format(x)) ) theme.style_primary_axis(ax) if not external_axes: theme.visualize_output() export_data( export, os.path.dirname(os.path.abspath(__file__)), "btcct", df, )
def display_vol_surface( ticker: str, export: str = "", z: str = "IV", external_axes: Optional[List[plt.Axes]] = None, ): """Display vol surface Parameters ---------- ticker : str Ticker to get surface for export : str Format to export data z : str The variable for the Z axis """ data = yfinance_model.get_iv_surface(ticker) if data.empty: console.print(f"No options data found for {ticker}.\n") return X = data.dte Y = data.strike if z == "IV": Z = data.impliedVolatility label = "Volatility" elif z == "OI": Z = data.openInterest label = "Open Interest" elif z == "LP": Z = data.lastPrice label = "Last Price" if external_axes is None: fig = plt.figure() ax = plt.axes(projection="3d") else: ax = external_axes[0] ax.plot_trisurf(X, Y, Z, cmap="jet", linewidth=0.2) ax.set_xlabel("DTE") ax.set_ylabel("Strike") ax.set_zlabel(z) if external_axes is None: fig.suptitle(f"{label} Surface for {ticker.upper()}") theme.visualize_output(force_tight_layout=False) export_data( export, os.path.dirname(os.path.abspath(__file__)), "vsurf", data, )
def realtime_performance_sector( raw: bool, export: str, external_axes: Optional[List[plt.Axes]] = None, ): """Display Real-Time Performance sector. [Source: AlphaVantage] Parameters ---------- raw : bool Output only raw data 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 """ df_sectors = alphavantage_model.get_sector_data() # pylint: disable=E1101 if df_sectors.empty: return # pylint: disable=invalid-sequence-index df_rtp = df_sectors["Rank A: Real-Time Performance"] df_rtp = df_rtp.apply(lambda x: x * 100) if raw: print_rich_table( df_rtp.to_frame(), show_index=True, headers=["Sector", "Real-Time Performance"], title="Real-Time Performance", ) else: ax = df_rtp.plot(kind="barh") theme.style_primary_axis(ax) ax.set_title("Real Time Performance (%) per Sector") ax.tick_params(axis="x", labelrotation=90) ax.xaxis.set_major_formatter( matplotlib.ticker.FormatStrFormatter("%.2f")) if external_axes is None: theme.visualize_output() export_data( export, os.path.dirname(os.path.abspath(__file__)), "rtps", df_sectors, )
def display_simple_ema( ticker: str, df_stock: pd.DataFrame, ema_length: int, spy_bt: bool = True, no_bench: bool = False, export: str = "", external_axes: Optional[List[plt.Axes]] = None, ): """Strategy where stock is bought when Price > EMA(l) Parameters ---------- ticker : str Stock ticker df_stock : pd.Dataframe Dataframe of prices ema_length : int Length of ema window spy_bt : bool Boolean to add spy comparison no_bench : bool Boolean to not show buy and hold comparison export : bool Format to export backtest results external_axes : Optional[List[plt.Axes]], optional External axes (3 axes are expected in the list), by default None """ # 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 (ax, ) = external_axes res = bt_model.ema_strategy(ticker, df_stock, ema_length, spy_bt, no_bench) res.plot(title=f"Equity for EMA({ema_length})", ax=ax) theme.style_primary_axis(ax) if not external_axes: theme.visualize_output() console.print(res.display(), "\n") export_data(export, os.path.dirname(os.path.abspath(__file__)), "simple_ema", res.stats)
def display_volume( similar_tickers: List[str], start: str = (datetime.now() - timedelta(days=366)).strftime("%Y-%m-%d"), export: str = "", external_axes: Optional[List[plt.Axes]] = None, ): """Display volume stock prices. [Source: Yahoo Finance] Parameters ---------- similar_tickers : List[str] List of similar tickers start : str, optional Start date of comparison, by default 1 year ago export : str, optional Format to export historical prices, by default "" external_axes : Optional[List[plt.Axes]], optional External axes (1 axis is expected in the list), by default None """ df_similar = yahoo_finance_model.get_historical(similar_tickers, start, "v") df_similar = df_similar[similar_tickers] # 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 (ax,) = external_axes df_similar = df_similar.div(1_000_000) companies_names = df_similar.columns.to_list() ax.plot(df_similar, label=companies_names) ax.set_title("Historical volume of similar companies") ax.set_ylabel("Volume [M]") # ensures that the historical data starts from same datapoint ax.set_xlim([df_similar.index[0], df_similar.index[-1]]) ax.legend() theme.style_primary_axis(ax) if not external_axes: theme.visualize_output() export_data( export, os.path.dirname(os.path.abspath(__file__)), "volume", df_similar ) console.print("")
def display_put_call_ratio( ticker: str, window: int = 30, start_date: str = (datetime.now() - timedelta(days=366)).strftime("%Y-%m-%d"), export: str = "", external_axes: Optional[List[plt.Axes]] = None, ): """Display put call ratio [Source: AlphaQuery.com] Parameters ---------- ticker : str Stock ticker window : int, optional Window length to look at, by default 30 start_date : str, optional Starting date for data, by default (datetime.now() - timedelta(days=366)).strftime("%Y-%m-%d") export : str, optional Format to export data, by default "" external_axes : Optional[List[plt.Axes]], optional External axes (1 axis is expected in the list), by default None """ pcr = alphaquery_model.get_put_call_ratio(ticker, window, start_date) if pcr.empty: console.print("No data found.\n") return 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 (ax, ) = external_axes ax.plot(pcr.index, pcr.values) ax.set_title(f"Put Call Ratio for {ticker.upper()}") theme.style_primary_axis(ax) if not external_axes: theme.visualize_output() export_data( export, os.path.dirname(os.path.abspath(__file__)), "pcr", pcr, )
def display_allocation( portfolio: portfolio_model.Portfolio, export: str = "", external_axes: Optional[plt.Axes] = None, ): """Display allocation of assets vs time Parameters ---------- portfolio: Portfolio Portfolio object with trades loaded export: str Format to export plot external_axes: plt.Axes Optional axes to display plot on """ portfolio.generate_holdings_from_trades() all_holdings = pd.concat( [ portfolio.portfolio["StockHoldings"], portfolio.portfolio["ETFHoldings"], portfolio.portfolio["CryptoHoldings"], ], axis=1, ) all_holdings = all_holdings.drop(columns=["temp"]) if external_axes is None: _, ax = plt.subplots(figsize=plot_autoscale(), dpi=PLOT_DPI) else: ax = external_axes all_holdings.plot(ax=ax) ax.set_title("Individual Asset Holdings") if len(all_holdings.columns) > 10: legend_columns = round(len(all_holdings.columns) / 5) elif len(all_holdings.columns) > 40: legend_columns = round(len(all_holdings.columns) / 10) else: legend_columns = 1 ax.legend(loc="upper left", ncol=legend_columns) ax.set_ylabel("Holdings ($)") theme.style_primary_axis(ax) if external_axes is None: theme.visualize_output() export_data( export, os.path.dirname(os.path.abspath(__file__)), "rolling", )
def display_dupont( ticker: str, raw: bool = False, export: str = "", external_axes: Optional[List[plt.Axes]] = None, ): """Shows the extended dupont ratio Parameters ---------- ticker : str Fundamental analysis ticker symbol raw : str Show raw data instead of a graph export : bool Whether to export the dupont breakdown external_axes : Optional[List[plt.Axes]], optional External axes (1 axis is expected in the list), by default None """ df = av_model.get_dupont(ticker) if df.empty: console.print("[red]Invalid response from AlphaVantage[/red]\n") return if raw: print_rich_table(df, headers=list(df.columns), show_index=True, title="Extended Dupont") return 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 (ax, ) = external_axes colors = theme.get_colors() df.transpose().plot(kind="line", ax=ax, color=colors) ax.set_title("Extended Dupont by Year") theme.style_primary_axis(ax) if not external_axes: theme.visualize_output() console.print("") export_data(export, os.path.dirname(os.path.abspath(__file__)), "dupont", df)
def get_plot( data: pd.DataFrame, dataset: str, column: str, export: str = "", external_axes: Optional[List[plt.axes]] = None, ): """Plot data from a dataset Parameters ---------- data: pd.DataFrame Dataframe of custom data dataset: str Dataset name column: str Column for y data export: str Format to export image external_axes:Optional[List[plt.axes]] External axes to plot on """ if isinstance(data.index, pd.MultiIndex): console.print( "The index appears to be a multi-index. " "Therefore, it is not possible to plot the data." ) else: if external_axes is None: _, ax = plt.subplots(figsize=plot_autoscale(), dpi=PLOT_DPI) else: ax = external_axes[0] if isinstance(data, pd.Series): ax.plot(data) elif isinstance(data, pd.DataFrame): ax.plot(data[column]) ax.set_title(f"{column} data from dataset {dataset}") theme.style_primary_axis(ax) if external_axes is None: theme.visualize_output() export_data( export, os.path.dirname(os.path.abspath(__file__)), f"{column}_{dataset}_plot", )