diff --git a/fundamental_analysis/fa_menu.py b/fundamental_analysis/fa_menu.py index bbdf3e0a3ef..5f189d477aa 100644 --- a/fundamental_analysis/fa_menu.py +++ b/fundamental_analysis/fa_menu.py @@ -15,6 +15,7 @@ from fundamental_analysis import financial_modeling_prep_api as fmp_api from fundamental_analysis import finviz_api as fvz_api from fundamental_analysis import market_watch_api as mw_api from fundamental_analysis import reddit_api as r_api +from fundamental_analysis import quandl_api as q_api # ----------------------------------------------------------------------------------------------------------------------- @@ -36,6 +37,7 @@ def print_fundamental_analysis(s_ticker, s_start, s_interval): print("") print(" dd gets due diligence from another user's post [Reddit]") print(" warnings company warnings according to Sean Seah book [Market Watch]") + print(" short short interest [Quandl]") print("\nFinviz API") print(" screener screen info about the company") print(" insider insider trading of the company") @@ -115,7 +117,7 @@ def fa_menu(s_ticker, s_start, s_interval): # Add list of arguments that the fundamental analysis parser accepts fa_parser = argparse.ArgumentParser(prog='fundamental_analysis', add_help=False) - fa_parser.add_argument('cmd', choices=['info', 'help', 'q', 'quit', 'more', 'warnings', 'dd', + fa_parser.add_argument('cmd', choices=['info', 'help', 'q', 'quit', 'more', 'warnings', 'dd', 'short', 'screener', 'insider', 'news', 'analyst', # Finviz 'income', 'assets', 'liabilities', 'operating', 'investing', 'financing', 'sec']) # MW @@ -153,6 +155,9 @@ def fa_menu(s_ticker, s_start, s_interval): elif ns_known_args.cmd == 'warnings': mw_api.sean_seah_warnings(l_args, s_ticker) + + elif ns_known_args.cmd == 'short': + q_api.short_interest(l_args, s_ticker, s_start) # FINVIZ API elif ns_known_args.cmd == 'screener': diff --git a/fundamental_analysis/quandl_api.py b/fundamental_analysis/quandl_api.py new file mode 100644 index 00000000000..ad2d3af7039 --- /dev/null +++ b/fundamental_analysis/quandl_api.py @@ -0,0 +1,69 @@ +import quandl +from datetime import datetime +import config_bot as cfg +import argparse +from matplotlib import pyplot as plt +import numpy as np +import matplotlib.ticker as ticker +import pandas as pd +from stock_market_helper_funcs import * + +# -------------------------------------------------------- SHORT_INTEREST -------------------------------------------------------- +def short_interest(l_args, s_ticker, s_start): + parser = argparse.ArgumentParser(prog='short', + description="""Short interest corresponds to the number of shares that have been sold short + but have not yet been covered or closed out. [Source: Quandl API]""") + + parser.add_argument('-n', "--nyse", action="store_true", default=False, dest="b_nyse", help='Data from NYSE') + parser.add_argument('-d', "--days", action="store", dest="n_days", type=check_positive, default=10, help='Number of latest days to see data') + + try: + (ns_parser, l_unknown_args) = parser.parse_known_args(l_args) + + if l_unknown_args: + print(f"The following args couldn't be interpreted: {l_unknown_args}\n") + return + + quandl.ApiConfig.api_key = cfg.API_KEY_QUANDL + + if ns_parser.b_nyse: + df_short_interest = quandl.get(f"FINRA/FNYX_{s_ticker}") + else: + df_short_interest = quandl.get(f"FINRA/FNSQ_{s_ticker}") + + df_short_interest = df_short_interest[s_start:] + df_short_interest.columns = [''.join(' ' + char if char.isupper() else char.strip() for char in idx).strip() for idx in df_short_interest.columns.tolist()] + df_short_interest['% of Volume Shorted'] = round(100*df_short_interest['Short Volume']/df_short_interest['Total Volume'], 2) + + fig, ax = plt.subplots() + ax.bar(df_short_interest.index, df_short_interest['Short Volume'], 0.3, color='r') + ax.bar(df_short_interest.index, df_short_interest['Total Volume']-df_short_interest['Short Volume'], 0.3, bottom=df_short_interest['Short Volume'], color='b') + ax.set_ylabel('Shares') + ax.set_xlabel('Date') + + ax.set_title(f"{('NASDAQ', 'NYSE')[ns_parser.b_nyse]} Short Interest on {s_ticker} from {s_start.date()}") + + ax.legend(labels=['Short Volume', 'Total Volume']) + ax.tick_params(axis='both', which='major') + ax.yaxis.set_major_formatter(ticker.EngFormatter()) + ax_twin = ax.twinx() + ax_twin.tick_params(axis='y', colors='green') + ax_twin.set_ylabel('Percentage of Volume Shorted', color='green') + ax_twin.plot(df_short_interest.index, df_short_interest['% of Volume Shorted'], color='green') + ax_twin.tick_params(axis='y', which='major', color='green') + ax_twin.yaxis.set_major_formatter(ticker.FormatStrFormatter('%.0f%%')) + plt.xlim([df_short_interest.index[0], df_short_interest.index[-1]]) + + df_short_interest['% of Volume Shorted'] = df_short_interest['% of Volume Shorted'].apply(lambda x: f'{x/100:.2%}') + df_short_interest = df_short_interest.applymap(lambda x: long_number_format(x)).sort_index(ascending=False) + + pd.set_option('display.max_colwidth', 70) + print(df_short_interest.head(n=ns_parser.n_days).to_string()) + print("") + + plt.show() + + except: + print("") + return + \ No newline at end of file