def ark_orders(l_args): parser = argparse.ArgumentParser( add_help=False, prog="ARK Orders", description=""" Orders by ARK Investment Management LLC - https://ark-funds.com/. [Source: https://cathiesark.com] """, ) parser.add_argument( "-n", "--num", action="store", dest="n_num", type=check_positive, default=20, help="Last N orders.", ) ns_parser = parse_known_args_and_warn(parser, l_args) if not ns_parser: return df_orders = get_ark_orders() if df_orders.empty: print("The ARK orders aren't anavilable at the moment.\n") return pd.set_option("mode.chained_assignment", None) df_orders = add_order_total(df_orders.head(ns_parser.n_num)) if gtff.USE_COLOR: df_orders["direction"] = df_orders["direction"].apply( direction_color_red_green) patch_pandas_text_adjustment() df_orders[ "link"] = "https://finviz.com/quote.ashx?t=" + df_orders["ticker"] pd.set_option("display.max_colwidth", None) pd.set_option("display.max_rows", None) pd.set_option("display.float_format", "{:,.2f}".format) print("") print("Orders by ARK Investment Management LLC") print("") print(df_orders.to_string(index=False)) print("")
def display_cashflow_comparison( similar: List[str], timeframe: str, quarter: bool = False, export: str = "", ): """Compare cashflow between companies. [Source: Marketwatch] Parameters ---------- ticker : str Main ticker to compare income similar : List[str] Similar companies to compare income with timeframe : str Whether to use quarterly or annual quarter : bool, optional Whether to use quarterly statements, by default False export : str, optional Format to export data """ df_financials_compared = marketwatch_model.get_financial_comparisons( similar, "cashflow", timeframe, quarter) # Export data before the color export_data( export, os.path.dirname(os.path.abspath(__file__)), "cashflow", df_financials_compared, ) if gtff.USE_COLOR: df_financials_compared = df_financials_compared.applymap( financials_colored_values) patch_pandas_text_adjustment() if not quarter: df_financials_compared.index.name = timeframe print_rich_table( df_financials_compared, headers=list(df_financials_compared.columns), show_index=True, title="Cashflow Comparison", ) console.print("")
def display_income_comparison( similar: List[str], timeframe: str, quarter: bool = False, export: str = "", ): """Display income data. [Source: Marketwatch] Parameters ---------- similar : List[str] List of tickers to compare timeframe : str Whether to use quarterly or annual quarter : bool, optional Whether to use quarterly statements, by default False export : str, optional Format to export data """ df_financials_compared = marketwatch_model.get_financial_comparisons( similar, "income", timeframe, quarter ) # Export data before the color export_data( export, os.path.dirname(os.path.abspath(__file__)), "income", df_financials_compared, ) if rich_config.USE_COLOR: df_financials_compared = df_financials_compared.applymap( lambda_financials_colored_values ) patch_pandas_text_adjustment() if not quarter: df_financials_compared.index.name = timeframe print_rich_table( df_financials_compared, headers=list(df_financials_compared.columns), show_index=True, title="Income Data", ) console.print("")
def analyst(l_args, s_ticker): parser = argparse.ArgumentParser( add_help=False, prog="analyst", description=""" Print analyst prices and ratings of the company. The following fields are expected: date, analyst, category, price from, price to, and rating. [Source: Finviz] """, ) parser.add_argument( "-c", "--color", action="store", dest="n_color", type=int, choices=[0, 1], default=1, help="Add / remove color", ) try: ns_parser = parse_known_args_and_warn(parser, l_args) if not ns_parser: return df_fa = analyst_df(s_ticker) if ns_parser.n_color == 1: df_fa["category"] = df_fa["category"].apply( category_color_red_green) patch_pandas_text_adjustment() print(df_fa) print("") except Exception as e: print(e) print("") return
def k_nearest_neighbors(l_args, s_ticker, df_stock): parser = argparse.ArgumentParser( add_help=False, prog="knn", description=""" K nearest neighbors is a simple algorithm that stores all available cases and predict the numerical target based on a similarity measure (e.g. distance functions). """, ) parser.add_argument( "-i", "--input", action="store", dest="n_inputs", type=check_positive, default=40, help="number of days to use for prediction.", ) parser.add_argument( "-d", "--days", action="store", dest="n_days", type=check_positive, default=5, help="prediction days.", ) parser.add_argument( "-j", "--jumps", action="store", dest="n_jumps", type=check_positive, default=1, help="number of jumps in training data.", ) parser.add_argument( "-n", "--neighbors", action="store", dest="n_neighbors", type=check_positive, default=20, help="number of neighbors to use on the algorithm.", ) parser.add_argument( "-e", "--end", action="store", type=valid_date, dest="s_end_date", default=None, help="The end date (format YYYY-MM-DD) to select - Backtesting", ) try: ns_parser = parse_known_args_and_warn(parser, l_args) if not ns_parser: return # BACKTESTING if ns_parser.s_end_date: if ns_parser.s_end_date < df_stock.index[0]: print( "Backtesting not allowed, since End Date is older than Start Date of historical data\n" ) return if ns_parser.s_end_date < get_next_stock_market_days( last_stock_day=df_stock.index[0], n_next_days=ns_parser.n_inputs + ns_parser.n_days, )[-1]: print( "Backtesting not allowed, since End Date is too close to Start Date to train model\n" ) return future_index = get_next_stock_market_days( last_stock_day=ns_parser.s_end_date, n_next_days=ns_parser.n_days) if future_index[-1] > datetime.datetime.now(): print( "Backtesting not allowed, since End Date + Prediction days is in the future\n" ) return df_future = df_stock[future_index[0]:future_index[-1]] df_stock = df_stock[:ns_parser.s_end_date] # Split training data stock_x, stock_y = splitTrain.split_train( df_stock["5. adjusted close"].values, ns_parser.n_inputs, ns_parser.n_days, ns_parser.n_jumps, ) if not stock_x: print("Given the model parameters more training data is needed.\n") return # Machine Learning model knn = neighbors.KNeighborsRegressor(n_neighbors=ns_parser.n_neighbors) knn.fit(stock_x, stock_y) # Prediction data l_predictions = knn.predict( df_stock["5. adjusted close"].values[-ns_parser.n_inputs:].reshape( 1, -1))[0] l_pred_days = get_next_stock_market_days( last_stock_day=df_stock["5. adjusted close"].index[-1], n_next_days=ns_parser.n_days, ) df_pred = pd.Series(l_predictions, index=l_pred_days, name="Price") # Plotting plt.figure(figsize=plot_autoscale(), dpi=PLOT_DPI) plt.plot(df_stock.index, df_stock["5. adjusted close"], lw=2) s_knn = f"{ns_parser.n_neighbors}-Nearest Neighbors on {s_ticker}" # BACKTESTING if ns_parser.s_end_date: plt.title( f"BACKTESTING: {s_knn} - {ns_parser.n_days} days prediction") else: plt.title(f"{s_knn} - {ns_parser.n_days} days prediction") plt.xlim(df_stock.index[0], get_next_stock_market_days(df_pred.index[-1], 1)[-1]) plt.xlabel("Time") plt.ylabel("Share Price ($)") plt.grid(b=True, which="major", color="#666666", linestyle="-") plt.minorticks_on() plt.grid(b=True, which="minor", color="#999999", linestyle="-", alpha=0.2) plt.plot( [df_stock.index[-1], df_pred.index[0]], [df_stock["5. adjusted close"].values[-1], df_pred.values[0]], lw=1, c="tab:green", linestyle="--", ) plt.plot(df_pred.index, df_pred, lw=2, c="tab:green") plt.axvspan(df_stock.index[-1], df_pred.index[-1], facecolor="tab:orange", alpha=0.2) _, _, ymin, ymax = plt.axis() plt.vlines(df_stock.index[-1], ymin, ymax, linewidth=1, linestyle="--", color="k") # BACKTESTING if ns_parser.s_end_date: plt.plot( df_future.index, df_future["5. adjusted close"], lw=2, c="tab:blue", ls="--", ) plt.plot( [df_stock.index[-1], df_future.index[0]], [ df_stock["5. adjusted close"].values[-1], df_future["5. adjusted close"].values[0], ], lw=1, c="tab:blue", linestyle="--", ) if gtff.USE_ION: plt.ion() plt.show() # BACKTESTING if ns_parser.s_end_date: plt.figure(figsize=plot_autoscale(), dpi=PLOT_DPI) plt.subplot(211) plt.plot( df_future.index, df_future["5. adjusted close"], lw=2, c="tab:blue", ls="--", ) plt.plot(df_pred.index, df_pred, lw=2, c="green") plt.scatter(df_future.index, df_future["5. adjusted close"], c="tab:blue", lw=3) plt.plot( [df_stock.index[-1], df_future.index[0]], [ df_stock["5. adjusted close"].values[-1], df_future["5. adjusted close"].values[0], ], lw=2, c="tab:blue", ls="--", ) plt.scatter(df_pred.index, df_pred, c="green", lw=3) plt.plot( [df_stock.index[-1], df_pred.index[0]], [df_stock["5. adjusted close"].values[-1], df_pred.values[0]], lw=2, c="green", ls="--", ) plt.title("BACKTESTING: Real data price versus Prediction") plt.xlim(df_stock.index[-1], df_pred.index[-1] + datetime.timedelta(days=1)) plt.xticks([ df_stock.index[-1], df_pred.index[-1] + datetime.timedelta(days=1) ]) plt.ylabel("Share Price ($)") plt.grid(b=True, which="major", color="#666666", linestyle="-") plt.minorticks_on() plt.grid(b=True, which="minor", color="#999999", linestyle="-", alpha=0.2) plt.legend(["Real data", "Prediction data"]) plt.xticks([]) plt.subplot(212) plt.axhline(y=0, color="k", linestyle="--", linewidth=2) plt.plot( df_future.index, 100 * (df_pred.values - df_future["5. adjusted close"].values) / df_future["5. adjusted close"].values, lw=2, c="red", ) plt.scatter( df_future.index, 100 * (df_pred.values - df_future["5. adjusted close"].values) / df_future["5. adjusted close"].values, c="red", lw=5, ) plt.title( "BACKTESTING: Error between Real data and Prediction [%]") plt.plot( [df_stock.index[-1], df_future.index[0]], [ 0, 100 * (df_pred.values[0] - df_future["5. adjusted close"].values[0]) / df_future["5. adjusted close"].values[0], ], lw=2, ls="--", c="red", ) plt.xlim(df_stock.index[-1], df_pred.index[-1] + datetime.timedelta(days=1)) plt.xticks([ df_stock.index[-1], df_pred.index[-1] + datetime.timedelta(days=1) ]) plt.xlabel("Time") plt.ylabel("Prediction Error (%)") plt.grid(b=True, which="major", color="#666666", linestyle="-") plt.minorticks_on() plt.grid(b=True, which="minor", color="#999999", linestyle="-", alpha=0.2) plt.legend(["Real data", "Prediction data"]) if gtff.USE_ION: plt.ion() plt.show() # Refactor prediction dataframe for backtesting print df_pred.name = "Prediction" df_pred = df_pred.to_frame() df_pred["Real"] = df_future["5. adjusted close"] if gtff.USE_COLOR: patch_pandas_text_adjustment() print("Time Real [$] x Prediction [$]") print( df_pred.apply(price_prediction_backtesting_color, axis=1).to_string()) else: print(df_pred[["Real", "Prediction"]].round(2).to_string()) print("") print_prediction_kpis(df_pred["Real"].values, df_pred["Prediction"].values) else: # Print prediction data print_pretty_prediction(df_pred, df_stock["5. adjusted close"].values[-1]) print("") except Exception as e: print(e) print("")
def display_chains( ticker: str, expiry: str, to_display: List[str], min_sp: float, max_sp: float, calls_only: bool, puts_only: bool, export: str = "", ): """Display option chain Parameters ---------- ticker: str Stock ticker expiry: str Expiration date of option to_display: List[str] List of columns to display min_sp: float Min strike price to display max_sp: float Max strike price to display calls_only: bool Only display calls puts_only: bool Only display puts export: str Format to export file """ chains_df = tradier_model.get_option_chains(ticker, expiry) columns = to_display + ["strike", "option_type"] chains_df = chains_df[columns].rename(columns=column_map) if min_sp == -1: min_strike = np.percentile(chains_df["strike"], 25) else: min_strike = min_sp if max_sp == -1: max_strike = np.percentile(chains_df["strike"], 75) else: max_strike = max_sp chains_df = chains_df[chains_df["strike"] >= min_strike] chains_df = chains_df[chains_df["strike"] <= max_strike] calls_df = chains_df[chains_df.option_type == "call"].drop(columns=["option_type"]) puts_df = chains_df[chains_df.option_type == "put"].drop(columns=["option_type"]) df = calls_df if calls_only else puts_df if calls_only or puts_only: print_rich_table( df, headers=[x.title() for x in df.columns], show_index=False, title=f"The strike prices are displayed between {min_strike} and {max_strike}", ) else: puts_df = puts_df[puts_df.columns[::-1]] chain_table = calls_df.merge(puts_df, on="strike") if gtff.USE_COLOR: call_cols = [col for col in chain_table if col.endswith("_x")] put_cols = [col for col in chain_table if col.endswith("_y")] patch_pandas_text_adjustment() pd.set_option("display.max_colwidth", 0) pd.set_option("display.max_rows", None) for cc in call_cols: chain_table[cc] = chain_table[cc].astype(str).apply(green_highlight) for pc in put_cols: chain_table[pc] = chain_table[pc].astype(str).apply(red_highlight) headers = [ col.strip("_x") if col.endswith("_x") else col.strip("_y") if col.endswith("_y") else col for col in chain_table.columns ] print_rich_table( chain_table, headers=headers, show_index=False, title="Option chain" ) export_data( export, os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "chains", chains_df, )
def fbprophet(l_args, s_ticker, df_stock): parser = argparse.ArgumentParser( add_help=False, prog="fbprophet", description=""" Facebook Prophet is a forecasting procedure that is fast and provides completely automated forecasts that can be tuned by hand by data scientists and analysts. It was developed by Facebook's data science team and is open source. """, ) parser.add_argument( "-d", "--days", action="store", dest="n_days", type=check_positive, default=5, help="prediction days", ) parser.add_argument( "-e", "--end", action="store", type=valid_date, dest="s_end_date", default=None, help="The end date (format YYYY-MM-DD) to select - Backtesting", ) try: ns_parser = parse_known_args_and_warn(parser, l_args) if not ns_parser: return # BACKTESTING if ns_parser.s_end_date: if ns_parser.s_end_date < df_stock.index[0]: print( "Backtesting not allowed, since End Date is older than Start Date of historical data\n" ) return if (ns_parser.s_end_date < get_next_stock_market_days( last_stock_day=df_stock.index[0], n_next_days=5 + ns_parser.n_days)[-1]): print( "Backtesting not allowed, since End Date is too close to Start Date to train model\n" ) return future_index = get_next_stock_market_days( last_stock_day=ns_parser.s_end_date, n_next_days=ns_parser.n_days) if future_index[-1] > datetime.datetime.now(): print( "Backtesting not allowed, since End Date + Prediction days is in the future\n" ) return df_future = df_stock[future_index[0]:future_index[-1]] df_stock = df_stock[:ns_parser.s_end_date] df_stock = df_stock.sort_index(ascending=True) df_stock.reset_index(level=0, inplace=True) df_stock = df_stock[["date", "5. adjusted close"]] df_stock = df_stock.rename(columns={ "date": "ds", "5. adjusted close": "y" }) df_stock["ds"] = pd.to_datetime(df_stock["ds"]) model = Prophet(yearly_seasonality=False, daily_seasonality=False) model.fit(df_stock) l_pred_days = get_next_stock_market_days( last_stock_day=pd.to_datetime(df_stock["ds"].values[-1]), n_next_days=ns_parser.n_days, ) close_prices = model.make_future_dataframe(periods=ns_parser.n_days) forecast = model.predict(close_prices) df_pred = forecast["yhat"][ -ns_parser.n_days:] # .apply(lambda x: f"{x:.2f} $") df_pred.index = l_pred_days _, ax = plt.subplots(figsize=plot_autoscale(), dpi=PLOT_DPI) model.plot( forecast[:-ns_parser.n_days], ax=ax, xlabel="Time", ylabel="Share Price ($)", ) _, _, ymin, ymax = ax.axis() ax.vlines( df_stock["ds"].values[-1], ymin, ymax, linewidth=2, linestyle="--", color="k", ) plt.axvspan( df_stock["ds"].values[-1], l_pred_days[-1], facecolor="tab:orange", alpha=0.2, ) plt.ylim(ymin, ymax) plt.xlim(df_stock["ds"].values[0], get_next_stock_market_days(l_pred_days[-1], 1)[-1]) # BACKTESTING if ns_parser.s_end_date: plt.title( f"BACKTESTING: Fb Prophet on {s_ticker} - {ns_parser.n_days} days prediction" ) else: plt.title( f"Fb Prophet on {s_ticker} - {ns_parser.n_days} days prediction" ) # BACKTESTING if ns_parser.s_end_date: plt.plot( df_future.index, df_future["5. adjusted close"], lw=2, c="tab:blue", ls="--", ) plt.plot( [df_stock["ds"].values[-1], df_future.index[0]], [ df_stock["y"].values[-1], df_future["5. adjusted close"].values[0], ], lw=1, c="tab:blue", linestyle="--", ) plt.plot(df_pred.index, df_pred.values, lw=2, c="green") if gtff.USE_ION: plt.ion() plt.show() # BACKTESTING if ns_parser.s_end_date: plt.figure(figsize=plot_autoscale(), dpi=PLOT_DPI) plt.subplot(211) plt.plot( df_future.index, df_future["5. adjusted close"], lw=2, c="tab:blue", ls="--", ) plt.plot(df_pred.index, df_pred, lw=2, c="green") plt.scatter( df_future.index, df_future["5. adjusted close"], c="tab:blue", lw=3, ) plt.plot( [df_stock["ds"].values[-1], df_future.index[0]], [ df_stock["y"].values[-1], df_future["5. adjusted close"].values[0], ], lw=2, c="tab:blue", ls="--", ) plt.scatter(df_pred.index, df_pred, c="green", lw=3) plt.plot( [df_stock["ds"].values[-1], df_pred.index[0]], [df_stock["y"].values[-1], df_pred.values[0]], lw=2, c="green", ls="--", ) plt.title("BACKTESTING: Real data price versus Prediction") plt.xlim( df_stock["ds"].values[-1], df_pred.index[-1] + datetime.timedelta(days=1), ) plt.ylabel("Share Price ($)") plt.grid(b=True, which="major", color="#666666", linestyle="-") plt.minorticks_on() plt.grid(b=True, which="minor", color="#999999", linestyle="-", alpha=0.2) plt.legend(["Real data", "Prediction data"]) plt.xticks([]) plt.subplot(212) plt.axhline(y=0, color="k", linestyle="--", linewidth=2) plt.plot( df_future.index, 100 * (df_pred.values - df_future["5. adjusted close"].values) / df_future["5. adjusted close"].values, lw=2, c="red", ) plt.scatter( df_future.index, 100 * (df_pred.values - df_future["5. adjusted close"].values) / df_future["5. adjusted close"].values, c="red", lw=5, ) plt.title( "BACKTESTING: Error between Real data and Prediction [%]") plt.plot( [df_stock["ds"].values[-1], df_future.index[0]], [ 0, 100 * (df_pred.values[0] - df_future["5. adjusted close"].values[0]) / df_future["5. adjusted close"].values[0], ], lw=2, ls="--", c="red", ) plt.xlim( df_stock["ds"].values[-1], df_pred.index[-1] + datetime.timedelta(days=1), ) plt.xlabel("Time") plt.ylabel("Prediction Error (%)") plt.grid(b=True, which="major", color="#666666", linestyle="-") plt.minorticks_on() plt.grid(b=True, which="minor", color="#999999", linestyle="-", alpha=0.2) plt.legend(["Real data", "Prediction data"]) if gtff.USE_ION: plt.ion() plt.show() # Refactor prediction dataframe for backtesting print df_pred.name = "Prediction" df_pred = df_pred.to_frame() df_pred["Real"] = df_future["5. adjusted close"] if gtff.USE_COLOR: patch_pandas_text_adjustment() print("Time Real [$] x Prediction [$]") print( df_pred.apply(price_prediction_backtesting_color, axis=1).to_string()) else: print(df_pred[["Real", "Prediction"]].round(2).to_string()) print("") print_prediction_kpis(df_pred["Real"].values, df_pred["Prediction"].values) else: print("") print("Predicted share price:") print(df_pred.to_string()) print("") except Exception as e: print(e) print("")
def _plot_and_print_results( df_stock, ns_parser, df_future, df_pred, model_name, s_ticker ): """Plot and print the results. """ # Plotting plt.figure(figsize=plot_autoscale(), dpi=PLOT_DPI) plt.plot(df_stock.index, df_stock["5. adjusted close"], lw=3) # BACKTESTING if ns_parser.n_loops == 1: if ns_parser.s_end_date: plt.title( f"BACKTESTING: {model_name} on {s_ticker} - {ns_parser.n_days} days prediction" ) else: plt.title( f"{model_name} on {s_ticker} - {ns_parser.n_days} days prediction" ) else: if ns_parser.s_end_date: plt.title( f"{ns_parser.n_loops} loops - BACKTESTING: {model_name} on {s_ticker}" f" - {ns_parser.n_days} days prediction" ) else: plt.title( f"{ns_parser.n_loops} loops - {model_name} on {s_ticker} - {ns_parser.n_days} days prediction" ) plt.xlim(df_stock.index[0], get_next_stock_market_days(df_pred.index[-1], 1)[-1]) plt.xlabel("Time") plt.ylabel("Share Price ($)") plt.grid(b=True, which="major", color="#666666", linestyle="-") plt.minorticks_on() plt.grid(b=True, which="minor", color="#999999", linestyle="-", alpha=0.2) if ns_parser.n_loops == 1: plt.plot( [df_stock.index[-1], df_pred.index[0]], [ df_stock["5. adjusted close"].values[-1], df_pred[df_pred.columns[0]].values[0], ], lw=1, c="tab:green", linestyle="--", ) plt.plot(df_pred.index, df_pred[df_pred.columns[0]], lw=2, c="tab:green") else: df_quantiles = pd.DataFrame() df_quantiles["Quantile 10%"] = df_pred.quantile(0.1, axis=1) df_quantiles["Median"] = df_pred.quantile(0.5, axis=1) df_quantiles["Quantile 90%"] = df_pred.quantile(0.9, axis=1) plt.plot(df_pred.index, df_quantiles["Median"], lw=2, c="tab:green") plt.fill_between( df_pred.index, df_quantiles["Quantile 10%"], df_quantiles["Quantile 90%"], alpha=0.30, color="tab:green", interpolate=True, ) plt.fill_between( [df_stock.index[-1], df_pred.index[0]], [ df_stock["5. adjusted close"].values[-1], df_quantiles["Quantile 10%"].values[0], ], [ df_stock["5. adjusted close"].values[-1], df_quantiles["Quantile 90%"].values[0], ], alpha=0.30, color="tab:green", interpolate=True, ) plt.axvspan( df_stock.index[-1], df_pred.index[-1], facecolor="tab:orange", alpha=0.2 ) _, _, ymin, ymax = plt.axis() plt.vlines( df_stock.index[-1], ymin, ymax, colors="k", linewidth=3, linestyle="--", color="k", ) # BACKTESTING if ns_parser.s_end_date: plt.plot( df_future.index, df_future["5. adjusted close"], lw=2, c="tab:blue", ls="--", ) plt.plot( [df_stock.index[-1], df_future.index[0]], [ df_stock["5. adjusted close"].values[-1], df_future["5. adjusted close"].values[0], ], lw=1, c="tab:blue", linestyle="--", ) if gtff.USE_ION: plt.ion() plt.show() # BACKTESTING if ns_parser.s_end_date: plt.figure(figsize=plot_autoscale(), dpi=PLOT_DPI) plt.subplot(211) plt.plot( df_future.index, df_future["5. adjusted close"], lw=2, c="tab:blue", ls="--", ) if ns_parser.n_loops == 1: plt.plot(df_pred.index, df_pred, lw=2, c="green") else: plt.plot( df_quantiles["Median"].index, df_quantiles["Median"], lw=2, c="green" ) plt.scatter(df_future.index, df_future["5. adjusted close"], c="tab:blue", lw=3) plt.plot( [df_stock.index[-1], df_future.index[0]], [ df_stock["5. adjusted close"].values[-1], df_future["5. adjusted close"].values[0], ], lw=2, c="tab:blue", ls="--", ) if ns_parser.n_loops == 1: plt.scatter(df_pred.index, df_pred, c="green", lw=3) plt.plot( [df_stock.index[-1], df_pred.index[0]], [df_stock["5. adjusted close"].values[-1], df_pred.values[0]], lw=2, c="green", ls="--", ) else: plt.scatter( df_quantiles["Median"].index, df_quantiles["Median"], lw=3, c="green" ) plt.plot( [df_stock.index[-1], df_quantiles["Median"].index[0]], [ df_stock["5. adjusted close"].values[-1], df_quantiles["Median"].values[0], ], lw=2, c="green", ls="--", ) plt.fill_between( df_pred.index, df_quantiles["Quantile 10%"], df_quantiles["Quantile 90%"], alpha=0.30, color="tab:green", interpolate=True, ) plt.title("BACKTESTING: Real data price versus Prediction") plt.xlim(df_stock.index[-1], df_pred.index[-1] + datetime.timedelta(days=1)) plt.xticks( [df_stock.index[-1], df_pred.index[-1] + datetime.timedelta(days=1)], visible=True, ) plt.ylabel("Share Price ($)") plt.grid(b=True, which="major", color="#666666", linestyle="-") plt.minorticks_on() plt.grid(b=True, which="minor", color="#999999", linestyle="-", alpha=0.2) plt.legend(["Real data", "Prediction data"]) plt.xticks([]) plt.subplot(212) plt.axhline(y=0, color="k", linestyle="--", linewidth=2) if ns_parser.n_loops == 1: plt.plot( df_future.index, 100 * ( df_pred[df_pred.columns[0]].values - df_future["5. adjusted close"].values ) / df_future["5. adjusted close"].values, lw=2, c="red", ) plt.scatter( df_future.index, 100 * ( df_pred[df_pred.columns[0]].values - df_future["5. adjusted close"].values ) / df_future["5. adjusted close"].values, c="red", lw=5, ) plt.plot( [df_stock.index[-1], df_future.index[0]], [ 0, 100 * ( df_pred[df_pred.columns[0]].values[0] - df_future["5. adjusted close"].values[0] ) / df_future["5. adjusted close"].values[0], ], lw=2, ls="--", c="red", ) else: plt.plot( df_future.index, 100 * ( df_quantiles["Median"].values - df_future["5. adjusted close"].values ) / df_future["5. adjusted close"].values, lw=2, c="red", ) plt.scatter( df_future.index, 100 * ( df_quantiles["Median"].values - df_future["5. adjusted close"].values ) / df_future["5. adjusted close"].values, c="red", lw=5, ) plt.plot( [df_stock.index[-1], df_future.index[0]], [ 0, 100 * ( df_quantiles["Median"].values[0] - df_future["5. adjusted close"].values[0] ) / df_future["5. adjusted close"].values[0], ], lw=2, ls="--", c="red", ) plt.fill_between( df_pred.index, 100 * ( df_quantiles["Quantile 10%"].values - df_future["5. adjusted close"].values ) / df_future["5. adjusted close"].values, 100 * ( df_quantiles["Quantile 90%"].values - df_future["5. adjusted close"].values ) / df_future["5. adjusted close"].values, alpha=0.30, color="red", interpolate=True, ) plt.title("BACKTESTING: Error between Real data and Prediction [%]") plt.xlim(df_stock.index[-1], df_pred.index[-1] + datetime.timedelta(days=1)) plt.xticks( [df_stock.index[-1], df_pred.index[-1] + datetime.timedelta(days=1)], visible=True, ) plt.xlabel("Time") plt.ylabel("Prediction Error (%)") plt.grid(b=True, which="major", color="#666666", linestyle="-") plt.minorticks_on() plt.grid(b=True, which="minor", color="#999999", linestyle="-", alpha=0.2) plt.legend(["Real data", "Prediction data"]) if gtff.USE_ION: plt.ion() plt.show() # Refactor prediction dataframe for backtesting print if ns_parser.n_loops == 1: df_pred.rename(columns={df_pred.columns[0]: "Prediction"}, inplace=True) else: df_pred = pd.DataFrame() df_pred["Prediction"] = df_quantiles["Median"] df_pred["Real"] = df_future["5. adjusted close"] if gtff.USE_COLOR: patch_pandas_text_adjustment() print("Time Real [$] x Prediction [$]") print(df_pred.apply(price_prediction_backtesting_color, axis=1).to_string()) else: print(df_pred[["Real", "Prediction"]].round(2).to_string()) print("") print_prediction_kpis(df_pred["Real"].values, df_pred["Prediction"].values) print("") else: patch_pandas_text_adjustment() # Print prediction data print_pretty_prediction_nn(df_pred, df_stock["5. adjusted close"].values[-1]) print("") if ns_parser.n_loops > 1: print("Prediction Stats:") print(df_quantiles.round(2).to_string()) print("")
def compare_cashflow(other_args: List[str], ticker: str, similar: List[str]): """Compare balance between companies Parameters ---------- other_args : List[str] Command line arguments to be processed with argparse ticker : str Main ticker to compare income similar : List[str] Similar companies to compare income with """ parser = argparse.ArgumentParser( add_help=False, prog="compare_cashflow", description=""" Prints either yearly or quarterly cash statement the company, and compares it against similar companies. [Source: Market Watch] """, ) parser.add_argument( "-s", "--similar", dest="l_similar", type=lambda s: [str(item).upper() for item in s.split(",")], default=similar, help="similar companies to compare with.", ) parser.add_argument( "-a", "--also", dest="l_also", type=lambda s: [str(item).upper() for item in s.split(",")], default=[], help="apart from loaded similar companies also compare with.", ) parser.add_argument( "-q", "--quarter", action="store_true", default=False, dest="b_quarter", help="Quarter financial data flag.", ) parser.add_argument( "-t", "--timeframe", dest="s_timeframe", type=str, default=None, help="Specify yearly/quarterly timeframe. Default is last.", ) try: ns_parser = parse_known_args_and_warn(parser, other_args) if not ns_parser: return l_similar = ns_parser.l_similar l_similar += ns_parser.l_also # Add main ticker to similar list of companies l_similar.insert(0, ticker) l_timeframes, ddf_financials = prepare_comparison_financials( l_similar, "cashflow", ns_parser.b_quarter) if ns_parser.s_timeframe: if ns_parser.s_timeframe not in l_timeframes: raise ValueError( f"Timeframe selected should be one of {', '.join(l_timeframes)}" ) s_timeframe = ns_parser.s_timeframe else: s_timeframe = l_timeframes[-1] print( f"Other available {('yearly', 'quarterly')[ns_parser.b_quarter]} timeframes are: {', '.join(l_timeframes)}\n" ) df_financials_compared = combine_similar_financials( ddf_financials, l_similar, s_timeframe, ns_parser.b_quarter) if gtff.USE_COLOR: df_financials_compared = df_financials_compared.applymap( financials_colored_values) patch_pandas_text_adjustment() pd.set_option("display.max_colwidth", None) pd.set_option("display.max_rows", None) if not ns_parser.b_quarter: df_financials_compared.index.name = s_timeframe print(df_financials_compared.to_string()) print("") except Exception as e: print(e, "\n") return
def balance(other_args: List[str], ticker: str): """Market Watch ticker balance statement Parameters ---------- other_args : List[str] argparse other args ticker : str Fundamental analysis ticker symbol """ parser = argparse.ArgumentParser( add_help=False, formatter_class=argparse.ArgumentDefaultsHelpFormatter, prog="balance", description=""" Prints either yearly or quarterly assets from balance sheet of the company. The following fields are expected: Cash & Short Term Investments, Cash & Short Term Investments Growth, Cash Only, Short-Term Investments, Cash & ST Investments / Total Assets, Total Accounts Receivable, Total Accounts Receivable Growth, Accounts Receivables, Net, Accounts Receivables, Gross, Bad Debt/Doubtful Accounts, Other Receivable, Accounts Receivable Turnover, Inventories, Finished Goods, Work in Progress, Raw Materials, Progress Payments & Other, Other Current Assets, Miscellaneous Current Assets, Net Property, Plant & Equipment, Property, Plant & Equipment - Gross, Buildings, Land & Improvements, Computer Software and Equipment, Other Property, Plant & Equipment, Accumulated Depreciation, Total Investments and Advances, Other Long-Term Investments, Long-Term Note Receivables, Intangible Assets, Net Goodwill, Net Other Intangibles, Other Assets. Prints either yearly or quarterly liabilities and shareholders' equity from balance sheet of the company. The following fields are expected: ST Debt & Current Portion LT Debt, Short Term Debt, Current Portion of Long Term Debt, Accounts Payable, Accounts Payable Growth, Income Tax Payable, Other Current Liabilities, Dividends Payable, Accrued Payroll, Miscellaneous Current Liabilities, Long-Term Debt, Long-Term Debt excl. Capitalized Leases, Non-Convertible Debt, Convertible Debt, Capitalized Lease Obligations, Provision for Risks & Charges, Deferred Taxes, Deferred Taxes - Credits, Deferred Taxes - Debit, Other Liabilities, Other Liabilities (excl. Deferred Income), Deferred Income, Non-Equity Reserves, Total Liabilities / Total Assets, Preferred Stock (Carrying Value), Redeemable Preferred Stock, Non-Redeemable Preferred Stock, Common Equity (Total), Common Equity/Total Assets, Common Stock Par/Carry Value, Retained Earnings, ESOP Debt Guarantee, Cumulative Translation Adjustment/Unrealized For. Exch. Gain, Unrealized Gain/Loss Marketable Securities, Revaluation Reserves, Treasury Stock, Total Shareholders' Equity, Total Shareholders' Equity / Total Assets, Accumulated Minority Interest, Total Equity, Total Current Assets, Total Assets, Total Current Liabilities, Total Liabilities, and Liabilities & Shareholders' Equity. [Source: Market Watch] """, ) parser.add_argument( "-q", "--quarter", action="store_true", default=False, dest="b_quarter", help="Quarter fundamental data flag.", ) ns_parser = parse_known_args_and_warn(parser, other_args) if not ns_parser: return df_financials = mwm.prepare_df_financials(ticker, "balance", ns_parser.b_quarter) if gtff.USE_COLOR: df_financials = df_financials.applymap(financials_colored_values) patch_pandas_text_adjustment() pd.set_option("display.max_colwidth", None) pd.set_option("display.max_rows", None) if df_financials.empty: print("Marketwatch does not yet provide financials for this ticker") else: print(df_financials.to_string(index=False)) print("")
def regression(l_args, s_ticker, df_stock, polynomial): parser = argparse.ArgumentParser( add_help=False, prog="regression", description=""" Regression attempts to model the relationship between two variables by fitting a linear/quadratic/cubic/other equation to observed data. One variable is considered to be an explanatory variable, and the other is considered to be a dependent variable. """, ) parser.add_argument( "-i", "--input", action="store", dest="n_inputs", type=check_positive, default=40, help="number of days to use for prediction.", ) parser.add_argument( "-d", "--days", action="store", dest="n_days", type=check_positive, default=5, help="prediction days.", ) parser.add_argument( "-j", "--jumps", action="store", dest="n_jumps", type=check_positive, default=1, help="number of jumps in training data.", ) parser.add_argument( "-e", "--end", action="store", type=valid_date, dest="s_end_date", default=None, help="The end date (format YYYY-MM-DD) to select - Backtesting", ) if polynomial == USER_INPUT: parser.add_argument( "-p", "--polynomial", action="store", dest="n_polynomial", type=check_positive, required=True, help="polynomial associated with regression.", ) try: ns_parser = parse_known_args_and_warn(parser, l_args) if not ns_parser: return # BACKTESTING if ns_parser.s_end_date: if ns_parser.s_end_date < df_stock.index[0]: print( "Backtesting not allowed, since End Date is older than Start Date of historical data\n" ) return if ns_parser.s_end_date < get_next_stock_market_days( last_stock_day=df_stock.index[0], n_next_days=ns_parser.n_inputs + ns_parser.n_days, )[-1]: print( "Backtesting not allowed, since End Date is too close to Start Date to train model\n" ) return future_index = get_next_stock_market_days( last_stock_day=ns_parser.s_end_date, n_next_days=ns_parser.n_days) if future_index[-1] > datetime.datetime.now(): print( "Backtesting not allowed, since End Date + Prediction days is in the future\n" ) return df_future = df_stock[future_index[0]:future_index[-1]] df_stock = df_stock[:ns_parser.s_end_date] # Split training data stock_x, stock_y = splitTrain.split_train( df_stock["5. adjusted close"].values, ns_parser.n_inputs, ns_parser.n_days, ns_parser.n_jumps, ) if not stock_x: print("Given the model parameters more training data is needed.\n") return # Machine Learning model if polynomial == LINEAR: model = linear_model.LinearRegression(n_jobs=-1) else: if polynomial == USER_INPUT: polynomial = ns_parser.n_polynomial model = pipeline.make_pipeline( preprocessing.PolynomialFeatures(polynomial), linear_model.Ridge()) model.fit(stock_x, stock_y) l_predictions = model.predict( df_stock["5. adjusted close"].values[-ns_parser.n_inputs:].reshape( 1, -1))[0] # Prediction data l_pred_days = get_next_stock_market_days( last_stock_day=df_stock["5. adjusted close"].index[-1], n_next_days=ns_parser.n_days, ) df_pred = pd.Series(l_predictions, index=l_pred_days, name="Price") # Plotting plt.figure(figsize=plot_autoscale(), dpi=PLOT_DPI) plt.plot(df_stock.index, df_stock["5. adjusted close"], lw=2) # BACKTESTING if ns_parser.s_end_date: plt.title( f"BACKTESTING: Regression (polynomial {polynomial}) on {s_ticker} - {ns_parser.n_days} days prediction" ) else: plt.title( f"Regression (polynomial {polynomial}) on {s_ticker} - {ns_parser.n_days} days prediction" ) plt.xlim(df_stock.index[0], get_next_stock_market_days(df_pred.index[-1], 1)[-1]) plt.xlabel("Time") plt.ylabel("Share Price ($)") plt.grid(b=True, which="major", color="#666666", linestyle="-") plt.minorticks_on() plt.grid(b=True, which="minor", color="#999999", linestyle="-", alpha=0.2) plt.plot( [df_stock.index[-1], df_pred.index[0]], [df_stock["5. adjusted close"].values[-1], df_pred.values[0]], lw=1, c="tab:green", linestyle="--", ) plt.plot(df_pred.index, df_pred, lw=2, c="tab:green") plt.axvspan(df_stock.index[-1], df_pred.index[-1], facecolor="tab:orange", alpha=0.2) _, _, ymin, ymax = plt.axis() plt.vlines(df_stock.index[-1], ymin, ymax, linewidth=1, linestyle="--", color="k") # BACKTESTING if ns_parser.s_end_date: plt.plot( df_future.index, df_future["5. adjusted close"], lw=2, c="tab:blue", ls="--", ) plt.plot( [df_stock.index[-1], df_future.index[0]], [ df_stock["5. adjusted close"].values[-1], df_future["5. adjusted close"].values[0], ], lw=1, c="tab:blue", linestyle="--", ) if gtff.USE_ION: plt.ion() plt.show() # BACKTESTING if ns_parser.s_end_date: plt.figure(figsize=plot_autoscale(), dpi=PLOT_DPI) plt.subplot(211) plt.plot( df_future.index, df_future["5. adjusted close"], lw=2, c="tab:blue", ls="--", ) plt.plot(df_pred.index, df_pred, lw=2, c="green") plt.scatter(df_future.index, df_future["5. adjusted close"], c="tab:blue", lw=3) plt.plot( [df_stock.index[-1], df_future.index[0]], [ df_stock["5. adjusted close"].values[-1], df_future["5. adjusted close"].values[0], ], lw=2, c="tab:blue", ls="--", ) plt.scatter(df_pred.index, df_pred, c="green", lw=3) plt.plot( [df_stock.index[-1], df_pred.index[0]], [df_stock["5. adjusted close"].values[-1], df_pred.values[0]], lw=2, c="green", ls="--", ) plt.title("BACKTESTING: Real data price versus Prediction") plt.xlim(df_stock.index[-1], df_pred.index[-1] + datetime.timedelta(days=1)) plt.xticks( [ df_stock.index[-1], df_pred.index[-1] + datetime.timedelta(days=1) ], visible=True, ) plt.ylabel("Share Price ($)") plt.grid(b=True, which="major", color="#666666", linestyle="-") plt.minorticks_on() plt.grid(b=True, which="minor", color="#999999", linestyle="-", alpha=0.2) plt.legend(["Real data", "Prediction data"]) plt.xticks([]) plt.subplot(212) plt.axhline(y=0, color="k", linestyle="--", linewidth=2) plt.plot( df_future.index, 100 * (df_pred.values - df_future["5. adjusted close"].values) / df_future["5. adjusted close"].values, lw=2, c="red", ) plt.scatter( df_future.index, 100 * (df_pred.values - df_future["5. adjusted close"].values) / df_future["5. adjusted close"].values, c="red", lw=5, ) plt.title( "BACKTESTING: Error between Real data and Prediction [%]") plt.plot( [df_stock.index[-1], df_future.index[0]], [ 0, 100 * (df_pred.values[0] - df_future["5. adjusted close"].values[0]) / df_future["5. adjusted close"].values[0], ], lw=2, ls="--", c="red", ) plt.xlim(df_stock.index[-1], df_pred.index[-1] + datetime.timedelta(days=1)) plt.xticks( [ df_stock.index[-1], df_pred.index[-1] + datetime.timedelta(days=1) ], visible=True, ) plt.xlabel("Time") plt.ylabel("Prediction Error (%)") plt.grid(b=True, which="major", color="#666666", linestyle="-") plt.minorticks_on() plt.grid(b=True, which="minor", color="#999999", linestyle="-", alpha=0.2) plt.legend(["Real data", "Prediction data"]) if gtff.USE_ION: plt.ion() plt.show() # Refactor prediction dataframe for backtesting print df_pred.name = "Prediction" df_pred = df_pred.to_frame() df_pred["Real"] = df_future["5. adjusted close"] if gtff.USE_COLOR: patch_pandas_text_adjustment() print("Time Real [$] x Prediction [$]") print( df_pred.apply(price_prediction_backtesting_color, axis=1).to_string()) else: print(df_pred[["Real", "Prediction"]].round(2).to_string()) print("") print_prediction_kpis(df_pred["Real"].values, df_pred["Prediction"].values) else: # Print prediction data print_pretty_prediction(df_pred, df_stock["5. adjusted close"].values[-1]) print("") except SystemExit: print("") except Exception as e: print(e) print("")
def exponential_smoothing(l_args, s_ticker, df_stock): parser = argparse.ArgumentParser( add_help=False, prog="ets", description=""" Exponential Smoothing, see https://otexts.com/fpp2/taxonomy.html Trend='N', Seasonal='N': Simple Exponential Smoothing Trend='N', Seasonal='A': Exponential Smoothing Trend='N', Seasonal='M': Exponential Smoothing Trend='A', Seasonal='N': Holt’s linear method Trend='A', Seasonal='A': Additive Holt-Winters’ method Trend='A', Seasonal='M': Multiplicative Holt-Winters’ method Trend='Ad', Seasonal='N': Additive damped trend method Trend='Ad', Seasonal='A': Exponential Smoothing Trend='Ad', Seasonal='M': Holt-Winters’ damped method Trend component: N: None, A: Additive, Ad: Additive Damped Seasonality component: N: None, A: Additive, M: Multiplicative """, ) parser.add_argument( "-d", "--days", action="store", dest="n_days", type=check_positive, default=5, help="prediction days.", ) parser.add_argument( "-t", "--trend", action="store", dest="trend", type=check_valid_trend, default="N", help="Trend component: N: None, A: Additive, Ad: Additive Damped.", ) parser.add_argument( "-s", "--seasonal", action="store", dest="seasonal", type=check_valid_seasonal, default="N", help="Seasonality component: N: None, A: Additive, M: Multiplicative.", ) parser.add_argument( "-p", "--periods", action="store", dest="seasonal_periods", type=check_positive, default=5, help="Seasonal periods.", ) parser.add_argument( "-e", "--end", action="store", type=valid_date, dest="s_end_date", default=None, help="The end date (format YYYY-MM-DD) to select - Backtesting", ) try: ns_parser = parse_known_args_and_warn(parser, l_args) if not ns_parser: return # BACKTESTING if ns_parser.s_end_date: if ns_parser.s_end_date < df_stock.index[0]: print( "Backtesting not allowed, since End Date is older than Start Date of historical data\n" ) return if (ns_parser.s_end_date < get_next_stock_market_days( last_stock_day=df_stock.index[0], n_next_days=5 + ns_parser.n_days)[-1]): print( "Backtesting not allowed, since End Date is too close to Start Date to train model\n" ) return future_index = get_next_stock_market_days( last_stock_day=ns_parser.s_end_date, n_next_days=ns_parser.n_days) if future_index[-1] > datetime.datetime.now(): print( "Backtesting not allowed, since End Date + Prediction days is in the future\n" ) return df_future = df_stock[future_index[0]:future_index[-1]] df_stock = df_stock[:ns_parser.s_end_date] # Get ETS model model, title = get_exponential_smoothing_model( df_stock["5. adjusted close"].values, ns_parser.trend, ns_parser.seasonal, ns_parser.seasonal_periods, ) if model.mle_retvals.success: forecast = model.forecast(ns_parser.n_days) l_pred_days = get_next_stock_market_days( last_stock_day=df_stock["5. adjusted close"].index[-1], n_next_days=ns_parser.n_days, ) df_pred = pd.Series(forecast, index=l_pred_days, name="Price") if ~np.isnan(forecast).any(): print(f"\n{title}") print("\nFit model parameters:") for key, value in model.params.items(): print(f"{key} {' '*(18-len(key))}: {value}") print("\nAssess fit model:") print(f"AIC: {round(model.aic, 2)}") print(f"BIC: {round(model.bic, 2)}") print(f"SSE: {round(model.sse, 2)}\n") # Plotting plt.figure(figsize=plot_autoscale(), dpi=PLOT_DPI) plt.plot(df_stock.index, df_stock["5. adjusted close"], lw=2) # BACKTESTING if ns_parser.s_end_date: plt.title(f"BACKTESTING: {title} on {s_ticker}") else: plt.title(f"{title} on {s_ticker}") plt.xlim( df_stock.index[0], get_next_stock_market_days(df_pred.index[-1], 1)[-1], ) plt.xlabel("Time") plt.ylabel("Share Price ($)") plt.grid(b=True, which="major", color="#666666", linestyle="-") plt.minorticks_on() plt.grid(b=True, which="minor", color="#999999", linestyle="-", alpha=0.2) plt.plot( [df_stock.index[-1], df_pred.index[0]], [ df_stock["5. adjusted close"].values[-1], df_pred.values[0] ], lw=1, c="tab:green", linestyle="--", ) plt.plot(df_pred.index, df_pred, lw=2, c="tab:green") plt.axvspan( df_stock.index[-1], df_pred.index[-1], facecolor="tab:orange", alpha=0.2, ) _, _, ymin, ymax = plt.axis() plt.vlines( df_stock.index[-1], ymin, ymax, linewidth=1, linestyle="--", color="k", ) # BACKTESTING if ns_parser.s_end_date: plt.plot( df_future.index, df_future["5. adjusted close"], lw=2, c="tab:blue", ls="--", ) plt.plot( [df_stock.index[-1], df_future.index[0]], [ df_stock["5. adjusted close"].values[-1], df_future["5. adjusted close"].values[0], ], lw=1, c="tab:blue", linestyle="--", ) if gtff.USE_ION: plt.ion() plt.show() # BACKTESTING if ns_parser.s_end_date: plt.figure(figsize=plot_autoscale(), dpi=PLOT_DPI) plt.subplot(211) plt.plot( df_future.index, df_future["5. adjusted close"], lw=2, c="tab:blue", ls="--", ) plt.plot(df_pred.index, df_pred, lw=2, c="green") plt.scatter( df_future.index, df_future["5. adjusted close"], c="tab:blue", lw=3, ) plt.plot( [df_stock.index[-1], df_future.index[0]], [ df_stock["5. adjusted close"].values[-1], df_future["5. adjusted close"].values[0], ], lw=2, c="tab:blue", ls="--", ) plt.scatter(df_pred.index, df_pred, c="green", lw=3) plt.plot( [df_stock.index[-1], df_pred.index[0]], [ df_stock["5. adjusted close"].values[-1], df_pred.values[0] ], lw=2, c="green", ls="--", ) plt.title("BACKTESTING: Real data price versus Prediction") plt.xlim( df_stock.index[-1], df_pred.index[-1] + datetime.timedelta(days=1), ) plt.ylabel("Share Price ($)") plt.grid(b=True, which="major", color="#666666", linestyle="-") plt.minorticks_on() plt.grid(b=True, which="minor", color="#999999", linestyle="-", alpha=0.2) plt.legend(["Real data", "Prediction data"]) plt.xticks([]) plt.subplot(212) plt.axhline(y=0, color="k", linestyle="--", linewidth=2) plt.plot( df_future.index, 100 * (df_pred.values - df_future["5. adjusted close"].values) / df_future["5. adjusted close"].values, lw=2, c="red", ) plt.scatter( df_future.index, 100 * (df_pred.values - df_future["5. adjusted close"].values) / df_future["5. adjusted close"].values, c="red", lw=5, ) plt.title( "BACKTESTING: Error between Real data and Prediction [%]" ) plt.plot( [df_stock.index[-1], df_future.index[0]], [ 0, 100 * (df_pred.values[0] - df_future["5. adjusted close"].values[0]) / df_future["5. adjusted close"].values[0], ], lw=2, ls="--", c="red", ) plt.xlim( df_stock.index[-1], df_pred.index[-1] + datetime.timedelta(days=1), ) plt.xlabel("Time") plt.ylabel("Prediction Error (%)") plt.grid(b=True, which="major", color="#666666", linestyle="-") plt.minorticks_on() plt.grid(b=True, which="minor", color="#999999", linestyle="-", alpha=0.2) plt.legend(["Real data", "Prediction data"]) if gtff.USE_ION: plt.ion() plt.show() # Refactor prediction dataframe for backtesting print df_pred.name = "Prediction" df_pred = df_pred.to_frame() df_pred["Real"] = df_future["5. adjusted close"] if gtff.USE_COLOR: patch_pandas_text_adjustment() print("Time Real [$] x Prediction [$]") print( df_pred.apply(price_prediction_backtesting_color, axis=1).to_string()) else: print(df_pred[["Real", "Prediction"]].round(2).to_string()) print("") print_prediction_kpis(df_pred["Real"].values, df_pred["Prediction"].values) else: # Print prediction data print_pretty_prediction( df_pred, df_stock["5. adjusted close"].values[-1]) print("") else: print( "RuntimeWarning: invalid value encountered in double_scalars." ) else: print("ConvergenceWarning: Optimization failed to converge.") except Exception as e: print(e) print("")
def display_exponential_smoothing( ticker: str, values: Union[pd.DataFrame, pd.Series], n_predict: int, trend: str = "N", seasonal: str = "N", seasonal_periods: int = 5, s_end_date: str = "", export: str = "", time_res: str = "", external_axes: Optional[List[plt.Axes]] = None, ): """Perform exponential smoothing Parameters ---------- ticker : str Dataset being smoothed values : Union[pd.DataFrame, pd.Series] Raw data n_predict : int Days to predict trend : str, optional Trend variable, by default "N" seasonal : str, optional Seasonal variable, by default "N" seasonal_periods : int, optional Number of seasonal periods, by default 5 s_end_date : str, optional End date for backtesting, by default "" export : str, optional Format to export data, by default "" time_res : str Resolution for data, allowing for predicting outside of standard market days external_axes : Optional[List[plt.Axes]], optional External axes (1 axis is expected in the list), by default None """ if s_end_date: if not time_res: future_index = get_next_stock_market_days( last_stock_day=s_end_date, n_next_days=n_predict ) else: future_index = pd.date_range( s_end_date, periods=n_predict + 1, freq=time_res )[1:] if future_index[-1] > datetime.datetime.now(): console.print( "Backtesting not allowed," + " since End Date + Prediction days is in the future\n" ) return df_future = values[future_index[0] : future_index[-1]] # noqa: E203 values = values[:s_end_date] # type: ignore # Get ETS model model, title, forecast = ets_model.get_exponential_smoothing_model( values, trend, seasonal, seasonal_periods, n_predict ) if not forecast: console.print("No forecast made. Model did not converge.\n") return if np.isnan(forecast).any(): console.print("Model predicted NaN values. Runtime Error.\n") return if not time_res: l_pred_days = get_next_stock_market_days( last_stock_day=values.index[-1], n_next_days=n_predict, ) else: l_pred_days = pd.date_range( values.index[-1], periods=n_predict + 1, freq=time_res )[1:] df_pred = pd.Series(forecast, index=l_pred_days, name="Price") console.print(f"\n{title}") console.print("\nFit model parameters:") for key, value in model.params.items(): console.print(f"{key} {' '*(18-len(key))}: {value}") console.print("\nAssess fit model:") console.print(f"AIC: {round(model.aic, 2)}") console.print(f"BIC: {round(model.bic, 2)}") console.print(f"SSE: {round(model.sse, 2)}\n") # Plotting # This plot has 1 axes if external_axes is None: _, ax1 = plt.subplots(figsize=plot_autoscale(), dpi=PLOT_DPI) else: if (not s_end_date and len(external_axes) != 1) or ( s_end_date and len(external_axes) != 3 ): console.print( "[red]Expected list of 1 axis item " + "or 3 axis items when backtesting./n[/red]" ) return ax1 = external_axes[0] ax1.plot(values.index, values.values) # BACKTESTING if s_end_date: ax1.set_title(f"BACKTESTING: {title} on {ticker}", fontsize=12) else: ax1.set_title(f"{title} on {ticker}", fontsize=12) ax1.set_xlim( values.index[0], get_next_stock_market_days(df_pred.index[-1], 1)[-1], ) ax1.set_ylabel("Value") ax1.plot( [values.index[-1], df_pred.index[0]], [values.values[-1], df_pred.values[0]], color=theme.down_color, linestyle="--", ) ax1.plot(df_pred.index, df_pred, color=theme.down_color) ax1.axvspan( values.index[-1], df_pred.index[-1], facecolor=theme.down_color, alpha=0.2, ) _, _, ymin, ymax = plt.axis() ax1.vlines( values.index[-1], ymin, ymax, linestyle="--", color=theme.get_colors(reverse=True)[0], ) # BACKTESTING if s_end_date: ax1.plot( df_future.index, df_future, color=theme.up_color, linestyle="--", ) ax1.plot( [values.index[-1], df_future.index[0]], [ values.values[-1], df_future.values[0], ], color=theme.up_color, linestyle="--", ) theme.style_primary_axis(ax1) if external_axes is None: theme.visualize_output() # BACKTESTING if s_end_date: # This plot has 1 axes if external_axes is None: _, axes = plt.subplots( 2, 1, sharex=True, figsize=plot_autoscale(), dpi=PLOT_DPI ) (ax2, ax3) = axes else: if len(external_axes) != 3: console.print("[red]Expected list of 1 axis item./n[/red]") return (_, ax2, ax3) = external_axes ax2.plot( df_future.index, df_future, color=theme.up_color, linestyle="--", ) ax2.plot(df_pred.index, df_pred) ax2.scatter( df_future.index, df_future, color=theme.up_color, ) ax2.plot( [values.index[-1], df_future.index[0]], [ values.values[-1], df_future.values[0], ], color=theme.up_color, linestyle="--", ) ax2.scatter(df_pred.index, df_pred) ax2.plot( [values.index[-1], df_pred.index[0]], [values.values[-1], df_pred.values[0]], linestyle="--", ) ax2.set_title("BACKTESTING: Values") ax2.set_xlim( values.index[-1], df_pred.index[-1] + datetime.timedelta(days=1), ) ax2.set_ylabel("Value") ax2.legend(["Real data", "Prediction data"]) theme.style_primary_axis(ax2) ax3.axhline(y=0, linestyle="--") ax3.plot( df_future.index, 100 * (df_pred.values - df_future.values) / df_future.values, color=theme.down_color, ) ax3.scatter( df_future.index, 100 * (df_pred.values - df_future.values) / df_future.values, color=theme.down_color, ) ax3.set_title("BACKTESTING: % Error") ax3.plot( [values.index[-1], df_future.index[0]], [ 0, 100 * (df_pred.values[0] - df_future.values[0]) / df_future.values[0], ], ls="--", color=theme.down_color, ) ax3.set_xlim( values.index[-1], df_pred.index[-1] + datetime.timedelta(days=1), ) ax3.set_ylabel("Prediction Error (%)") theme.style_primary_axis(ax3) if external_axes is None: theme.visualize_output() # Refactor prediction dataframe for backtesting print df_pred.name = "Prediction" df_pred = df_pred.to_frame() df_pred["Real"] = df_future if gtff.USE_COLOR: patch_pandas_text_adjustment() console.print("Time Real [$] x Prediction [$]") console.print( df_pred.apply( lambda_price_prediction_backtesting_color, axis=1 ).to_string() ) else: console.print(df_pred[["Real", "Prediction"]].round(2).to_string()) console.print("") print_prediction_kpis(df_pred["Real"].values, df_pred["Prediction"].values) else: # Print prediction data print_pretty_prediction(df_pred, values.values[-1]) export_data(export, os.path.dirname(os.path.abspath(__file__)), "ets")
def simple_moving_average(l_args, s_ticker, df_stock): parser = argparse.ArgumentParser( add_help=False, prog="sma", description=""" Moving Averages are used to smooth the data in an array to help eliminate noise and identify trends. The Simple Moving Average is literally the simplest form of a moving average. Each output value is the average of the previous n values. In a Simple Moving Average, each value in the time period carries equal weight, and values outside of the time period are not included in the average. This makes it less responsive to recent changes in the data, which can be useful for filtering out those changes. """, ) parser.add_argument( "-l", "--length", action="store", dest="n_length", type=check_positive, default=20, help="length of SMA window.", ) parser.add_argument( "-d", "--days", action="store", dest="n_days", type=check_positive, default=5, help="prediction days.", ) parser.add_argument( "-e", "--end", action="store", type=valid_date, dest="s_end_date", default=None, help="The end date (format YYYY-MM-DD) to select - Backtesting", ) try: ns_parser = parse_known_args_and_warn(parser, l_args) if not ns_parser: return # BACKTESTING if ns_parser.s_end_date: if ns_parser.s_end_date < df_stock.index[0]: print( "Backtesting not allowed, since End Date is older than Start Date of historical data\n" ) return if ( ns_parser.s_end_date < get_next_stock_market_days( last_stock_day=df_stock.index[0], n_next_days=5 + ns_parser.n_days )[-1] ): print( "Backtesting not allowed, since End Date is too close to Start Date to train model\n" ) return future_index = get_next_stock_market_days( last_stock_day=ns_parser.s_end_date, n_next_days=ns_parser.n_days ) if future_index[-1] > datetime.datetime.now(): print( "Backtesting not allowed, since End Date + Prediction days is in the future\n" ) return df_future = df_stock[future_index[0] : future_index[-1]] df_stock = df_stock[: ns_parser.s_end_date] # Prediction data l_predictions = list() for pred_day in range(ns_parser.n_days): if pred_day < ns_parser.n_length: l_ma_stock = df_stock["5. adjusted close"].values[ -ns_parser.n_length + pred_day : ] else: l_ma_stock = list() l_predictions.append(np.mean(np.append(l_ma_stock, l_predictions))) l_pred_days = get_next_stock_market_days( last_stock_day=df_stock["5. adjusted close"].index[-1], n_next_days=ns_parser.n_days, ) df_pred = pd.Series(l_predictions, index=l_pred_days, name="Price") # Plotting plt.figure(figsize=plot_autoscale(), dpi=PLOT_DPI) plt.plot(df_stock.index, df_stock["5. adjusted close"], lw=2) # BACKTESTING if ns_parser.s_end_date: plt.title( f"BACKTESTING: {ns_parser.n_length} Moving Average on {s_ticker} - {ns_parser.n_days} days prediction" ) else: plt.title( f"{ns_parser.n_length} Moving Average on {s_ticker} - {ns_parser.n_days} days prediction" ) plt.xlim( df_stock.index[0], get_next_stock_market_days(df_pred.index[-1], 1)[-1] ) plt.xlabel("Time") plt.ylabel("Share Price ($)") plt.grid(b=True, which="major", color="#666666", linestyle="-") plt.minorticks_on() plt.grid(b=True, which="minor", color="#999999", linestyle="-", alpha=0.2) df_ma = df_stock["5. adjusted close"].rolling(window=ns_parser.n_length).mean() plt.plot(df_ma.index, df_ma, lw=2, linestyle="--", c="tab:orange") plt.plot( [df_stock.index[-1], df_pred.index[0]], [df_stock["5. adjusted close"].values[-1], df_pred.values[0]], lw=1, c="tab:green", linestyle="--", ) plt.plot(df_pred.index, df_pred, lw=2, c="tab:green") plt.axvspan( df_stock.index[-1], df_pred.index[-1], facecolor="tab:orange", alpha=0.2 ) _, _, ymin, ymax = plt.axis() plt.vlines( df_stock.index[-1], ymin, ymax, linewidth=1, linestyle="--", color="k" ) # BACKTESTING if ns_parser.s_end_date: plt.plot( df_future.index, df_future["5. adjusted close"], lw=2, c="tab:blue", ls="--", ) plt.plot( [df_stock.index[-1], df_future.index[0]], [ df_stock["5. adjusted close"].values[-1], df_future["5. adjusted close"].values[0], ], lw=1, c="tab:blue", linestyle="--", ) if gtff.USE_ION: plt.ion() plt.show() # BACKTESTING if ns_parser.s_end_date: plt.figure(figsize=plot_autoscale(), dpi=PLOT_DPI) plt.subplot(211) plt.plot( df_future.index, df_future["5. adjusted close"], lw=2, c="tab:blue", ls="--", ) plt.plot(df_pred.index, df_pred, lw=2, c="green") plt.scatter( df_future.index, df_future["5. adjusted close"], c="tab:blue", lw=3 ) plt.plot( [df_stock.index[-1], df_future.index[0]], [ df_stock["5. adjusted close"].values[-1], df_future["5. adjusted close"].values[0], ], lw=2, c="tab:blue", ls="--", ) plt.scatter(df_pred.index, df_pred, c="green", lw=3) plt.plot( [df_stock.index[-1], df_pred.index[0]], [df_stock["5. adjusted close"].values[-1], df_pred.values[0]], lw=2, c="green", ls="--", ) plt.title("BACKTESTING: Real data price versus Prediction") plt.xlim(df_stock.index[-1], df_pred.index[-1] + datetime.timedelta(days=1)) plt.xticks( [df_stock.index[-1], df_pred.index[-1] + datetime.timedelta(days=1)], visible=True, ) plt.ylabel("Share Price ($)") plt.grid(b=True, which="major", color="#666666", linestyle="-") plt.minorticks_on() plt.grid(b=True, which="minor", color="#999999", linestyle="-", alpha=0.2) plt.legend(["Real data", "Prediction data"]) plt.xticks([]) plt.subplot(212) plt.axhline(y=0, color="k", linestyle="--", linewidth=2) plt.plot( df_future.index, 100 * (df_pred.values - df_future["5. adjusted close"].values) / df_future["5. adjusted close"].values, lw=2, c="red", ) plt.scatter( df_future.index, 100 * (df_pred.values - df_future["5. adjusted close"].values) / df_future["5. adjusted close"].values, c="red", lw=5, ) plt.title("BACKTESTING: Error between Real data and Prediction [%]") plt.plot( [df_stock.index[-1], df_future.index[0]], [ 0, 100 * (df_pred.values[0] - df_future["5. adjusted close"].values[0]) / df_future["5. adjusted close"].values[0], ], lw=2, ls="--", c="red", ) plt.xlim(df_stock.index[-1], df_pred.index[-1] + datetime.timedelta(days=1)) plt.xticks( [df_stock.index[-1], df_pred.index[-1] + datetime.timedelta(days=1)], visible=True, ) plt.xlabel("Time") plt.ylabel("Prediction Error (%)") plt.grid(b=True, which="major", color="#666666", linestyle="-") plt.minorticks_on() plt.grid(b=True, which="minor", color="#999999", linestyle="-", alpha=0.2) plt.legend(["Real data", "Prediction data"]) if gtff.USE_ION: plt.ion() plt.show() # Refactor prediction dataframe for backtesting print df_pred.name = "Prediction" df_pred = df_pred.to_frame() df_pred["Real"] = df_future["5. adjusted close"] if gtff.USE_COLOR: patch_pandas_text_adjustment() print("Time Real [$] x Prediction [$]") print( df_pred.apply( price_prediction_backtesting_color, axis=1 ).to_string() ) else: print(df_pred[["Real", "Prediction"]].round(2).to_string()) print("") print_prediction_kpis(df_pred["Real"].values, df_pred["Prediction"].values) else: # Print prediction data print_pretty_prediction(df_pred, df_stock["5. adjusted close"].values[-1]) print("") except Exception as e: print(e) print("")
def print_insider_filter( preset_loaded: str, ticker: str, limit: int = 10, links: bool = False, export: str = "", ): """Print insider filter based on loaded preset. [Source: OpenInsider] Parameters ---------- preset_loaded : str Loaded preset filter ticker : str Stock ticker limit : int Limit of rows of data to display links : bool Flag to show hyperlinks export : str Format to export data """ if ticker: link = f"http://openinsider.com/screener?s={ticker}" else: link = get_open_insider_link(preset_loaded) if not link: console.print("") return df_insider = get_open_insider_data(link, has_company_name=bool(not ticker)) df_insider_orig = df_insider.copy() if df_insider.empty: console.print("No insider data found\n") return if links: df_insider = df_insider[["Ticker Link", "Insider Link", "Filing Link"]].head(limit) else: df_insider = df_insider.drop( columns=["Filing Link", "Ticker Link", "Insider Link"]).head(limit) if rich_config.USE_COLOR and not links: if not df_insider[df_insider["Trade Type"] == "S - Sale"].empty: df_insider[df_insider["Trade Type"] == "S - Sale"] = df_insider[ df_insider["Trade Type"] == "S - Sale"].apply( lambda_red_highlight) if not df_insider[df_insider["Trade Type"] == "S - Sale+OE"].empty: df_insider[df_insider["Trade Type"] == "S - Sale+OE"] = df_insider[ df_insider["Trade Type"] == "S - Sale+OE"].apply( lambda_yellow_highlight) if not df_insider[df_insider["Trade Type"] == "F - Tax"].empty: df_insider[df_insider["Trade Type"] == "F - Tax"] = df_insider[ df_insider["Trade Type"] == "F - Tax"].apply( lambda_magenta_highlight) if not df_insider[df_insider["Trade Type"] == "P - Purchase"].empty: df_insider[df_insider["Trade Type"] == "P - Purchase"] = df_insider[df_insider["Trade Type"] == "P - Purchase"].apply( lambda_green_highlight) patch_pandas_text_adjustment() pd.set_option("display.max_colwidth", 0) pd.set_option("display.max_rows", None) # needs to be done because table is too large :( df_insider = df_insider.drop(columns=["Filing Date", "Trade Type"]) else: # needs to be done because table is too large :( df_insider = df_insider.drop(columns=["Filing Date"]) console.print("") print_rich_table( df_insider, headers=[x.title() for x in df_insider.columns], title="Insider filtered", ) if export: if preset_loaded: cmd = "filter" if ticker: cmd = "lis" export_data(export, os.path.dirname(os.path.abspath(__file__)), cmd, df_insider) if not links: l_chars = [list(chars) for chars in df_insider_orig["X"].values] l_uchars = np.unique(list(itertools.chain(*l_chars))) console.print("") for char in l_uchars: console.print(d_notes[char]) l_tradetype = df_insider_orig["Trade Type"].values l_utradetype = np.unique(l_tradetype) console.print("") for tradetype in l_utradetype: console.print(d_trade_types[tradetype]) console.print("")
def cash(other_args: List[str], ticker: str): """Market Watch ticker cash flow statement Parameters ---------- other_args : List[str] argparse other args ticker : str Fundamental analysis ticker symbol """ parser = argparse.ArgumentParser( add_help=False, formatter_class=argparse.ArgumentDefaultsHelpFormatter, prog="cash_flow", description=""" Prints either yearly or quarterly cash flow operating activities of the company. The following fields are expected: Net Income before Extraordinaries, Net Income Growth, Depreciation, Depletion & Amortization, Depreciation and Depletion, Amortization of Intangible Assets, Deferred Taxes & Investment Tax Credit, Deferred Taxes, Investment Tax Credit, Other Funds, Funds from Operations, Extraordinaries, Changes in Working Capital, Receivables, Accounts Payable, Other Assets/Liabilities, and Net Operating Cash Flow Growth. Prints either yearly or quarterly cash flow investing activities of the company. The following fields are expected: Capital Expenditures, Capital Expenditures Growth, Capital Expenditures/Sales, Capital Expenditures (Fixed Assets), Capital Expenditures (Other Assets), Net Assets from Acquisitions, Sale of Fixed Assets & Businesses, Purchase/Sale of Investments, Purchase of Investments, Sale/Maturity of Investments, Other Uses, Other Sources, Net Investing Cash Flow Growth. Prints either yearly or quarterly cash flow financing activities of the company. The following fields are expected: Cash Dividends Paid - Total, Common Dividends, Preferred Dividends, Change in Capital Stock, Repurchase of Common & Preferred Stk., Sale of Common & Preferred Stock, Proceeds from Stock Options, Other Proceeds from Sale of Stock, Issuance/Reduction of Debt, Net, Change in Current Debt, Change in Long-Term Debt, Issuance of Long-Term Debt, Reduction in Long-Term Debt, Other Funds, Other Uses, Other Sources, Net Financing Cash Flow Growth, Net Financing Cash Flow/Sales, Exchange Rate Effect, Miscellaneous Funds, Net Change in Cash, Free Cash Flow, Free Cash Flow Growth, Free Cash Flow Yield, Net Operating Cash Flow, Net Investing Cash Flow, Net Financing Cash Flow. [Source: Market Watch] """, ) parser.add_argument( "-q", "--quarter", action="store_true", default=False, dest="b_quarter", help="Quarter fundamental data flag.", ) ns_parser = parse_known_args_and_warn(parser, other_args) if not ns_parser: return df_financials = mwm.prepare_df_financials(ticker, "cashflow", ns_parser.b_quarter) if gtff.USE_COLOR: df_financials = df_financials.applymap(financials_colored_values) patch_pandas_text_adjustment() pd.set_option("display.max_colwidth", None) pd.set_option("display.max_rows", None) if df_financials.empty: print("Marketwatch does not yet provide financials for this ticker") else: print(df_financials.to_string(index=False)) print("")
def income(other_args: List[str], ticker: str): """Market Watch ticker income statement Parameters ---------- other_args : List[str] argparse other args ticker : str Fundamental analysis ticker symbol """ parser = argparse.ArgumentParser( add_help=False, formatter_class=argparse.ArgumentDefaultsHelpFormatter, prog="income", description=""" Prints either yearly or quarterly income statement the company. The following fields are expected: Sales Growth, Cost of Goods Sold (COGS) incl. D&A, COGS Growth, COGS excluding D&A, Depreciation & Amortization Expense, Depreciation, Amortization of Intangibles, Gross Income, Gross Income Growth, Gross Profit Margin, SG&A Expense, SGA Growth, Research & Development, Other SG&A, Other Operating Expense, Unusual Expense, EBIT after Unusual Expense, Non Operating Income/Expense, Non-Operating Interest Income, Equity in Affiliates (Pretax), Interest Expense, Interest Expense Growth, Gross Interest Expense, Interest Capitalized, Pretax Income, Pretax Income Growth, Pretax Margin, Income Tax, Income Tax - Current Domestic, Income Tax - Current Foreign, Income Tax - Deferred Domestic, Income Tax - Deferred Foreign, Income Tax Credits, Equity in Affiliates, Other After Tax Income (Expense), Consolidated Net Income, Minority Interest Expense, Net Income Growth, Net Margin Growth, Extraordinaries & Discontinued Operations, Extra Items & Gain/Loss Sale Of Assets, Cumulative Effect - Accounting Chg, Discontinued Operations, Net Income After Extraordinaries, Preferred Dividends, Net Income Available to Common, EPS (Basic), EPS (Basic) Growth, Basic Shares Outstanding, EPS (Diluted), EPS (Diluted) Growth, Diluted Shares Outstanding, EBITDA, EBITDA Growth, EBITDA Margin, Sales/Revenue, and Net Income. [Source: Market Watch] """, ) parser.add_argument( "-q", "--quarter", action="store_true", default=False, dest="b_quarter", help="Quarter fundamental data flag.", ) ns_parser = parse_known_args_and_warn(parser, other_args) if not ns_parser: return df_financials = mwm.prepare_df_financials(ticker, "income", ns_parser.b_quarter) if gtff.USE_COLOR: df_financials = df_financials.applymap(financials_colored_values) patch_pandas_text_adjustment() pd.set_option("display.max_colwidth", None) pd.set_option("display.max_rows", None) if df_financials.empty: print("Marketwatch does not yet provide financials for this ticker") else: print(df_financials.to_string(index=False)) print("")
def print_insider_filter(other_args: List[str], preset_loaded: str): """Print insider filter based on loaded preset Parameters ---------- other_args : List[str] Command line arguments to be processed with argparse preset_loaded: str Loaded preset filter """ parser = argparse.ArgumentParser( add_help=False, formatter_class=argparse.ArgumentDefaultsHelpFormatter, prog="filter", description= "Print open insider filtered data using loaded preset, or selected ticker. [Source: OpenInsider]", ) parser.add_argument( "-n", "--num", action="store", dest="num", type=check_positive, default=20, help="Number of datarows to display", ) parser.add_argument( "-t", "--ticker", action="store", dest="ticker", type=str, default="", help="Filter latest insiders from this ticker", ) parser.add_argument( "-l", "--links", action="store_true", default=False, help="Flag to show hyperlinks", dest="links", ) try: ns_parser = parse_known_args_and_warn(parser, other_args) if not ns_parser: return if ns_parser.ticker: link = f"http://openinsider.com/screener?s={ns_parser.ticker}" else: link = get_open_insider_link(preset_loaded) if not link: print("") return df_insider = get_open_insider_data( link, has_company_name=bool(not ns_parser.ticker)) df_insider_orig = df_insider.copy() if df_insider.empty: print("") return if ns_parser.links: df_insider = df_insider[[ "Ticker Link", "Insider Link", "Filing Link" ]].head(ns_parser.num) else: df_insider = df_insider.drop( columns=["Filing Link", "Ticker Link", "Insider Link"]).head( ns_parser.num) if gtff.USE_COLOR and not ns_parser.links: if not df_insider[df_insider["Trade Type"] == "S - Sale"].empty: df_insider[df_insider["Trade Type"] == "S - Sale"] = df_insider[df_insider["Trade Type"] == "S - Sale"].apply( red_highlight) if not df_insider[df_insider["Trade Type"] == "S - Sale+OE"].empty: df_insider[df_insider["Trade Type"] == "S - Sale+OE"] = df_insider[df_insider["Trade Type"] == "S - Sale+OE"].apply( yellow_highlight) if not df_insider[df_insider["Trade Type"] == "F - Tax"].empty: df_insider[df_insider["Trade Type"] == "F - Tax"] = df_insider[ df_insider["Trade Type"] == "F - Tax"].apply( magenta_highlight) if not df_insider[df_insider["Trade Type"] == "P - Purchase"].empty: df_insider[ df_insider["Trade Type"] == "P - Purchase"] = df_insider[ df_insider["Trade Type"] == "P - Purchase"].apply( green_highlight) patch_pandas_text_adjustment() pd.set_option("display.max_colwidth", 0) pd.set_option("display.max_rows", None) # needs to be done because table is too large :( df_insider = df_insider.drop(columns=["Filing Date", "Trade Type"]) else: # needs to be done because table is too large :( df_insider = df_insider.drop(columns=["Filing Date"]) print("") print(df_insider.to_string(index=False)) if not ns_parser.links: l_chars = [list(chars) for chars in df_insider_orig["X"].values] l_uchars = np.unique(list(itertools.chain(*l_chars))) print("") for char in l_uchars: print(d_notes[char]) l_tradetype = df_insider_orig["Trade Type"].values l_utradetype = np.unique(l_tradetype) print("") for tradetype in l_utradetype: print(d_trade_types[tradetype]) print("") except Exception as e: print(e, "\n")
def display_exponential_smoothing( ticker: str, values: Union[pd.DataFrame, pd.Series], n_predict: int, trend: str = "N", seasonal: str = "N", seasonal_periods: int = 5, s_end_date: str = "", export: str = "", time_res: str = "", ): """Perform exponential smoothing Parameters ---------- ticker : str Dataset being smoothed values : Union[pd.DataFrame, pd.Series] Raw data n_predict : int Days to predict trend : str, optional Trend variable, by default "N" seasonal : str, optional Seasonal variable, by default "N" seasonal_periods : int, optional Number of seasonal periods, by default 5 s_end_date : str, optional End date for backtesting, by default "" export : str, optional Format to export data, by default "" time_res : str Resolution for data, allowing for predicting outside of standard market days """ if s_end_date: if not time_res: future_index = get_next_stock_market_days( last_stock_day=s_end_date, n_next_days=n_predict) else: future_index = pd.date_range(s_end_date, periods=n_predict + 1, freq=time_res)[1:] if future_index[-1] > datetime.datetime.now(): console.print( "Backtesting not allowed, since End Date + Prediction days is in the future\n" ) return df_future = values[future_index[0]:future_index[-1]] values = values[:s_end_date] # type: ignore # Get ETS model model, title, forecast = ets_model.get_exponential_smoothing_model( values, trend, seasonal, seasonal_periods, n_predict) if not forecast: console.print("No forecast made. Model did not converge.\n") return if np.isnan(forecast).any(): console.print("Model predicted NaN values. Runtime Error.\n") return if not time_res: l_pred_days = get_next_stock_market_days( last_stock_day=values.index[-1], n_next_days=n_predict, ) else: l_pred_days = pd.date_range(values.index[-1], periods=n_predict + 1, freq=time_res)[1:] df_pred = pd.Series(forecast, index=l_pred_days, name="Price") console.print(f"\n{title}") console.print("\nFit model parameters:") for key, value in model.params.items(): console.print(f"{key} {' '*(18-len(key))}: {value}") console.print("\nAssess fit model:") console.print(f"AIC: {round(model.aic, 2)}") console.print(f"BIC: {round(model.bic, 2)}") console.print(f"SSE: {round(model.sse, 2)}\n") # Plotting fig, ax = plt.subplots(figsize=plot_autoscale(), dpi=PLOT_DPI) ax.plot(values.index, values.values, lw=2) # BACKTESTING if s_end_date: ax.set_title(f"BACKTESTING: {title} on {ticker}") else: ax.set_title(f"{title} on {ticker}") ax.set_xlim( values.index[0], get_next_stock_market_days(df_pred.index[-1], 1)[-1], ) ax.set_xlabel("Time") ax.set_ylabel("Share Price ($)") ax.grid(b=True, which="major", color="#666666", linestyle="-") ax.minorticks_on() ax.grid(b=True, which="minor", color="#999999", linestyle="-", alpha=0.2) ax.plot( [values.index[-1], df_pred.index[0]], [values.values[-1], df_pred.values[0]], lw=1, c="tab:green", linestyle="--", ) ax.plot(df_pred.index, df_pred, lw=2, c="tab:green") ax.axvspan( values.index[-1], df_pred.index[-1], facecolor="tab:orange", alpha=0.2, ) _, _, ymin, ymax = plt.axis() ax.vlines( values.index[-1], ymin, ymax, linewidth=1, linestyle="--", color="k", ) dateFmt = mdates.DateFormatter("%m/%d/%Y") ax.xaxis.set_major_formatter(dateFmt) ax.tick_params(axis="x", labelrotation=45) # BACKTESTING if s_end_date: ax.plot( df_future.index, df_future, lw=2, c="tab:blue", ls="--", ) ax.plot( [values.index[-1], df_future.index[0]], [ values.values[-1], df_future.values[0], ], lw=1, c="tab:blue", linestyle="--", ) if gtff.USE_ION: plt.ion() fig.tight_layout() plt.show() # BACKTESTING if s_end_date: dateFmt = mdates.DateFormatter("%m-%d") fig, ax = plt.subplots(1, 2, figsize=plot_autoscale(), dpi=PLOT_DPI) ax0 = ax[0] ax0.plot( df_future.index, df_future, lw=2, c="tab:blue", ls="--", ) ax0.plot(df_pred.index, df_pred, lw=2, c="green") ax0.scatter( df_future.index, df_future, c="tab:blue", lw=3, ) ax0.plot( [values.index[-1], df_future.index[0]], [ values.values[-1], df_future.values[0], ], lw=2, c="tab:blue", ls="--", ) ax0.scatter(df_pred.index, df_pred, c="green", lw=3) ax0.plot( [values.index[-1], df_pred.index[0]], [values.values[-1], df_pred.values[0]], lw=2, c="green", ls="--", ) ax0.set_title("BACKTESTING: Prices") ax0.set_xlim( values.index[-1], df_pred.index[-1] + datetime.timedelta(days=1), ) ax0.set_ylabel("Share Price ($)") ax0.grid(b=True, which="major", color="#666666", linestyle="-") ax0.legend(["Real data", "Prediction data"]) ax1 = ax[1] ax1.axhline(y=0, color="k", linestyle="--", linewidth=2) ax1.plot( df_future.index, 100 * (df_pred.values - df_future.values) / df_future.values, lw=2, c="red", ) ax1.scatter( df_future.index, 100 * (df_pred.values - df_future.values) / df_future.values, c="red", lw=5, ) ax1.set_title("BACKTESTING: % Error") ax1.plot( [values.index[-1], df_future.index[0]], [ 0, 100 * (df_pred.values[0] - df_future.values[0]) / df_future.values[0], ], lw=2, ls="--", c="red", ) ax1.set_xlim( values.index[-1], df_pred.index[-1] + datetime.timedelta(days=1), ) ax1.set_xlabel("Time") ax1.set_ylabel("Prediction Error (%)") ax1.grid(b=True, which="major", color="#666666", linestyle="-") ax1.legend(["Real data", "Prediction data"]) ax0.xaxis.set_major_formatter(dateFmt) ax0.tick_params(axis="x", labelrotation=45) ax1.xaxis.set_major_formatter(dateFmt) ax1.tick_params(axis="x", labelrotation=45) if gtff.USE_ION: plt.ion() fig.tight_layout() plt.show() # Refactor prediction dataframe for backtesting print df_pred.name = "Prediction" df_pred = df_pred.to_frame() df_pred["Real"] = df_future if gtff.USE_COLOR: patch_pandas_text_adjustment() console.print("Time Real [$] x Prediction [$]") console.print( df_pred.apply(price_prediction_backtesting_color, axis=1).to_string()) else: console.print(df_pred[["Real", "Prediction"]].round(2).to_string()) console.print("") print_prediction_kpis(df_pred["Real"].values, df_pred["Prediction"].values) else: # Print prediction data print_pretty_prediction(df_pred, values.values[-1]) export_data(export, os.path.dirname(os.path.abspath(__file__)), "ets") console.print("")
def display_regression( dataset: str, values: Union[pd.Series, pd.DataFrame], poly_order: int, n_input: int, n_predict: int, n_jumps: int, s_end_date: str = "", export: str = "", time_res: str = "", ): """Display predications for regression models Parameters ---------- dataset : str Title for data values : Union[pd.Series, pd.DataFrame] Data to fit poly_order : int Order of polynomial to fit n_input : int Length of input sequence n_predict : int Length of prediction sequence n_jumps : int Number of jumps in data s_end_date : str, optional Start date for backtesting export : str, optional Format for exporting figures time_res : str Resolution for data, allowing for predicting outside of standard market days """ # BACKTESTING if s_end_date: if not time_res: future_index = get_next_stock_market_days( last_stock_day=s_end_date, n_next_days=n_predict) else: future_index = pd.date_range(s_end_date, periods=n_predict + 1, freq=time_res)[1:] df_future = values[future_index[0]:future_index[-1]] values = values[:s_end_date] # type: ignore l_predictions, _ = regression_model.get_regression_model( values, poly_order, n_input, n_predict, n_jumps) # Prediction data if not time_res: l_pred_days = get_next_stock_market_days( last_stock_day=values.index[-1], n_next_days=n_predict, ) else: l_pred_days = pd.date_range(values.index[-1], periods=n_predict + 1, freq=time_res)[1:] df_pred = pd.Series(l_predictions, index=l_pred_days, name="Price") # Plotting fig, ax = plt.subplots(figsize=plot_autoscale(), dpi=PLOT_DPI) ax.plot(values.index, values, lw=2) # BACKTESTING if s_end_date: ax.set_title( f"BACKTESTING: Regression (polynomial {poly_order}) on {dataset} - {n_predict} step prediction" ) else: ax.set_title( f"Regression (polynomial {poly_order}) on {dataset} - {n_predict} step prediction" ) ax.set_xlim(values.index[0], l_pred_days[-1]) ax.set_xlabel("Time") ax.set_ylabel("Value") ax.grid(b=True, which="major", color="#666666", linestyle="-") ax.minorticks_on() ax.grid(b=True, which="minor", color="#999999", linestyle="-", alpha=0.2) ax.plot( [values.index[-1], df_pred.index[0]], [values.values[-1], df_pred.values[0]], lw=1, c="tab:green", linestyle="--", ) ax.plot(df_pred.index, df_pred, lw=2, c="tab:green") ax.axvspan(values.index[-1], df_pred.index[-1], facecolor="tab:orange", alpha=0.2) _, _, ymin, ymax = plt.axis() ax.vlines(values.index[-1], ymin, ymax, linewidth=1, linestyle="--", color="k") # BACKTESTING if s_end_date: ax.plot( df_future.index, df_future, lw=2, c="tab:blue", ls="--", ) ax.plot( [values.index[-1], df_future.index[0]], [ values.values[-1], df_future.values[0], ], lw=1, c="tab:blue", linestyle="--", ) fig.tight_layout() if gtff.USE_ION: plt.ion() plt.show() export_data(export, os.path.dirname(os.path.abspath(__file__)), "regression") console.print("") # BACKTESTING if s_end_date: fig, ax = plt.subplots(1, 2, figsize=plot_autoscale(), dpi=PLOT_DPI) ax0 = ax[0] ax0.plot( df_future.index, df_future, lw=2, c="tab:blue", ls="--", ) ax0.plot(df_pred.index, df_pred, lw=2, c="green") ax0.scatter(df_future.index, df_future, c="tab:blue", lw=3) ax0.plot( [values.index[-1], df_future.index[0]], [ values.values[-1], df_future.values[0], ], lw=2, c="tab:blue", ls="--", ) ax0.scatter(df_pred.index, df_pred, c="green", lw=3) ax0.plot( [values.index[-1], df_pred.index[0]], [values.values[-1], df_pred.values[0]], lw=2, c="green", ls="--", ) ax0.set_title("BACKTESTING: Real data vs Prediction") ax0.set_xlim(values.index[-1], df_pred.index[-1]) ax0.set_xticks([values.index[-1], df_pred.index[-1]]) ax0.set_ylabel("Value") ax0.grid(b=True, which="major", color="#666666", linestyle="-") ax0.minorticks_on() ax0.grid(b=True, which="minor", color="#999999", linestyle="-", alpha=0.2) ax0.legend(["Real data", "Prediction data"]) ax0.set_xticks([]) ax1 = ax[1] ax1.axhline(y=0, color="k", linestyle="--", linewidth=2) ax1.plot( df_future.index, 100 * (df_pred.values - df_future.values) / df_future.values, lw=2, c="red", ) ax1.scatter( df_future.index, 100 * (df_pred.values - df_future.values) / df_future.values, c="red", lw=5, ) ax1.set_title( "BACKTESTING: Error between Real data and Prediction [%]") ax1.plot( [values.index[-1], df_future.index[0]], [ 0, 100 * (df_pred.values[0] - df_future.values[0]) / df_future.values[0], ], lw=2, ls="--", c="red", ) ax1.set_xlim(values.index[-1], df_pred.index[-1]) ax1.set_xticks([values.index[-1], df_pred.index[-1]]) ax1.set_xlabel("Time") ax1.set_ylabel("Prediction Error (%)") ax1.grid(b=True, which="major", color="#666666", linestyle="-") ax1.minorticks_on() ax1.grid(b=True, which="minor", color="#999999", linestyle="-", alpha=0.2) ax1.legend(["Real data", "Prediction data"]) fig.tight_layout() if gtff.USE_ION: plt.ion() plt.show() # Refactor prediction dataframe for backtesting print df_pred.name = "Prediction" df_pred = df_pred.to_frame() df_pred["Real"] = df_future if gtff.USE_COLOR: patch_pandas_text_adjustment() console.print("Time Real [$] x Prediction [$]") console.print( df_pred.apply(price_prediction_backtesting_color, axis=1).to_string()) else: console.print(df_pred[["Real", "Prediction"]].round(2).to_string()) console.print("") print_prediction_kpis(df_pred["Real"].values, df_pred["Prediction"].values) else: # Print prediction data print_pretty_prediction(df_pred, values.values[-1]) console.print("")
def orders(l_args): parser = argparse.ArgumentParser( prog="orders", description=""" Orders by Fidelity customers. Information shown in the table below is based on the volume of orders entered on the "as of" date shown. Securities identified are not recommended or endorsed by Fidelity and are displayed for informational purposes only. [Source: Fidelity] """, ) parser.add_argument( "-n", "--num", action="store", dest="n_num", type=check_positive, default=10, help="Number of top ordered stocks to be printed.", ) ns_parser = parse_known_args_and_warn(parser, l_args) url_orders = ( "https://eresearch.fidelity.com/eresearch/gotoBL/fidelityTopOrders.jhtml" ) text_soup_url_orders = BeautifulSoup( requests.get(url_orders, headers={ "User-Agent": get_user_agent() }).text, "lxml") l_orders = list() l_orders_vals = list() idx = 0 order_list = text_soup_url_orders.findAll( "td", { "class": [ "second", "third", "fourth", "fifth", "sixth", "seventh", "eight" ] }, ) for an_order in order_list: if ((idx + 1) % 3 == 0) or ((idx + 1) % 4 == 0) or ((idx + 1) % 6 == 0): if not an_order: l_orders_vals.append("") else: l_orders_vals.append(an_order.contents[1]) elif (idx + 1) % 5 == 0: s_orders = str(an_order) l_orders_vals.append(s_orders[s_orders.find('title="') + len('title="'):s_orders.find('"/>')]) else: l_orders_vals.append(an_order.text.strip()) idx += 1 # Add value to dictionary if (idx + 1) % 8 == 0: l_orders.append(l_orders_vals) l_orders_vals = list() idx = 0 df_orders = pd.DataFrame( l_orders, columns=[ "Symbol", "Company", "Price Change", "# Buy Orders", "Buy / Sell Ratio", "# Sell Orders", "Latest News", ], ) df_orders = df_orders[[ "Symbol", "Buy / Sell Ratio", "Price Change", "Company", "# Buy Orders", "# Sell Orders", "Latest News", ]] print( text_soup_url_orders.findAll("span", {"class": "source"}) [0].text.capitalize() + ":") pd.set_option("display.max_colwidth", -1) if USE_COLOR: df_orders["Buy / Sell Ratio"] = df_orders["Buy / Sell Ratio"].apply( buy_sell_ratio_color_red_green) df_orders["Price Change"] = df_orders["Price Change"].apply( price_change_color_red_green) patch_pandas_text_adjustment() print( df_orders.head(n=ns_parser.n_num).iloc[:, :-1].to_string(index=False)) print("")
def display_regression( dataset: str, values: Union[pd.Series, pd.DataFrame], poly_order: int, n_input: int, n_predict: int, n_jumps: int, s_end_date: str = "", export: str = "", time_res: str = "", external_axes: Optional[List[plt.Axes]] = None, ): """Display predications for regression models Parameters ---------- dataset : str Title for data values : Union[pd.Series, pd.DataFrame] Data to fit poly_order : int Order of polynomial to fit n_input : int Length of input sequence n_predict : int Length of prediction sequence n_jumps : int Number of jumps in data s_end_date : str, optional Start date for backtesting export : str, optional Format for exporting figures time_res : str Resolution for data, allowing for predicting outside of standard market days external_axes : Optional[List[plt.Axes]], optional External axes (1 axis is expected in the list), by default None """ # BACKTESTING if s_end_date: if not time_res: future_index = get_next_stock_market_days( last_stock_day=s_end_date, n_next_days=n_predict ) else: future_index = pd.date_range( s_end_date, periods=n_predict + 1, freq=time_res )[1:] df_future = values[future_index[0] : future_index[-1]] # noqa: E203 values = values[:s_end_date] # type: ignore l_predictions, _ = regression_model.get_regression_model( list(values.values), poly_order, n_input, n_predict, n_jumps ) # Prediction data if not time_res: l_pred_days = get_next_stock_market_days( last_stock_day=values.index[-1], n_next_days=n_predict, ) else: l_pred_days = pd.date_range( values.index[-1], periods=n_predict + 1, freq=time_res )[1:] df_pred = pd.Series(l_predictions, index=l_pred_days, name="Price") # Plotting # This plot has 1 axes if external_axes is None: _, ax1 = plt.subplots(figsize=plot_autoscale(), dpi=PLOT_DPI) else: if (not s_end_date and len(external_axes) != 1) or ( s_end_date and len(external_axes) != 3 ): logger.error("Expected list of 1 axis or 3 axes when backtesting.") console.print( "[red]Expected list of 1 axis or 3 axes when backtesting./n[/red]" ) return ax1 = external_axes[0] ax1.plot(values.index, values) # BACKTESTING if s_end_date: ax1.set_title( f"BACKTESTING: Regression (polynomial {poly_order}) on {dataset} - {n_predict} step prediction", fontsize=12, ) else: ax1.set_title( f"Regression (polynomial {poly_order}) on {dataset} - {n_predict} step prediction" ) ax1.set_xlim(values.index[0], l_pred_days[-1]) ax1.set_ylabel("Value") ax1.plot( [values.index[-1], df_pred.index[0]], [values.values[-1], df_pred.values[0]], color=theme.down_color, linestyle="--", ) ax1.plot(df_pred.index, df_pred, color=theme.down_color) ax1.axvspan(values.index[-1], df_pred.index[-1], alpha=0.2) _, _, ymin, ymax = plt.axis() ax1.vlines(values.index[-1], ymin, ymax, linestyle="--") # BACKTESTING if s_end_date: ax1.plot( df_future.index, df_future, color=theme.up_color, linestyle="--", ) ax1.plot( [values.index[-1], df_future.index[0]], [ values.values[-1], df_future.values[0], ], color=theme.up_color, linestyle="--", ) theme.style_primary_axis(ax1) if external_axes is None: theme.visualize_output() export_data(export, os.path.dirname(os.path.abspath(__file__)), "regression") console.print("") # BACKTESTING if s_end_date: # This plot has 1 axes if external_axes is None: _, axes = plt.subplots( 2, 1, sharex=True, figsize=plot_autoscale(), dpi=PLOT_DPI ) (ax2, ax3) = axes else: if len(external_axes) != 3: logger.error("Expected list of three axis items.") console.print("[red]Expected list of 3 axis items./n[/red]") return (_, ax2, ax3) = external_axes ax2.plot( df_future.index, df_future, color=theme.up_color, linestyle="--", ) ax2.plot(df_pred.index, df_pred, color=theme.down_color, marker="o") ax2.plot( [values.index[-1], df_future.index[0]], [ values.values[-1], df_future.values[0], ], color=theme.up_color, linestyle="--", ) ax2.plot( [values.index[-1], df_pred.index[0]], [values.values[-1], df_pred.values[0]], color=theme.down_color, linestyle="--", marker="o", ) ax2.set_title("BACKTESTING: Real data vs Prediction", fontsize=12) ax2.set_xlim(values.index[-1], df_pred.index[-1]) ax2.set_ylabel("Value") ax2.legend(["Real data", "Prediction data"]) ax3.axhline(y=0, linestyle="--", color=theme.up_color) ax3.plot( df_future.index, 100 * (df_pred.values - df_future.values) / df_future.values, color=theme.down_color, marker="o", ) ax3.set_title( "BACKTESTING: Error between Real data and Prediction [%]", fontsize=12 ) ax3.plot( [values.index[-1], df_future.index[0]], [ 0, 100 * (df_pred.values[0] - df_future.values[0]) / df_future.values[0], ], linestyle="--", color=theme.down_color, ) ax3.set_xlim(values.index[-1], df_pred.index[-1]) ax3.set_xlabel("Time") ax3.set_ylabel("Error (%)") ax3.legend(["Real data", "Prediction data"]) theme.style_primary_axis(ax2) theme.style_primary_axis(ax3) if external_axes is None: theme.visualize_output() # Refactor prediction dataframe for backtesting print df_pred.name = "Prediction" df_pred = df_pred.to_frame() df_pred["Real"] = df_future if rich_config.USE_COLOR: patch_pandas_text_adjustment() console.print("Time Real [$] x Prediction [$]") console.print( df_pred.apply( lambda_price_prediction_backtesting_color, axis=1 ).to_string() ) else: console.print(df_pred[["Real", "Prediction"]].round(2).to_string()) console.print("") print_prediction_kpis(df_pred["Real"].values, df_pred["Prediction"].values) else: # Print prediction data print_pretty_prediction(df_pred, values.values[-1]) console.print("")
def arima(other_args: List[str], s_ticker: str, df_stock: pd.DataFrame): """ ARIMA prediction Parameters ---------- other_args: List[str] Argparse arguments s_ticker: str ticker df_stock: pd.DataFrame Dataframe of prices """ parser = argparse.ArgumentParser( add_help=False, prog="arima", description=""" In statistics and econometrics, and in particular in time series analysis, an autoregressive integrated moving average (ARIMA) model is a generalization of an autoregressive moving average (ARMA) model. Both of these models are fitted to time series data either to better understand the data or to predict future points in the series (forecasting). ARIMA(p,d,q) where parameters p, d, and q are non-negative integers, p is the order (number of time lags) of the autoregressive model, d is the degree of differencing (the number of times the data have had past values subtracted), and q is the order of the moving-average model. """, ) parser.add_argument( "-d", "--days", action="store", dest="n_days", type=check_positive, default=5, help="prediction days.", ) parser.add_argument( "-i", "--ic", action="store", dest="s_ic", type=str, default="aic", choices=["aic", "aicc", "bic", "hqic", "oob"], help="information criteria.", ) parser.add_argument( "-s", "--seasonal", action="store_true", default=False, dest="b_seasonal", help="Use weekly seasonal data.", ) parser.add_argument( "-o", "--order", action="store", dest="s_order", type=str, help="arima model order (p,d,q) in format: p,d,q.", ) parser.add_argument( "-r", "--results", action="store_true", dest="b_results", default=False, help="results about ARIMA summary flag.", ) parser.add_argument( "-e", "--end", action="store", type=valid_date, dest="s_end_date", default=None, help="The end date (format YYYY-MM-DD) to select - Backtesting", ) try: ns_parser = parse_known_args_and_warn(parser, other_args) if not ns_parser: return # BACKTESTING if ns_parser.s_end_date: if ns_parser.s_end_date < df_stock.index[0]: print( "Backtesting not allowed, since End Date is older than Start Date of historical data\n" ) return if (ns_parser.s_end_date < get_next_stock_market_days( last_stock_day=df_stock.index[0], n_next_days=5 + ns_parser.n_days)[-1]): print( "Backtesting not allowed, since End Date is too close to Start Date to train model\n" ) return future_index = get_next_stock_market_days( last_stock_day=ns_parser.s_end_date, n_next_days=ns_parser.n_days) if future_index[-1] > datetime.datetime.now(): print( "Backtesting not allowed, since End Date + Prediction days is in the future\n" ) return df_future = df_stock[future_index[0]:future_index[-1]] df_stock = df_stock[:ns_parser.s_end_date] # Machine Learning model if ns_parser.s_order: t_order = tuple(int(ord) for ord in ns_parser.s_order.split(",")) model = ARIMA(df_stock["5. adjusted close"].values, order=t_order).fit() l_predictions = model.predict( start=len(df_stock["5. adjusted close"]) + 1, end=len(df_stock["5. adjusted close"]) + ns_parser.n_days, ) else: if ns_parser.b_seasonal: model = pmdarima.auto_arima( df_stock["5. adjusted close"].values, error_action="ignore", seasonal=True, m=5, information_criteria=ns_parser.s_ic, ) else: model = pmdarima.auto_arima( df_stock["5. adjusted close"].values, error_action="ignore", seasonal=False, information_criteria=ns_parser.s_ic, ) l_predictions = [ i if i > 0 else 0 for i in model.predict(n_periods=ns_parser.n_days) ] # Prediction data l_pred_days = get_next_stock_market_days( last_stock_day=df_stock["5. adjusted close"].index[-1], n_next_days=ns_parser.n_days, ) df_pred = pd.Series(l_predictions, index=l_pred_days, name="Price") if ns_parser.b_results: print(model.summary()) print("") # Plotting plt.figure(figsize=plot_autoscale(), dpi=PLOT_DPI) plt.plot(df_stock.index, df_stock["5. adjusted close"], lw=2) if ns_parser.s_order: # BACKTESTING if ns_parser.s_end_date: plt.title( f"BACKTESTING: ARIMA {str(t_order)} on {s_ticker} - {ns_parser.n_days} days prediction" ) else: plt.title( f"ARIMA {str(t_order)} on {s_ticker} - {ns_parser.n_days} days prediction" ) else: # BACKTESTING if ns_parser.s_end_date: plt.title( f"BACKTESTING: ARIMA {model.order} on {s_ticker} - {ns_parser.n_days} days prediction" ) else: plt.title( f"ARIMA {model.order} on {s_ticker} - {ns_parser.n_days} days prediction" ) plt.xlim(df_stock.index[0], get_next_stock_market_days(df_pred.index[-1], 1)[-1]) plt.xlabel("Time") plt.ylabel("Share Price ($)") plt.grid(b=True, which="major", color="#666666", linestyle="-") plt.minorticks_on() plt.grid(b=True, which="minor", color="#999999", linestyle="-", alpha=0.2) plt.plot( [df_stock.index[-1], df_pred.index[0]], [df_stock["5. adjusted close"].values[-1], df_pred.values[0]], lw=1, c="tab:green", linestyle="--", ) plt.plot(df_pred.index, df_pred, lw=2, c="tab:green") plt.axvspan(df_stock.index[-1], df_pred.index[-1], facecolor="tab:orange", alpha=0.2) _, _, ymin, ymax = plt.axis() plt.vlines(df_stock.index[-1], ymin, ymax, linewidth=1, linestyle="--", color="k") # BACKTESTING if ns_parser.s_end_date: plt.plot( df_future.index, df_future["5. adjusted close"], lw=2, c="tab:blue", ls="--", ) plt.plot( [df_stock.index[-1], df_future.index[0]], [ df_stock["5. adjusted close"].values[-1], df_future["5. adjusted close"].values[0], ], lw=1, c="tab:blue", linestyle="--", ) if gtff.USE_ION: plt.ion() plt.show() # BACKTESTING if ns_parser.s_end_date: plt.figure(figsize=plot_autoscale(), dpi=PLOT_DPI) plt.subplot(211) plt.plot( df_future.index, df_future["5. adjusted close"], lw=2, c="tab:blue", ls="--", ) plt.plot(df_pred.index, df_pred, lw=2, c="green") plt.scatter(df_future.index, df_future["5. adjusted close"], c="tab:blue", lw=3) plt.plot( [df_stock.index[-1], df_future.index[0]], [ df_stock["5. adjusted close"].values[-1], df_future["5. adjusted close"].values[0], ], lw=2, c="tab:blue", ls="--", ) plt.scatter(df_pred.index, df_pred, c="green", lw=3) plt.plot( [df_stock.index[-1], df_pred.index[0]], [df_stock["5. adjusted close"].values[-1], df_pred.values[0]], lw=2, c="green", ls="--", ) plt.title("BACKTESTING: Real data price versus Prediction") plt.xlim(df_stock.index[-1], df_pred.index[-1] + datetime.timedelta(days=1)) plt.xticks( [ df_stock.index[-1], df_pred.index[-1] + datetime.timedelta(days=1) ], visible=True, ) plt.ylabel("Share Price ($)") plt.grid(b=True, which="major", color="#666666", linestyle="-") plt.minorticks_on() plt.grid(b=True, which="minor", color="#999999", linestyle="-", alpha=0.2) plt.legend(["Real data", "Prediction data"]) plt.xticks([]) plt.subplot(212) plt.axhline(y=0, color="k", linestyle="--", linewidth=2) plt.plot( df_future.index, 100 * (df_pred.values - df_future["5. adjusted close"].values) / df_future["5. adjusted close"].values, lw=2, c="red", ) plt.scatter( df_future.index, 100 * (df_pred.values - df_future["5. adjusted close"].values) / df_future["5. adjusted close"].values, c="red", lw=5, ) plt.title( "BACKTESTING: Error between Real data and Prediction [%]") plt.plot( [df_stock.index[-1], df_future.index[0]], [ 0, 100 * (df_pred.values[0] - df_future["5. adjusted close"].values[0]) / df_future["5. adjusted close"].values[0], ], lw=2, ls="--", c="red", ) plt.xlim(df_stock.index[-1], df_pred.index[-1] + datetime.timedelta(days=1)) plt.xticks( [ df_stock.index[-1], df_pred.index[-1] + datetime.timedelta(days=1) ], visible=True, ) plt.xlabel("Time") plt.ylabel("Prediction Error (%)") plt.grid(b=True, which="major", color="#666666", linestyle="-") plt.minorticks_on() plt.grid(b=True, which="minor", color="#999999", linestyle="-", alpha=0.2) plt.legend(["Real data", "Prediction data"]) if gtff.USE_ION: plt.ion() plt.show() # Refactor prediction dataframe for backtesting print df_pred.name = "Prediction" df_pred = df_pred.to_frame() df_pred["Real"] = df_future["5. adjusted close"] if gtff.USE_COLOR: patch_pandas_text_adjustment() print("Time Real [$] x Prediction [$]") print( df_pred.apply(price_prediction_backtesting_color, axis=1).to_string()) else: print(df_pred[["Real", "Prediction"]].round(2).to_string()) print("") print_prediction_kpis(df_pred["Real"].values, df_pred["Prediction"].values) else: # Print prediction data print_pretty_prediction(df_pred, df_stock["5. adjusted close"].values[-1]) print("") except Exception as e: print(e, "\n")
def display_arima( dataset: str, values: Union[pd.DataFrame, pd.Series], arima_order: str, n_predict: int, seasonal: bool, ic: str, results: bool, s_end_date: str = "", export: str = "", ): """View fit ARIMA model Parameters ---------- dataset : str String indicating dataset (for plot title) values : Union[pd.DataFrame, pd.Series] Data to fit arima_order : str String of ARIMA params in form "p,q,d" n_predict : int Days to predict seasonal : bool Flag to use seasonal model ic : str Information Criteria for model evaluation results : bool Flag to display model summary s_end_date : str, optional Specified end date for backtesting comparisons export : str, optional Format to export image """ if arima_order: t_order = tuple(int(ord) for ord in arima_order.split(",")) if s_end_date: future_index = get_next_stock_market_days(last_stock_day=s_end_date, n_next_days=n_predict) if future_index[-1] > datetime.datetime.now(): print( "Backtesting not allowed, since End Date + Prediction days is in the future\n" ) return df_future = values[future_index[0]:future_index[-1]] values = values[:s_end_date] # type: ignore l_predictions, model = arima_model.get_arima_model(values, arima_order, n_predict, seasonal, ic) # Prediction data l_pred_days = get_next_stock_market_days( last_stock_day=values.index[-1], n_next_days=n_predict, ) df_pred = pd.Series(l_predictions, index=l_pred_days, name="Price") if results: print(model.summary()) print("") # Plotting fig, ax = plt.subplots(figsize=plot_autoscale(), dpi=PLOT_DPI) ax.plot(values.index, values, lw=2) # pylint:disable=no-member if arima_order: # BACKTESTING if s_end_date: ax.set_title( f"BACKTESTING: ARIMA {str(t_order)} on {dataset} - {n_predict} days prediction" ) else: ax.set_title( f"ARIMA {str(t_order)} on {dataset} - {n_predict} days prediction" ) else: # BACKTESTING if s_end_date: ax.set_title( f"BACKTESTING: ARIMA {model.order} on {dataset} - {n_predict} days prediction" ) else: plt.title( f"ARIMA {model.order} on {dataset} - {n_predict} days prediction" ) ax.set_xlim(values.index[0], get_next_stock_market_days(df_pred.index[-1], 1)[-1]) ax.set_xlabel("Time") ax.set_ylabel("Value") ax.grid(b=True, which="major", color="#666666", linestyle="-") ax.minorticks_on() ax.grid(b=True, which="minor", color="#999999", linestyle="-", alpha=0.2) ax.plot( [values.index[-1], df_pred.index[0]], [values.values[-1], df_pred.values[0]], lw=1, c="tab:green", linestyle="--", ) ax.plot(df_pred.index, df_pred, lw=2, c="tab:green") ax.axvspan(values.index[-1], df_pred.index[-1], facecolor="tab:orange", alpha=0.2) _, _, ymin, ymax = plt.axis() ax.vlines(values.index[-1], ymin, ymax, linewidth=1, linestyle="--", color="k") # BACKTESTING if s_end_date: ax.plot( df_future.index, df_future.values, lw=2, c="tab:blue", ls="--", ) plt.plot( [values.index[-1], df_future.index[0]], [ values.values[-1], df_future.values[0], ], lw=1, c="tab:blue", linestyle="--", ) fig.tight_layout() if gtff.USE_ION: plt.ion() plt.show() # BACKTESTING if s_end_date: fig, ax = plt.subplots(1, 2, figsize=plot_autoscale(), dpi=PLOT_DPI) ax0 = ax[0] ax0.plot( df_future.index, df_future.values, lw=2, c="tab:blue", ls="--", ) ax0.plot(df_pred.index, df_pred, lw=2, c="green") ax0.scatter(df_future.index, df_future, c="tab:blue", lw=3) ax0.plot( [values.index[-1], df_future.index[0]], [ values.values[-1], df_future.values[0], ], lw=2, c="tab:blue", ls="--", ) ax0.scatter(df_pred.index, df_pred, c="green", lw=3) ax0.plot( [values.index[-1], df_pred.index[0]], [values.values[-1], df_pred.values[0]], lw=2, c="green", ls="--", ) ax0.set_title("BACKTESTING: Real data Prediction") ax0.set_xlim(values.index[-1], df_pred.index[-1] + datetime.timedelta(days=1)) ax0.set_xticks( [values.index[-1], df_pred.index[-1] + datetime.timedelta(days=1)]) ax0.set_ylabel("Value") ax0.grid(b=True, which="major", color="#666666", linestyle="-") ax0.minorticks_on() ax0.grid(b=True, which="minor", color="#999999", linestyle="-", alpha=0.2) ax0.legend(["Real data", "Prediction data"]) ax0.set_xticks([]) ax1 = ax[1] ax1.axhline(y=0, color="k", linestyle="--", linewidth=2) ax1.plot( df_future.index, 100 * (df_pred.values - df_future.values) / df_future.values, lw=2, c="red", ) ax1.scatter( df_future.index, 100 * (df_pred.values - df_future.values) / df_future.values, c="red", lw=5, ) ax1.set_title( "BACKTESTING: Error between Real data and Prediction [%]") ax1.plot( [values.index[-1], df_future.index[0]], [ 0, 100 * (df_pred.values[0] - df_future.values[0]) / df_future.values[0], ], lw=2, ls="--", c="red", ) ax1.set_xlim(values.index[-1], df_pred.index[-1] + datetime.timedelta(days=1)) ax1.set_xticks( [values.index[-1], df_pred.index[-1] + datetime.timedelta(days=1)]) ax1.set_xlabel("Time") ax1.set_ylabel("Prediction Error (%)") ax1.grid(b=True, which="major", color="#666666", linestyle="-") ax1.minorticks_on() ax1.grid(b=True, which="minor", color="#999999", linestyle="-", alpha=0.2) ax1.legend(["Real data", "Prediction data"]) fig.tight_layout() if gtff.USE_ION: plt.ion() plt.show() # Refactor prediction dataframe for backtesting print df_pred.name = "Prediction" df_pred = df_pred.to_frame() df_pred["Real"] = df_future.values if gtff.USE_COLOR: if gtff.USE_TABULATE_DF: df_pred["Real"] = df_pred["Real"].astype(float) df_pred["Prediction"] = df_pred["Prediction"].astype(float) df_pred["Dif"] = (100 * (df_pred.Prediction - df_pred.Real) / df_pred.Real) print( tabulate( df_pred, headers=[ "Date", "Predicted", "Actual", "% Difference" ], showindex=True, floatfmt=".2f", tablefmt="fancy_grid", )) else: patch_pandas_text_adjustment() print("Time Real [$] x Prediction [$]") print( df_pred.apply(price_prediction_backtesting_color, axis=1).to_string()) else: if gtff.USE_TABULATE_DF: df_pred["Real"] = df_pred["Real"].astype(float) df_pred["Prediction"] = df_pred["Predicted"].astype(float) df_pred["Dif"] = (100 * (df_pred.Prediction - df_pred.Real) / df_pred.Real) print( tabulate( df_pred, headers=[ "Date", "Predicted", "Actual", "% Difference" ], showindex=True, floatfmt=".2f", tablefmt="fancy_grid", )) else: print(df_pred[["Real", "Prediction"]].round(2).to_string()) print("") print_prediction_kpis(df_pred["Real"].values, df_pred["Prediction"].values) else: # Print prediction data print_pretty_prediction(df_pred, values.values[-1]) export_data(export, os.path.dirname(os.path.abspath(__file__)), "arima") print("")