From a1cc95757c78c3b90f1f022e8a5ea14241d84107 Mon Sep 17 00:00:00 2001 From: didier Date: Sun, 3 Jan 2021 15:04:57 +0000 Subject: [PATCH] Reorganize code structure in fa and ta folders --- config_bot.py | 2 + fundamental_analysis/.DS_Store | Bin 0 -> 6148 bytes .../alpha_vantage_api.cpython-36.pyc | Bin 0 -> 17028 bytes ...financial_modeling_prep_api.cpython-36.pyc | Bin 0 -> 28173 bytes .../__pycache__/menu.cpython-36.pyc | Bin 0 -> 4207 bytes fundamental_analysis/alpha_vantage_api.py | 327 +++++++++++ .../financial_modeling_prep_api.py | 532 ++++-------------- .../key_metrics_explained.txt | 35 ++ fundamental_analysis/menu.py | 170 ++++++ stock_market_cli.py | 260 +-------- stock_market_technical_analysis.py | 491 ---------------- technical_analysis/.DS_Store | Bin 0 -> 6148 bytes .../alpha_vantage_api.cpython-36.pyc | Bin 0 -> 17292 bytes ...financial_modeling_prep_api.cpython-36.pyc | Bin 0 -> 28851 bytes .../__pycache__/menu.cpython-36.pyc | Bin 0 -> 3074 bytes .../__pycache__/momentum.cpython-36.pyc | Bin 0 -> 6652 bytes .../__pycache__/overlap.cpython-36.pyc | Bin 0 -> 4099 bytes .../__pycache__/trend.cpython-36.pyc | Bin 0 -> 3638 bytes .../__pycache__/volatility.cpython-36.pyc | Bin 0 -> 2461 bytes .../__pycache__/volume.cpython-36.pyc | Bin 0 -> 3960 bytes technical_analysis/menu.py | 127 +++++ technical_analysis/momentum.py | 159 ++++++ technical_analysis/overlap.py | 98 ++++ technical_analysis/trend.py | 78 +++ technical_analysis/volatility.py | 46 ++ technical_analysis/volume.py | 91 +++ 26 files changed, 1276 insertions(+), 1140 deletions(-) create mode 100644 config_bot.py create mode 100644 fundamental_analysis/.DS_Store create mode 100644 fundamental_analysis/__pycache__/alpha_vantage_api.cpython-36.pyc create mode 100644 fundamental_analysis/__pycache__/financial_modeling_prep_api.cpython-36.pyc create mode 100644 fundamental_analysis/__pycache__/menu.cpython-36.pyc create mode 100644 fundamental_analysis/alpha_vantage_api.py rename stock_market_fundamental_analysis.py => fundamental_analysis/financial_modeling_prep_api.py (55%) create mode 100644 fundamental_analysis/key_metrics_explained.txt create mode 100644 fundamental_analysis/menu.py delete mode 100644 stock_market_technical_analysis.py create mode 100644 technical_analysis/.DS_Store create mode 100644 technical_analysis/__pycache__/alpha_vantage_api.cpython-36.pyc create mode 100644 technical_analysis/__pycache__/financial_modeling_prep_api.cpython-36.pyc create mode 100644 technical_analysis/__pycache__/menu.cpython-36.pyc create mode 100644 technical_analysis/__pycache__/momentum.cpython-36.pyc create mode 100644 technical_analysis/__pycache__/overlap.cpython-36.pyc create mode 100644 technical_analysis/__pycache__/trend.cpython-36.pyc create mode 100644 technical_analysis/__pycache__/volatility.cpython-36.pyc create mode 100644 technical_analysis/__pycache__/volume.cpython-36.pyc create mode 100644 technical_analysis/menu.py create mode 100644 technical_analysis/momentum.py create mode 100644 technical_analysis/overlap.py create mode 100644 technical_analysis/trend.py create mode 100644 technical_analysis/volatility.py create mode 100644 technical_analysis/volume.py diff --git a/config_bot.py b/config_bot.py new file mode 100644 index 00000000000..86b89aae11f --- /dev/null +++ b/config_bot.py @@ -0,0 +1,2 @@ +API_KEY_ALPHAVANTAGE = 'P6YGOQ6FL6OEIZ3B' +API_KEY_FINANCIALMODELINGPREP = "845b22316eeec4168d249976bba94330" \ No newline at end of file diff --git a/fundamental_analysis/.DS_Store b/fundamental_analysis/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..5008ddfcf53c02e82d7eee2e57c38e5672ef89f6 GIT binary patch literal 6148 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 J{G{-~{{m3Q`2PR^ literal 0 HcmV?d00001 diff --git a/fundamental_analysis/__pycache__/financial_modeling_prep_api.cpython-36.pyc b/fundamental_analysis/__pycache__/financial_modeling_prep_api.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4fca7be3bcd5065424eac051ddeceed34c3f8684 GIT binary patch literal 28173 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 Gy!(IOv$&uD literal 0 HcmV?d00001 diff --git a/fundamental_analysis/__pycache__/menu.cpython-36.pyc b/fundamental_analysis/__pycache__/menu.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..893dce1b44dce076d5d379d727042e4f5885da08 GIT binary patch literal 4207 zcmb7H%WvGq87H}1F11>%Ru9XsB%L&MQYDJyJPv{C8kH@nHsCmlK@sdMMCddhFGQqQ7rAE3LOGimo*Cef(aW8Gf(% zXlknZ#^Xg(PH*;;!0(2M@Z)t~_#nA~FG3M@L*VASnCkmkns`ad zyM7$yM4s{E-k$Fr`B3YGp5Kc=yxEQtKWRmN>~+&1jH9IE^?2ALcB@1$#LvcXG45kz zZL&N`O@22Lz zrs3-vzCkef3BDA|Yix^0iC}wS+++E~!$fdD@K2a5ulrGaA}b$!{PFE>lt{ChyKG0K zt%FsTSJ=1uxCTe4#q>x!GFc$0u2ot>*U_V^Pvh0o1R@)1xQ| zGeyK_7g3rp{CE8*VF%#}>xP0yt&F8@)=IlQKRL-ifu>rcwvp|n&zabZGS`ik+qEN`mF;d(qbLN%-8>`Lr~=Q~>lk2XF0U3Lni@+%OG5}Zp| zXlOhWh%1UTb!?*w??GUt9heVVZCalC1yR;Y`!E$02Ybn3j%Y7JXXyTDJq>GbmtNd*P_e9h>2)V3e9*l4ytC!dfZ_N{?&W`1p*mQL+~&2NhmYK={GNM+vgX<68V@|pRE z)l+BS?3d4s)5`Hr2Nk{tNoU^~RQ4-put3s7{^5hC2Dqv+Jw@&Q+}Jk0GM*aAtZC36 zc&@T;?0}2hKJi%Ely&nzZC#dc{oS-L{v+isv&Sgc@yRONxcBhM`r1;JobZ4C5a3H} zYh?q|#;=#y=KW22ytl-*KLc%jYnvV+vK~?5N5Xv;g>k^P$$LR1MM}f>Lg6pN)ojYE zauOw?#iJgThkWS?Qf51ik%=h!eU7Yyu!@7^9l>@(WJDFKA;JvxY56iwSV1g#I<~y< zxEG^3gu${n7PEdqz|~I^ zc=|!O`x9ffs-XV}dUcFG3Ho0_pB$st4ywd<)Lp7-vp#egJ2FjDvk*)qe)(vYndz@8Dd% z(|>_8zSDVFv-mY|u8h6sisF0-&cYaHL2({|bM=BF%7N-y4;z%Lkd3ZA&aJyFe~ZEx zy-QbhU11!ys4fO+m{A;u$5AG#%1xzB-JUcLH>FKo*AwXu8z@;qAWNs{dt^noGt#EE zMY_X2L{@YUA)TUQkY!c$W%Z(z%MuE;tmvFj2&S2IiYl02y{{LVq=NCVm39(bP=YrX zuc?Y4%Tdzn3w{$pgdp$55z61rNrpCT<2VvUQn1>7u^-1jqN@sj7t;JaOwC5I11g+F z=hmFkd+}6j)|{XndDJiP6?#Xd-Bs5eew%E3K+}gbeS`^DvGYE|JJ)MYj^w;%f8aX~p>g;(r;u_7nhzD`Y?QWmGG$7e7hH&U6$=H(R9*G0 z`k#ZGwJ{l1tz=tn$wFSLQ!TctW(}imRV|xFN#XR2QM(xS2tK5jMrfnB&DZdz#jDM^ z&5H}d@J_;i0bcX ') + + # Parse fundamental analysis command of the list of possible commands + try: + (ns_known_args, l_args) = fa_parser.parse_known_args(as_input.split()) + + except SystemExit: + print("The command selected doesn't exist\n") + continue + + if ns_known_args.fa == 'info': + info(l_args, s_ticker) + + elif ns_known_args.fa == 'help': + print_fundamental_analysis(s_ticker, s_start, s_interval) + + elif ns_known_args.fa == 'q': + # Just leave the FA menu + return False + + elif ns_known_args.fa == 'quit': + # Abandon the program + return True + + # ----------------------------------------------- ALPHA VANTAGE ---------------------------------------------- + elif ns_known_args.fa == 'overview': + av_api.overview(l_args, s_ticker) + + elif ns_known_args.fa == 'key': + av_api.key(l_args, s_ticker) + + elif ns_known_args.fa == 'income': + av_api.income_statement(l_args, s_ticker) + + elif ns_known_args.fa == 'balance': + av_api.balance_sheet(l_args, s_ticker) + + elif ns_known_args.fa == 'cash': + av_api.cash_flow(l_args, s_ticker) + + elif ns_known_args.fa == 'earnings': + av_api.earnings(l_args, s_ticker) + + # -------------------------------------------- FINANCIAL MODELING PREP ----------------------------------------- + # Details: + elif ns_known_args.fa == 'profile': + fmp_api.profile(l_args, s_ticker) + + elif ns_known_args.fa == 'rating': + fmp_api.rating(l_args, s_ticker) + + elif ns_known_args.fa == 'quote': + fmp_api.quote(l_args, s_ticker) + + elif ns_known_args.fa == 'enterprise': + fmp_api.enterprise(l_args, s_ticker) + + elif ns_known_args.fa == 'dcf': + fmp_api.discounted_cash_flow(l_args, s_ticker) + + # Financial statement: + elif ns_known_args.fa == 'income': + fmp_api.income_statement(l_args, s_ticker) + + elif ns_known_args.fa == 'balance': + fmp_api.balance_sheet(l_args, s_ticker) + + elif ns_known_args.fa == 'cash': + fmp_api.cash_flow(l_args, s_ticker) + + # Ratios: + elif ns_known_args.fa == 'metrics': + fmp_api.key_metrics(l_args, s_ticker) + + elif ns_known_args.fa == 'ratios': + fmp_api.financial_ratios(l_args, s_ticker) + + elif ns_known_args.fa == 'growth': + fmp_api.financial_statement_growth(l_args, s_ticker) + + # ------------------------------------------------------------------------------------------------------------ + else: + print("Command not recognized!") \ No newline at end of file diff --git a/stock_market_cli.py b/stock_market_cli.py index 218d408861d..b388e55f616 100644 --- a/stock_market_cli.py +++ b/stock_market_cli.py @@ -21,18 +21,17 @@ """ -from alpha_vantage.timeseries import TimeSeries import argparse -import config_bot as cfg import pandas as pd -import pandas_ta as ta -from pandas.plotting import register_matplotlib_converters -register_matplotlib_converters() - from stock_market_helper_funcs import * import stock_market_menu as smm -import stock_market_technical_analysis as smta -import stock_market_fundamental_analysis as smfa +from fundamental_analysis import menu as fam +from technical_analysis import menu as tam + +# delete this important when automatic loading tesla +#i.e. when program is done +import config_bot as cfg +from alpha_vantage.timeseries import TimeSeries # ----------------------------------------------------------------------------------------------------------------------- def print_help(s_ticker, s_start, s_interval, b_is_market_open): @@ -75,78 +74,6 @@ def print_help(s_ticker, s_start, s_interval, b_is_market_open): ''' -# ----------------------------------------------------------------------------------------------------------------------- -def print_fundamental_analysis(s_ticker, s_start, s_interval): - """ Print help """ - - s_intraday = (f'Intraday {s_interval}', 'Daily')[s_interval == "1440min"] - - if s_start: - print(f"\n{s_intraday} Stock: {s_ticker} (from {s_start.strftime('%Y-%m-%d')})") - else: - print(f"\n{s_intraday} Stock: {s_ticker}") - - print("\nFundamental Analysis:") # https://github.com/JerBouma/FundamentalAnalysis - print(" info provides information on main key metrics of company") - print(" help show this fundamental analysis menu again") - print(" q quit this menu, and shows back to main menu") - print(" quit quit to abandon program") - print("details:") - print(" overview overview of the company [AV]") - print(" key main key metrics of the company [AV]") - print(" profile profile of the company [FMP]") - print(" rating rating of the company from strong sell to strong buy [FMP]") - print(" quote quote of the company [FMP]") - print(" enterprise enterprise value of the company over time [FMP]") - print(" dcf discounted cash flow of the company over time [FMP]") - print("financial statement:") - print(" income income statements of the company [default: AV, FMP]") - print(" balance balance sheet of the company [default: AV, FMP]") - print(" cash cash flow of the company [default: AV, FMP]") - print(" earnings earnings dates and reported EPS [AV]") - print("ratios:") - print(" metrics key metrics of the company [FMP]") - print(" ratios financial ratios of the company [FMP]") - print(" growth financial statement growth of the company [FMP]") - print("") - - -# ----------------------------------------------------------------------------------------------------------------------- -def print_technical_analysis(s_ticker, s_start, s_interval): - """ Print help """ - - s_intraday = (f'Intraday {s_interval}', 'Daily')[s_interval == "1440min"] - - if s_start: - print(f"\n{s_intraday} Stock: {s_ticker} (from {s_start.strftime('%Y-%m-%d')})") - else: - print(f"\n{s_intraday} Stock: {s_ticker}") - - print("\nTechnical Analysis:") # https://github.com/twopirllc/pandas-ta - print(" help show this technical analysis menu again") - print(" q quit this menu, and shows back to main menu") - print(" quit quit to abandon program") - print("overlap:") - print(" ema exponential moving average") - print(" sma simple moving average") - if s_interval != "1440min": - print(" vwap volume weighted average price") - print("momentum:") - print(" cci commodity channel index") - print(" macd moving average convergence/divergence") - print(" rsi relative strength index") - print(" stoch stochastic oscillator") - print("trend:") - print(" adx average directional movement index") - print(" aroon aroon indicator") - print("volatility:") - print(" bbands bollinger bands") - print("volume:") - print(" ad chaikin accumulation/distribution line values") - print(" obv on balance volume") - print("") - - # ----------------------------------------------------------------------------------------------------------------------- def main(): """ Main function of the program @@ -207,10 +134,6 @@ def main(): print("The command selected doesn't exist\n") continue - # -------------------------------------------------------------------------------------------------------------- - # --------------------------------------------------- MENU ----------------------------------------------------- - # -------------------------------------------------------------------------------------------------------------- - # --------------------------------------------------- GAINERS -------------------------------------------------- if ns_known_args.cmd == 'gainers': smm.gainers(l_args) @@ -242,171 +165,30 @@ def main(): print("Hope you made money today. Good bye my lover, good bye my friend.\n") return - # -------------------------------------------------------------------------------------------------------------- # ------------------------------------------- FUNDAMENTAL ANALYSIS --------------------------------------------- - # -------------------------------------------------------------------------------------------------------------- elif ns_known_args.cmd == 'fa': - # Print fundamental analysis menun - print_fundamental_analysis(s_ticker, s_start, s_interval) + b_quit = fam.fa_menu(fa_parser, s_ticker, s_start, s_interval) - # Loop forever and ever - while True: - # Get input command from user - as_input = input('> ') - - # Parse fundamental analysis command of the list of possible commands - try: - (ns_known_args, l_args) = fa_parser.parse_known_args(as_input.split()) + if b_quit: + print("Hope you made money today. Good bye my lover, good bye my friend.\n") + return + else: + print_help(s_ticker, s_start, s_interval, b_is_stock_market_open()) - except SystemExit: - print("The command selected doesn't exist\n") - continue - - if ns_known_args.fa == 'info': - smfa.info(l_args, s_ticker) - - elif ns_known_args.fa == 'help': - print_fundamental_analysis(s_ticker, s_start, s_interval) - - elif ns_known_args.fa == 'q': - print_help(s_ticker, s_start, s_interval, b_is_stock_market_open()) - break - - elif ns_known_args.fa == 'quit': - print("Hope you made money today. Good bye my lover, good bye my friend.\n") - return - - # -------------------------------------------------- DETAILS -------------------------------------------------- - elif ns_known_args.fa == 'profile': - smfa.profile(l_args, s_ticker) - - elif ns_known_args.fa == 'rating': - smfa.rating(l_args, s_ticker) - - elif ns_known_args.fa == 'quote': - smfa.quote(l_args, s_ticker) - - elif ns_known_args.fa == 'enterprise': - smfa.enterprise(l_args, s_ticker) - - elif ns_known_args.fa == 'dcf': - smfa.discounted_cash_flow(l_args, s_ticker) - - elif ns_known_args.fa == 'overview': - smfa.overview(l_args, s_ticker) - - elif ns_known_args.fa == 'key': - smfa.key(l_args, s_ticker) - - # --------------------------------------------- FINANCIAL STATEMENT -------------------------------------------- - elif ns_known_args.fa == 'income': - smfa.income_statement(l_args, s_ticker) - - elif ns_known_args.fa == 'balance': - smfa.balance_sheet(l_args, s_ticker) - - elif ns_known_args.fa == 'cash': - smfa.cash_flow(l_args, s_ticker) - - elif ns_known_args.fa == 'earnings': - smfa.earnings(l_args, s_ticker) - - # --------------------------------------------------- RATIOS ----------------------------------------------------- - elif ns_known_args.fa == 'metrics': - smfa.key_metrics(l_args, s_ticker) - - elif ns_known_args.fa == 'ratios': - smfa.financial_ratios(l_args, s_ticker) - - elif ns_known_args.fa == 'growth': - smfa.financial_statement_growth(l_args, s_ticker) - - # ------------------------------------------------------------------------------------------------------------ - else: - print("Command not recognized!") - - print("") - - # -------------------------------------------------------------------------------------------------------------- # -------------------------------------------- TECHNICAL ANALYSIS ---------------------------------------------- - # -------------------------------------------------------------------------------------------------------------- elif ns_known_args.cmd == 'ta': - # Print technical analysis menun - print_technical_analysis(s_ticker, s_start, s_interval) + b_quit = tam.ta_menu(ta_parser, df_stock, s_ticker, s_start, s_interval) - # Loop forever and ever - while True: - # Get input command from user - as_input = input('> ') - - # Parse fundamental analysis command of the list of possible commands - try: - (ns_known_args, l_args) = ta_parser.parse_known_args(as_input.split()) + if b_quit: + print("Hope you made money today. Good bye my lover, good bye my friend.\n") + return + else: + print_help(s_ticker, s_start, s_interval, b_is_stock_market_open()) - except SystemExit: - print("The command selected doesn't exist\n") - continue - - if ns_known_args.ta == 'help': - print_technical_analysis(s_ticker, s_start, s_interval) - - elif ns_known_args.ta == 'q': - print_help(s_ticker, s_start, s_interval, b_is_stock_market_open()) - break - - elif ns_known_args.ta == 'quit': - print("Hope you made money today. Good bye my lover, good bye my friend.\n") - return - - # -------------------------------------------------- OVERLAP -------------------------------------------------- - elif ns_known_args.ta == 'ema': - smta.ema(l_args, s_ticker, s_interval, df_stock) - - elif ns_known_args.ta == 'sma': - smta.sma(l_args, s_ticker, s_interval, df_stock) - - elif ns_known_args.ta == 'vwap': - smta.vwap(l_args, s_ticker, s_interval, df_stock) - - # --------------------------------------------------- MOMENTUM --------------------------------------------------- - elif ns_known_args.ta == 'cci': - smta.cci(l_args, s_ticker, s_interval, df_stock) - - elif ns_known_args.ta == 'macd': - smta.macd(l_args, s_ticker, s_interval, df_stock) - - elif ns_known_args.ta == 'rsi': - smta.rsi(l_args, s_ticker, s_interval, df_stock) - - elif ns_known_args.ta == 'stoch': - smta.stoch(l_args, s_ticker, s_interval, df_stock) - - # ---------------------------------------------------- TREND ---------------------------------------------------- - elif ns_known_args.ta == 'adx': - smta.adx(l_args, s_ticker, s_interval, df_stock) - - elif ns_known_args.ta == 'aroon': - smta.aroon(l_args, s_ticker, s_interval, df_stock) - - # -------------------------------------------------- VOLATILITY -------------------------------------------------- - elif ns_known_args.ta == 'bbands': - smta.bbands(l_args, s_ticker, s_interval, df_stock) - - # ---------------------------------------------------- VOLUME ---------------------------------------------------- - elif ns_known_args.ta == 'ad': - smta.ad(l_args, s_ticker, s_interval, df_stock) - - elif ns_known_args.ta == 'obv': - smta.obv(l_args, s_ticker, s_interval, df_stock) - - # ------------------------------------------------------------------------------------------------------------ - else: - print("Command not recognized!") - - # -------------------------------------------------------------------------------------------------------------- # ------------------------------------------------ PREDICTION -------------------------------------------------- - # -------------------------------------------------------------------------------------------------------------- + + # -------------------------------------------------------------------------------------------------------------- else: print('Shouldnt see this command!') diff --git a/stock_market_technical_analysis.py b/stock_market_technical_analysis.py deleted file mode 100644 index 08df4b6e872..00000000000 --- a/stock_market_technical_analysis.py +++ /dev/null @@ -1,491 +0,0 @@ -import argparse -from alpha_vantage.timeseries import TimeSeries -from alpha_vantage.techindicators import TechIndicators -import pandas_ta as ta -import config_bot as cfg -from stock_market_helper_funcs import * - -# ----------------------------------------------------- EMA ----------------------------------------------------- -def ema(l_args, s_ticker, s_interval, df_stock): - parser = argparse.ArgumentParser(prog='ema', - description=""" The Exponential Moving Average is a staple of technical - analysis and is used in countless technical indicators. 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. However, the Exponential - Moving Average is a cumulative calculation, including all data. Past values have - a diminishing contribution to the average, while more recent values have a greater - contribution. This method allows the moving average to be more responsive to changes - in the data. """) - - parser.add_argument('-l', "--length", action="store", dest="n_length", type=check_positive, default=10, help='length') - parser.add_argument('-o', "--offset", action="store", dest="n_offset", type=check_positive, default=0, help='offset') - - try: - (ns_parser, l_unknown_args) = parser.parse_known_args(l_args) - except SystemExit: - print("") - return - - if l_unknown_args: - print(f"The following args couldn't be interpreted: {l_unknown_args}") - - try: - # Daily - if s_interval == "1440min": - df_ta = ta.ema(df_stock['5. adjusted close'], length=ns_parser.n_length, offset=ns_parser.n_offset).dropna() - plot_stock_ta(df_stock['5. adjusted close'], s_ticker, df_ta, "EMA") - # Intraday - else: - df_ta = ta.ema(df_stock['4. close'], length=ns_parser.n_length, offset=ns_parser.n_offset).dropna() - plot_stock_ta(df_stock['4. close'], s_ticker, df_ta, "EMA") - except: - print("ERROR!\n") - return - - -# ----------------------------------------------------- SMA ----------------------------------------------------- -def sma(l_args, s_ticker, s_interval, df_stock): - parser = argparse.ArgumentParser(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=10, help='length') - parser.add_argument('-o', "--offset", action="store", dest="n_offset", type=check_positive, default=0, help='offset') - - try: - (ns_parser, l_unknown_args) = parser.parse_known_args(l_args) - except SystemExit: - print("") - return - - if l_unknown_args: - print(f"The following args couldn't be interpreted: {l_unknown_args}") - - try: - # Daily - if s_interval == "1440min": - df_ta = ta.sma(df_stock['5. adjusted close'], length=ns_parser.n_length, offset=ns_parser.n_offset).dropna() - plot_stock_ta(df_stock['5. adjusted close'], s_ticker, df_ta, "SMA") - # Intraday - else: - df_ta = ta.sma(df_stock['4. close'], length=ns_parser.n_length, offset=ns_parser.n_offset).dropna() - plot_stock_ta(df_stock['4. close'], s_ticker, df_ta, "SMA") - except: - print("ERROR!\n") - return - - -# ----------------------------------------------------- VWAP ----------------------------------------------------- -def vwap(l_args, s_ticker, s_interval, df_stock): - parser = argparse.ArgumentParser(prog='vwap', - description=""" The Volume Weighted Average Price that measures the average typical price - by volume. It is typically used with intraday charts to identify general direction. """) - - parser.add_argument('-o', "--offset", action="store", dest="n_offset", type=check_positive, default=0, help='offset') - - try: - (ns_parser, l_unknown_args) = parser.parse_known_args(l_args) - except SystemExit: - print("") - return - - if l_unknown_args: - print(f"The following args couldn't be interpreted: {l_unknown_args}") - - try: - df_ta = ta.vwap(high=df_stock['2. high'], low=df_stock['3. low'], close=df_stock['4. close'], - volume=df_stock['5. volume'], offset=ns_parser.n_offset) - - plot_stock_ta(df_stock['4. close'], s_ticker, df_ta, "VWAP") - except: - print("ERROR!\n") - return - - -# ----------------------------------------------------- CCI ----------------------------------------------------- -def cci(l_args, s_ticker, s_interval, df_stock): - parser = argparse.ArgumentParser(prog='cci', - description=""" The CCI is designed to detect beginning and ending market trends. - The range of 100 to -100 is the normal trading range. CCI values outside of this - range indicate overbought or oversold conditions. You can also look for price - divergence in the CCI. If the price is making new highs, and the CCI is not, - then a price correction is likely. """) - - parser.add_argument('-l', "--length", action="store", dest="n_length", type=check_positive, default=14, help='length') - parser.add_argument('-s', "--scalar", action="store", dest="n_scalar", type=check_positive, default=0.015, help='scalar') - parser.add_argument('-o', "--offset", action="store", dest="n_offset", type=check_positive, default=0, help='offset') - - try: - (ns_parser, l_unknown_args) = parser.parse_known_args(l_args) - except SystemExit: - print("") - return - - if l_unknown_args: - print(f"The following args couldn't be interpreted: {l_unknown_args}") - - try: - # Daily - if s_interval == "1440min": - df_ta = ta.cci(high=df_stock['2. high'], low=df_stock['3. low'], close=df_stock['5. adjusted close'], - length=ns_parser.n_length, scalar=ns_parser.n_scalar, offset=ns_parser.n_offset).dropna() - plot_stock_and_ta(df_stock['5. adjusted close'], s_ticker, df_ta, "CCI") - # Intraday - else: - df_ta = ta.cci(high=df_stock['2. high'], low=df_stock['3. low'], close=df_stock['4. close'], - length=ns_parser.n_length, scalar=ns_parser.n_scalar, offset=ns_parser.n_offset).dropna() - plot_stock_and_ta(df_stock['4. close'], s_ticker, df_ta, "CCI") - except: - print("ERROR!\n") - return - - -# ----------------------------------------------------- MACD ----------------------------------------------------- -def macd(l_args, s_ticker, s_interval, df_stock): - parser = argparse.ArgumentParser(prog='macd', - description=""" The Moving Average Convergence Divergence (MACD) is the difference - between two Exponential Moving Averages. The Signal line is an Exponential Moving - Average of the MACD. \n \n The MACD signals trend changes and indicates the start - of new trend direction. High values indicate overbought conditions, low values - indicate oversold conditions. Divergence with the price indicates an end to the - current trend, especially if the MACD is at extreme high or low values. When the MACD - line crosses above the signal line a buy signal is generated. When the MACD crosses - below the signal line a sell signal is generated. To confirm the signal, the MACD - should be above zero for a buy, and below zero for a sell. """) - - parser.add_argument('-f', "--fast", action="store", dest="n_fast", type=check_positive, default=12, - help='The short period.') - parser.add_argument('-s', "--slow", action="store", dest="n_slow", type=check_positive, default=26, - help='The long period.') - parser.add_argument("--signal", action="store", dest="n_signal", type=check_positive, default=9, - help='The signal period.') - parser.add_argument('-o', "--offset", action="store", dest="n_offset", type=check_positive, default=0, - help='How many periods to offset the result.') - - try: - (ns_parser, l_unknown_args) = parser.parse_known_args(l_args) - except SystemExit: - print("") - return - - if l_unknown_args: - print(f"The following args couldn't be interpreted: {l_unknown_args}") - - try: - # Daily - if s_interval == "1440min": - df_ta = ta.macd(df_stock['5. adjusted close'], fast=ns_parser.n_fast, slow=ns_parser.n_slow, - signal=ns_parser.n_signal, offset=ns_parser.n_offset).dropna() - plot_stock_and_ta(df_stock['5. adjusted close'], s_ticker, df_ta, "MACD") - # Intraday - else: - df_ta = ta.macd(df_stock['4. close'], fast=ns_parser.n_fast, slow=ns_parser.n_slow, - signal=ns_parser.n_signal, offset=ns_parser.n_offset).dropna() - plot_stock_and_ta(df_stock['4. close'], s_ticker, df_ta, "MACD") - except: - print("ERROR!\n") - return - - -# ----------------------------------------------------- RSI ----------------------------------------------------- -def rsi(l_args, s_ticker, s_interval, df_stock): - parser = argparse.ArgumentParser(prog='rsi', - description=""" The Relative Strength Index (RSI) calculates a ratio of the - recent upward price movements to the absolute price movement. The RSI ranges - from 0 to 100. The RSI is interpreted as an overbought/oversold indicator when - the value is over 70/below 30. You can also look for divergence with price. If - the price is making new highs/lows, and the RSI is not, it indicates a reversal. """) - - parser.add_argument('-l', "--length", action="store", dest="n_length", type=check_positive, default=14, help='length') - parser.add_argument('-s', "--scalar", action="store", dest="n_scalar", type=check_positive, default=100, help='scalar') - parser.add_argument('-d', "--drift", action="store", dest="n_drift", type=check_positive, default=1, help='drift') - parser.add_argument('-o', "--offset", action="store", dest="n_offset", type=check_positive, default=0, help='offset') - - try: - (ns_parser, l_unknown_args) = parser.parse_known_args(l_args) - except SystemExit: - print("") - return - - if l_unknown_args: - print(f"The following args couldn't be interpreted: {l_unknown_args}") - - try: - # Daily - if s_interval == "1440min": - df_ta = ta.rsi(df_stock['5. adjusted close'], length=ns_parser.n_length, scalar=ns_parser.n_scalar, - drift=ns_parser.n_drift, offset=ns_parser.n_offset).dropna() - plot_stock_and_ta(df_stock['5. adjusted close'], s_ticker, df_ta, "RSI") - # Intraday - else: - df_ta = ta.rsi(df_stock['4. close'], length=ns_parser.n_length, scalar=ns_parser.n_scalar, - drift=ns_parser.n_drift, offset=ns_parser.n_offset).dropna() - plot_stock_and_ta(df_stock['4. close'], s_ticker, df_ta, "RSI") - except: - print("ERROR!\n") - return - - -# ----------------------------------------------------- STOCH ----------------------------------------------------- -def stoch(l_args, s_ticker, s_interval, df_stock): - parser = argparse.ArgumentParser(prog='stoch', - description=""" The Stochastic Oscillator measures where the close is in relation - to the recent trading range. The values range from zero to 100. %D values over 75 - indicate an overbought condition; values under 25 indicate an oversold condition. - When the Fast %D crosses above the Slow %D, it is a buy signal; when it crosses - below, it is a sell signal. The Raw %K is generally considered too erratic to use - for crossover signals. """) - - parser.add_argument('-k', "--fastkperiod", action="store", dest="n_fastkperiod", type=check_positive, default=14, - help='The time period of the fastk moving average') - parser.add_argument('-d', "--slowdperiod", action="store", dest="n_slowdperiod", type=check_positive, default=3, - help='TThe time period of the slowd moving average') - parser.add_argument("--slowkperiod", action="store", dest="n_slowkperiod", type=check_positive, default=3, - help='The time period of the slowk moving average') - parser.add_argument('-o', "--offset", action="store", dest="n_offset", type=check_positive, default=0, help='offset') - - try: - (ns_parser, l_unknown_args) = parser.parse_known_args(l_args) - except SystemExit: - print("") - return - - if l_unknown_args: - print(f"The following args couldn't be interpreted: {l_unknown_args}") - - try: - # Daily - if s_interval == "1440min": - df_ta = ta.stoch(high=df_stock['2. high'], low=df_stock['3. low'], close=df_stock['5. adjusted close'], k=ns_parser.n_fastkperiod, - d=ns_parser.n_slowdperiod, smooth_k=ns_parser.n_slowkperiod, offset=ns_parser.n_offset).dropna() - plot_stock_and_ta(df_stock['5. adjusted close'], s_ticker, df_ta, "STOCH") - # Intraday - else: - df_ta = ta.stoch(high=df_stock['2. high'], low=df_stock['3. low'], close=df_stock['4. close'], k=ns_parser.n_fastkperiod, - d=ns_parser.n_slowdperiod, smooth_k=ns_parser.n_slowkperiod, offset=ns_parser.n_offset).dropna() - plot_stock_and_ta(df_stock['4. close'], s_ticker, df_ta, "STOCH") - except: - print("ERROR!\n") - return - - -# ----------------------------------------------------- ADX ----------------------------------------------------- -def adx(l_args, s_ticker, s_interval, df_stock): - parser = argparse.ArgumentParser(prog='adx', - description=""" The ADX is a Welles Wilder style moving average of the Directional - Movement Index (DX). The values range from 0 to 100, but rarely get above 60. - To interpret the ADX, consider a high number to be a strong trend, and a low number, - a weak trend. """) - - parser.add_argument('-l', "--length", action="store", dest="n_length", type=check_positive, default=14, help='length') - parser.add_argument('-s', "--scalar", action="store", dest="n_scalar", type=check_positive, default=100, help='scalar') - parser.add_argument('-d', "--drift", action="store", dest="n_drift", type=check_positive, default=1, help='drift') - parser.add_argument('-o', "--offset", action="store", dest="n_offset", type=check_positive, default=0, help='offset') - - try: - (ns_parser, l_unknown_args) = parser.parse_known_args(l_args) - except SystemExit: - print("") - return - - if l_unknown_args: - print(f"The following args couldn't be interpreted: {l_unknown_args}") - - try: - # Daily - if s_interval == "1440min": - df_ta = ta.adx(high=df_stock['2. high'], low=df_stock['3. low'], close=df_stock['5. adjusted close'], length=ns_parser.n_length, - scalar=ns_parser.n_scalar, drift=ns_parser.n_drift, offset=ns_parser.n_offset).dropna() - plot_stock_and_ta(df_stock['5. adjusted close'], s_ticker, df_ta, "ADX") - # Intraday - else: - df_ta = ta.adx(high=df_stock['2. high'], low=df_stock['3. low'], close=df_stock['4. close'], length=ns_parser.n_length, - scalar=ns_parser.n_scalar, drift=ns_parser.n_drift, offset=ns_parser.n_offset).dropna() - plot_stock_and_ta(df_stock['4. close'], s_ticker, df_ta, "ADX") - except: - print("ERROR!\n") - return - - -# ----------------------------------------------------- AROON ----------------------------------------------------- -def aroon(l_args, s_ticker, s_interval, df_stock): - parser = argparse.ArgumentParser(prog='aroon', - description=""" The word aroon is Sanskrit for "dawn's early light." The Aroon - indicator attempts to show when a new trend is dawning. The indicator consists - of two lines (Up and Down) that measure how long it has been since the highest - high/lowest low has occurred within an n period range. \n \n When the Aroon Up is - staying between 70 and 100 then it indicates an upward trend. When the Aroon Down - is staying between 70 and 100 then it indicates an downward trend. A strong upward - trend is indicated when the Aroon Up is above 70 while the Aroon Down is below 30. - Likewise, a strong downward trend is indicated when the Aroon Down is above 70 while - the Aroon Up is below 30. Also look for crossovers. When the Aroon Down crosses above - the Aroon Up, it indicates a weakening of the upward trend (and vice versa). """) - - parser.add_argument('-l', "--length", action="store", dest="n_length", type=check_positive, default=14, help='length') - parser.add_argument('-s', "--scalar", action="store", dest="n_scalar", type=check_positive, default=100, help='scalar') - parser.add_argument('-o', "--offset", action="store", dest="n_offset", type=check_positive, default=0, help='offset') - - try: - (ns_parser, l_unknown_args) = parser.parse_known_args(l_args) - except SystemExit: - print("") - return - - if l_unknown_args: - print(f"The following args couldn't be interpreted: {l_unknown_args}") - - try: - df_ta = ta.aroon(high=df_stock['2. high'], low=df_stock['3. low'], length=ns_parser.n_length, - scalar=ns_parser.n_scalar, offset=ns_parser.n_offset).dropna() - # Daily - if s_interval == "1440min": - plot_stock_and_ta(df_stock['5. adjusted close'], s_ticker, df_ta.iloc[:,-1], "AROON") - # Intraday - else: - plot_stock_and_ta(df_stock['4. close'], s_ticker, df_ta.iloc[:,-1], "AROON") - except: - print("ERROR!\n") - return - - -# ----------------------------------------------------- BBANDS ----------------------------------------------------- -def bbands(l_args, s_ticker, s_interval, df_stock): - parser = argparse.ArgumentParser(prog='bbands', - description=""" Bollinger Bands consist of three lines. The middle band is a simple - moving average (generally 20 periods) of the typical price (TP). The upper and lower - bands are F standard deviations (generally 2) above and below the middle band. - The bands widen and narrow when the volatility of the price is higher or lower, respectively. - \n \nBollinger Bands do not, in themselves, generate buy or sell signals; they are an - indicator of overbought or oversold conditions. When the price is near the upper or lower - band it indicates that a reversal may be imminent. The middle band becomes a support or - resistance level. The upper and lower bands can also be interpreted as price targets. - When the price bounces off of the lower band and crosses the middle band, then the - upper band becomes the price target. """) - - parser.add_argument('-l', "--length", action="store", dest="n_length", type=check_positive, default=5, help='length') - parser.add_argument('-s', "--std", action="store", dest="n_std", type=check_positive, default=2, help='std') - parser.add_argument('-m', "--mamode", action="store", dest="s_mamode", default="sma", help='mamode') - parser.add_argument('-o', "--offset", action="store", dest="n_offset", type=check_positive, default=0, help='offset') - - try: - (ns_parser, l_unknown_args) = parser.parse_known_args(l_args) - except SystemExit: - print("") - return - - if l_unknown_args: - print(f"The following args couldn't be interpreted: {l_unknown_args}") - - try: - # Daily - if s_interval == "1440min": - df_ta = ta.bbands(close=df_stock['5. adjusted close'], length=ns_parser.n_length, std=ns_parser.n_std, - mamode=ns_parser.s_mamode, offset=ns_parser.n_offset).dropna() - plot_stock_ta(df_stock['5. adjusted close'], s_ticker, df_ta, "BBANDS") - # Intraday - else: - df_ta = ta.bbands(close=df_stock['4. close'], length=ns_parser.n_length, std=ns_parser.n_std, - mamode=ns_parser.s_mamode, offset=ns_parser.n_offset).dropna() - plot_stock_ta(df_stock['4. close'], s_ticker, df_ta, "BBANDS") - - except: - print("ERROR!\n") - return - - -# ------------------------------------------------------- AD ------------------------------------------------------- -def ad(l_args, s_ticker, s_interval, df_stock): - parser = argparse.ArgumentParser(prog='ad', - description=""" The Accumulation/Distribution Line is similar to the On Balance - Volume (OBV), which sums the volume times +1/-1 based on whether the close is - higher than the previous close. The Accumulation/Distribution indicator, however - multiplies the volume by the close location value (CLV). The CLV is based on the - movement of the issue within a single bar and can be +1, -1 or zero. \n \n - The Accumulation/Distribution Line is interpreted by looking for a divergence in - the direction of the indicator relative to price. If the Accumulation/Distribution - Line is trending upward it indicates that the price may follow. Also, if the - Accumulation/Distribution Line becomes flat while the price is still rising (or falling) - then it signals an impending flattening of the price.""") - - parser.add_argument('-o', "--offset", action="store", dest="n_offset", type=check_positive, default=0, help='offset') - parser.add_argument('--open', action="store_true", default=False, dest="b_use_open", help='uses open value of stock') - - try: - (ns_parser, l_unknown_args) = parser.parse_known_args(l_args) - except SystemExit: - print("") - return - - if l_unknown_args: - print(f"The following args couldn't be interpreted: {l_unknown_args}") - - try: - # Daily - if s_interval == "1440min": - # Use open stock values - if ns_parser.b_use_open: - df_ta = ta.ad(high=df_stock['2. high'], low=df_stock['3. low'], close=df_stock['5. adjusted close'], - volume=df_stock['6. volume'], offset=ns_parser.n_offset, open_=df_stock['1. open']).dropna() - # Do not use open stock values - else: - df_ta = ta.ad(high=df_stock['2. high'], low=df_stock['3. low'], close=df_stock['5. adjusted close'], - volume=df_stock['6. volume'], offset=ns_parser.n_offset).dropna() - - plot_stock_and_ta(df_stock['5. adjusted close'], s_ticker, df_ta, "AD") - # Intraday - else: - # Use open stock values - if ns_parser.b_use_open: - df_ta = ta.ad(high=df_stock['2. high'], low=df_stock['3. low'], close=df_stock['4. close'], - volume=df_stock['5. volume'], offset=ns_parser.n_offset, open_=df_stock['1. open']).dropna() - # Do not use open stock values - else: - df_ta = ta.ad(high=df_stock['2. high'], low=df_stock['3. low'], close=df_stock['4. close'], - volume=df_stock['5. volume'], offset=ns_parser.n_offset).dropna() - - plot_stock_and_ta(df_stock['4. close'], s_ticker, df_ta, "AD") - - except: - print("ERROR!\n") - return - - -# ------------------------------------------------------- OBV ------------------------------------------------------- -def obv(l_args, s_ticker, s_interval, df_stock): - parser = argparse.ArgumentParser(prog='obv', - description=""" The On Balance Volume (OBV) is a cumulative total of the up and - down volume. When the close is higher than the previous close, the volume is added - to the running total, and when the close is lower than the previous close, the volume - is subtracted from the running total. \n \n To interpret the OBV, look for the OBV - to move with the price or precede price moves. If the price moves before the OBV, - then it is a non-confirmed move. A series of rising peaks, or falling troughs, in the - OBV indicates a strong trend. If the OBV is flat, then the market is not trending. """) - - parser.add_argument('-o', "--offset", action="store", dest="n_offset", type=check_positive, default=0, help='offset') - - try: - (ns_parser, l_unknown_args) = parser.parse_known_args(l_args) - except SystemExit: - print("") - return - - if l_unknown_args: - print(f"The following args couldn't be interpreted: {l_unknown_args}") - - try: - # Daily - if s_interval == "1440min": - df_ta = ta.obv(close=df_stock['5. adjusted close'], volume=df_stock['6. volume'], offset=ns_parser.n_offset).dropna() - plot_stock_and_ta(df_stock['5. adjusted close'], s_ticker, df_ta, "OBV") - # Intraday - else: - df_ta = ta.ad(close=df_stock['4. close'], volume=df_stock['5. volume'], offset=ns_parser.n_offset).dropna() - plot_stock_and_ta(df_stock['4. close'], s_ticker, df_ta, "OBV") - except: - print("ERROR!\n") - return diff --git a/technical_analysis/.DS_Store b/technical_analysis/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..5008ddfcf53c02e82d7eee2e57c38e5672ef89f6 GIT binary patch literal 6148 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 literal 0 HcmV?d00001 diff --git a/technical_analysis/__pycache__/financial_modeling_prep_api.cpython-36.pyc b/technical_analysis/__pycache__/financial_modeling_prep_api.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..65a832724edffa0fd9f128a2ad174711e5032c47 GIT binary patch literal 28851 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 kg#+=;viMhLgcQpc%cski%ai4+<o%{L@v1> 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 RT)?%bZ71)(>8`qO{U2=ut2Y1u literal 0 HcmV?d00001 diff --git a/technical_analysis/__pycache__/overlap.cpython-36.pyc b/technical_analysis/__pycache__/overlap.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..44ca538ef2974a979efd150bbe276fdfb4ba7a7e GIT binary patch literal 4099 zcmd^CU5^~a747c%>Ye@Y+8AR8hZK+mO|qU1;Jidp!~#Yj#g64QwzNW;l)GwXYPYAW zQ&qjoj@D0`r$~N}67d800sH|Z{zQuhq&)G+D^HwT-RqqN8=COQ%6+H1y87O_Rrj8A z{QBx@|I^RE8hvsx2>ur={6)Bb1DAaVMg$^EgPrO(+==iUrLDX4+)CTC&Q2!`Wal^t z1JM?pe+D~U(G@-X_Czd}@EeP8I~er8gs z(qPagZJLe07}qkcw{Y1nU|g^picmzN^(cDSK5Fkq6qZ7|76lajN4+rc;&D3+vSB^{*{9B@H;?Dv53&m(wk!+~{Sw6$!M48! z&)q6pa>n_qtsr1`r;^?HFxQ#PoZ>0FsrOYjVO!WHK9NjW#+h|IPbJf1=43L>RDyYZ z*5r?8JUz7JBopMTuoAx+OLURBR9d^>QDp+2oi=vJ-pdenTg@nJy`p9T>veB1$&)GD z=V^f)GUkw_Q!~kOX_OW$;l?OwnfynATn?m~Ox=cGr2oV+T{x?RY?vnP%(o(NBUz>$ zf+uMqs;p@auQqnb-qi;Z_Z$Ap#S>_j=#$PVDP~2=o!Xa3Firfu&Nk{b(6RC~Wr90C zWVg9>)&5vE#iAN!%9&6zl_@(VcW5VP)Puq)jXl;rl{&!F7@45F&V=J^ zVkAc=HVnKNYKW>uG0mi#;w+JqK0qO1b7xiY)=QujJ$SqViyF7IH5g5%Je%P7n{9Pn zKh?esqOzSEJt>!kw24tURm8&v~e_5mwpw|W?K$}Ugn ztFjFju57!*T$Vi{$Gk}KIF)G*hngJf@z_d7o~k<&dQa8EeB&;19&5_qAFi2L>a0{` zuQ}%NadbJn z97W+;)DG8Lad zkOb}=|BT^>)Y;8Cnp%v>l#mP%1e{hD$V?O^hz7@SWn?BmMATttd8l3$v019nUx1&( zhG7Y!tS2>K?^v4|Q7ZoyY7N;9qAn0nUeu6DvFO_qT&wA(S+3~+eWeS_vKoJ%$gXu( zO?k6f=pSU)|A#l5g{}yK?*ZhMV_s<(xkv#uC7m$A0>*ph!U-g(D}X2pZ(O8wTn$fo ztWuN(0W!`I=LUQ|A)Fxt(sqCbrVDeHHB67jJrFL@9Rc#7V@R5s6*8-2*2tWLIm-|p zJ3Tpg4F7S=U@nlqA7X{=r?7&7whzp+WG<0;j?85;SIGQ=%qwIbW4w8u9AKzok3!_gN4Kw>yJ8+_Dgt6<0RG3le9l0)i0cp>d)LN+xrJR zpMU0&=$=l&M(n=Vt03@F!X#x)iQQwT_^9gC)PRouwR{#-W$EZ^QCRC8uUy zz>J6l@xSA7ktMb~S4|y~>TV1 literal 0 HcmV?d00001 diff --git a/technical_analysis/__pycache__/trend.cpython-36.pyc b/technical_analysis/__pycache__/trend.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ba1df3dfbd407cfa953743bbc0722eba14df4df2 GIT binary patch literal 3638 zcmcInOK%*<5uTZS4OisqVTlqIS!z*Eq;<$89Vrh4ff3rwA%HCzlnfa}fJJkaR)< z7Z#fT`1ar3zh4Q0e+6fL5!S!PV?G5Dfe5o;yZjq&M|h92$}@VeWYtk^yA}qrb{K?# zsEXR}gYCMgiw6ESMEEpl$4Af+JZ^_B{21i6mi^RNsk zzZlO&JfGt+zX*fC2D_mMMITX2l$ds*!Sj>s$t40`j{sl1){sQ3`T+LXerHk`!$vA4E(p|lLY1dqx`-HnH zR9IKF`-OB3A$xqB;dLOh0tyW&GzrhRCQaq)NO(=<3xve9vAQaB+Ow{acm3iBwGg

_|VTaN>z5LS-<6?IV2oNmEl#%TQ!ok6~3ckCV=jkT=(}1NwUn6oIWV?dn zoW_qj<+f?#H(Ogzw(d6DEf;g$FSs_+wKjBrOm+7ay=phlh3Mj|=ebrgkjb!HD3jWB zPr6HfQ+JrFNlsG6)e4PBTx7W>B+>*!`Vx^3h%AD*y3ne~xw}m8)x|MFCF-VYc{|1d zmWpE2wP`Yh3r*AY$wA?}SoF#buI^21H`l(%eN-llL^-$W+lwGqj8RRL71YYuN-=t>ES9_<} z_d!yO<^f0$)~j)JBlQ2GC~QU5uvLk}o8e-3wL)|;s)uptcb!A(1#JGD)I|R`q~8D2 zTZsGuSa=@lt`+doqKrK5O_T<-5Rbt3DbLMNrxsUAvt_|2 z`F+DA*Fe4ucfod+OQ`npvmtJp3mh^)g>h@;sIZ1G&J2KMlYz_uYq^}12t^){P2A)X zlu!41v^3Z|n^Ecy69u1hVETiv3lE^1xK3>VFt=sO(0rTTx!g1u~ReRGgrD#UGaPWOi3ur%U zeB-3c9s4v}z}|Dp&q-KF?z_@gwrQkeGDtB&oMzVtiTyj0PU+#yef*1bC?~0rXvZgx zpO5H&I(1_84Yy{DnWly_rE%)|MrKgwN)7#$O|&uw(}^~ncOI?(PIcf%nD@86@g*XcW*l$oAW#guV*? zc5P$p$&<(Lm=un_!%we6rrpxFNY95vZWFmfgb}$*WSPhsk<$r)n!mnB7yZ2=)BG2&U?~#qpRVSC=Qn^AC*0q zy`N4e*qD)x!M2# literal 0 HcmV?d00001 diff --git a/technical_analysis/__pycache__/volatility.cpython-36.pyc b/technical_analysis/__pycache__/volatility.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0e76dd3392a6d556d6dfaeef15ecaf6c1c35f768 GIT binary patch literal 2461 zcma)8L30~56y9BX*Bd8s+q6y70!8IQ4T)2r^Z*P)L*WFWlZ5GzVa6k`l=UXs)s7@P zV~=wRN5T();Ro<%7|t4QoOXw(h&6C0@_?A3;+)`Du6tx}$Vr|tCOC24B-4Zv zo#iDIZ8Fa%mtzDX6dj}~CwEg`U?#+bynBz7TxF8!ZXK5sGbyu#3R0>pf$iSoZk@uY zge7qa2ziXze4(p)300hYPPBnHRg5q`&Zx;y?+dwf2_48WuVM^1q5y{%O7G1X)FD;} zKF$~~stpUO6m~owV(qpaOMw(bW+oSf*98OJVU`Y2pj36G>qK!~^2B6gE+)PC>TZ+v z%l&1N6w<7dtV$r)T#UJ1Cv`InG9DonMW7dGZ(2~HKXj>1D)?wIXYpCV&_9EnKqSDa z26B`RK`SV*(o!%-HI`Kk=#eKEh&-#m;8ax@)h)lkVb1t9M-9rX^57a&~`j>3o6f zK2_UZK>4Xumlk#1m{rIM*#WLzgID_#Gm!G@T|8ykWbsTtZ(gE!p9MZZ=&4RN>I zs9tnK8&RABS=c7FFt&-Sg4-732XrK`9CA@&Lp=>QHnd?jEc*C*>Ygauzzo0TE?7=; z$q+^3fvIK*(J(YAHP;Q+ewBz zIqH{E;~d z4eiG0S-lBBHd%6n@NM14c3h3AurWKRjcrtgRd%7!{qt!@^hd?>dBE7vUp)0TBL4Nw z=GQ1jZ$8Rc#?_8wDoaOPe<4c_rA(^o^k$lw&0UwymsA~bvn9=@;mNRYPfMTTZkyno zZvJx#_sU6Cr7Ke3h4B2S9S3Xvn!oC=1%clQntrDd`z!dn)^Kt)i2T^Eyt*xQ3odq{ zbT14_#s%iqH)}-lDu=$~C;qEBz_HZ!Qf=CEz!|VbHQ-PK?dq(Gt;M?ADgFpd9SQ!i QBb;`uh!H&Ym;9*lH~$Q}^Z)<= literal 0 HcmV?d00001 diff --git a/technical_analysis/__pycache__/volume.cpython-36.pyc b/technical_analysis/__pycache__/volume.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..abe09399b7a5a7ebd8e516fdca169627395690a9 GIT binary patch literal 3960 zcmb7H&2JmW72jQw%N6xu%T`p$ag<5hB&H)#cH{I=v_b8-K?^u`VLJ|B6kV)#hU7@g z9b#ryf(ZFi^{OKGqP_QTY5#&jZawwbYft^XSxS~1CuS(@({Og)_nY^7{CIJ(^UrVo zo36hV1pf}seIl%XjmLZn!UG-_!Snim_&mb*sAxQ;?~S54YCUg-foL5EVZfWb_2=Mu z%wyih|27Yw1l{C6kP$rWhAzAbvZ2L58Y^@<%IvsMwvan%uF8F(v1#%qoyI4@vxMg} zJf;YPzy`Y^4|&8JC((=MQFAvUb)?ERc*5s+=cFA5et(`X@I}7FFY(JKFz)N{a1Hy- zqu@CFL-eBcB0h@sA8m^-AH{zS{uUjF;EVW`y-0s^)Y^^p-)(z0Ico5$>jCJBr*C<> z3fkJ8!|spP1HN_=?{hITNvl3<=fO?V!lO37cH9hua-Xz*9qQHBNO{}q zz5WCAUf_5|FTFd{`&Ce036ZuiKrG&&DDdEkf4UnFU6k?c5wgLa4h6fL=hdhxGAmWN zeINPLa;Ks%?13x=lZF{Nl0~MORm_6nQOWLQMONm5b=WMQXR4@1g57v@?^$<~9SmhY zWTqM!FKxemY2`>5_R;O_t=nuTGlDZ1a4-~52*uEv7s_~RX45&8gPJodJ^NUTeW@x_ z%jvzrb6IkkXIAM=HdF@!1w5mx2&9$cLc$j^dg|QH;W-xy1<4fN{j8`EmCqhL>(=&Q zMd3bkpCruY?MUs5kti)weXmIx1JMW44rR$QB(NM50)jQmO3re`WJe&_n+(xbnoWdO zJ*c9;Sw2r;*qh5nmbmqZyG1e)fkLT0*unZxm@zI9)PbNPf{C-KrFd|uMef6Q>gs8# zm=;vT`-19ptYt2G?00oIzT4K>6rWxMs|B>dhiZI~Y0jjD@xD@gzB4;5HRxue>=3RN zg*xc5yMc2(NvRbjiJm5*4tF1Gl@U$p}G$y%b)aE#&;_~ATAm8tI6EYd($Q`Y2WU7 zo4PUl0Gn%o$F=-97uTIa&%qwoBGc1uOJ5-quM$}y0w@pa6VcuKljKhCR0;If{FC-? z9zTBc_`Obd!6ooxoM|K6(p^1311|0F>8o}N8Rse9`aQRl4@JJ0j+K#gd)#HuldR2?BAaQ#aZMoZVy@M=%-k}eed=SJqQj&%>n1KPYWBpWR_1$9+%c(- zB|4u=c)wf$NPAy<6m!xdjr0aVLq^ z!j-5QF45CSqBvX)uQyh)x6(|`)~nc0LeG6+!lC-|6VAV|m~Fy2{L8mynco7x=P%4M z3z%j8WaHg7W{pKZK`i+RBH@=#8oP5ev)In`9nAxm{Ty;@%CYP@uDq6m-kot=m>{lR zm>^ajx`x`>&#pD5BgDCh;MqB>r$&^q)9J!DW}6kKJ);_XFq*9$aunmV#(V6mA#OIc zyR(_#`_X>WAFdPaZQ>jkbT-A)nMYTp?{`+ggH3NZhLcyUzmSTmS*Cl&Y1m8(4V3gt7(`bc$K83ci$o9-8 z%`j7dV^*tbFvK3l3i5k4-4vadP>zWSVgLmm@XuWIhic6A*{l_ee0QO`DisER>4?x{ z-AK1^^K}ez5d?Lc_Nmo)^z$tp-QGi!N2LXNu`?ss#N%2^Ye+k$m!h)Z`xB literal 0 HcmV?d00001 diff --git a/technical_analysis/menu.py b/technical_analysis/menu.py new file mode 100644 index 00000000000..9135bc42897 --- /dev/null +++ b/technical_analysis/menu.py @@ -0,0 +1,127 @@ +import FundamentalAnalysis as fa +from alpha_vantage.fundamentaldata import FundamentalData +import config_bot as cfg +import argparse +import datetime +from datetime import datetime +from stock_market_helper_funcs import * +import pandas as pd +import json +import requests +from pandas.io.json import json_normalize + +from technical_analysis import overlap as ta_overlap +from technical_analysis import momentum as ta_momentum +from technical_analysis import trend as ta_trend +from technical_analysis import volatility as ta_volatility +from technical_analysis import volume as ta_volume + +# ----------------------------------------------------------------------------------------------------------------------- +def print_technical_analysis(s_ticker, s_start, s_interval): + """ Print help """ + + s_intraday = (f'Intraday {s_interval}', 'Daily')[s_interval == "1440min"] + + if s_start: + print(f"\n{s_intraday} Stock: {s_ticker} (from {s_start.strftime('%Y-%m-%d')})") + else: + print(f"\n{s_intraday} Stock: {s_ticker}") + + print("\nTechnical Analysis:") # https://github.com/twopirllc/pandas-ta + print(" help show this technical analysis menu again") + print(" q quit this menu, and shows back to main menu") + print(" quit quit to abandon program") + print("overlap:") + print(" ema exponential moving average") + print(" sma simple moving average") + if s_interval != "1440min": + print(" vwap volume weighted average price") + print("momentum:") + print(" cci commodity channel index") + print(" macd moving average convergence/divergence") + print(" rsi relative strength index") + print(" stoch stochastic oscillator") + print("trend:") + print(" adx average directional movement index") + print(" aroon aroon indicator") + print("volatility:") + print(" bbands bollinger bands") + print("volume:") + print(" ad chaikin accumulation/distribution line values") + print(" obv on balance volume") + print("") + + +# ---------------------------------------------------- MENU ---------------------------------------------------- +def ta_menu(ta_parser, df_stock, s_ticker, s_start, s_interval): + + print_technical_analysis(s_ticker, s_start, s_interval) + + # Loop forever and ever + while True: + # Get input command from user + as_input = input('> ') + + # Parse fundamental analysis command of the list of possible commands + try: + (ns_known_args, l_args) = ta_parser.parse_known_args(as_input.split()) + + except SystemExit: + print("The command selected doesn't exist\n") + continue + + if ns_known_args.ta == 'help': + print_technical_analysis(s_ticker, s_start, s_interval) + + elif ns_known_args.ta == 'q': + # Just leave the FA menu + return False + + elif ns_known_args.ta == 'quit': + # Abandon the program + return True + + # -------------------------------------------------- OVERLAP -------------------------------------------------- + elif ns_known_args.ta == 'ema': + ta_overlap.ema(l_args, s_ticker, s_interval, df_stock) + + elif ns_known_args.ta == 'sma': + ta_overlap.sma(l_args, s_ticker, s_interval, df_stock) + + elif ns_known_args.ta == 'vwap': + ta_overlap.vwap(l_args, s_ticker, s_interval, df_stock) + + # --------------------------------------------------- MOMENTUM --------------------------------------------------- + elif ns_known_args.ta == 'cci': + ta_momentum.cci(l_args, s_ticker, s_interval, df_stock) + + elif ns_known_args.ta == 'macd': + ta_momentum.macd(l_args, s_ticker, s_interval, df_stock) + + elif ns_known_args.ta == 'rsi': + ta_momentum.rsi(l_args, s_ticker, s_interval, df_stock) + + elif ns_known_args.ta == 'stoch': + ta_momentum.stoch(l_args, s_ticker, s_interval, df_stock) + + # ---------------------------------------------------- TREND ---------------------------------------------------- + elif ns_known_args.ta == 'adx': + ta_trend.adx(l_args, s_ticker, s_interval, df_stock) + + elif ns_known_args.ta == 'aroon': + ta_trend.aroon(l_args, s_ticker, s_interval, df_stock) + + # -------------------------------------------------- VOLATILITY -------------------------------------------------- + elif ns_known_args.ta == 'bbands': + ta_volatility.bbands(l_args, s_ticker, s_interval, df_stock) + + # ---------------------------------------------------- VOLUME ---------------------------------------------------- + elif ns_known_args.ta == 'ad': + ta_volume.ad(l_args, s_ticker, s_interval, df_stock) + + elif ns_known_args.ta == 'obv': + ta_volume.obv(l_args, s_ticker, s_interval, df_stock) + + # ------------------------------------------------------------------------------------------------------------ + else: + print("Command not recognized!") diff --git a/technical_analysis/momentum.py b/technical_analysis/momentum.py new file mode 100644 index 00000000000..b8ca46adf26 --- /dev/null +++ b/technical_analysis/momentum.py @@ -0,0 +1,159 @@ +import argparse +import pandas_ta as ta +from stock_market_helper_funcs import * +from pandas.plotting import register_matplotlib_converters +register_matplotlib_converters() + +# ----------------------------------------------------- CCI ----------------------------------------------------- +def cci(l_args, s_ticker, s_interval, df_stock): + parser = argparse.ArgumentParser(prog='cci', + description=""" The CCI is designed to detect beginning and ending market trends. + The range of 100 to -100 is the normal trading range. CCI values outside of this + range indicate overbought or oversold conditions. You can also look for price + divergence in the CCI. If the price is making new highs, and the CCI is not, + then a price correction is likely. """) + + parser.add_argument('-l', "--length", action="store", dest="n_length", type=check_positive, default=14, help='length') + parser.add_argument('-s', "--scalar", action="store", dest="n_scalar", type=check_positive, default=0.015, help='scalar') + parser.add_argument('-o', "--offset", action="store", dest="n_offset", type=check_positive, default=0, help='offset') + + 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}") + + # Daily + if s_interval == "1440min": + df_ta = ta.cci(high=df_stock['2. high'], low=df_stock['3. low'], close=df_stock['5. adjusted close'], + length=ns_parser.n_length, scalar=ns_parser.n_scalar, offset=ns_parser.n_offset).dropna() + plot_stock_and_ta(df_stock['5. adjusted close'], s_ticker, df_ta, "CCI") + # Intraday + else: + df_ta = ta.cci(high=df_stock['2. high'], low=df_stock['3. low'], close=df_stock['4. close'], + length=ns_parser.n_length, scalar=ns_parser.n_scalar, offset=ns_parser.n_offset).dropna() + plot_stock_and_ta(df_stock['4. close'], s_ticker, df_ta, "CCI") + + except: + print("ERROR!\n") + + +# ----------------------------------------------------- MACD ----------------------------------------------------- +def macd(l_args, s_ticker, s_interval, df_stock): + parser = argparse.ArgumentParser(prog='macd', + description=""" The Moving Average Convergence Divergence (MACD) is the difference + between two Exponential Moving Averages. The Signal line is an Exponential Moving + Average of the MACD. \n \n The MACD signals trend changes and indicates the start + of new trend direction. High values indicate overbought conditions, low values + indicate oversold conditions. Divergence with the price indicates an end to the + current trend, especially if the MACD is at extreme high or low values. When the MACD + line crosses above the signal line a buy signal is generated. When the MACD crosses + below the signal line a sell signal is generated. To confirm the signal, the MACD + should be above zero for a buy, and below zero for a sell. """) + + parser.add_argument('-f', "--fast", action="store", dest="n_fast", type=check_positive, default=12, + help='The short period.') + parser.add_argument('-s', "--slow", action="store", dest="n_slow", type=check_positive, default=26, + help='The long period.') + parser.add_argument("--signal", action="store", dest="n_signal", type=check_positive, default=9, + help='The signal period.') + parser.add_argument('-o', "--offset", action="store", dest="n_offset", type=check_positive, default=0, + help='How many periods to offset the result.') + + 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}") + + # Daily + if s_interval == "1440min": + df_ta = ta.macd(df_stock['5. adjusted close'], fast=ns_parser.n_fast, slow=ns_parser.n_slow, + signal=ns_parser.n_signal, offset=ns_parser.n_offset).dropna() + plot_stock_and_ta(df_stock['5. adjusted close'], s_ticker, df_ta, "MACD") + # Intraday + else: + df_ta = ta.macd(df_stock['4. close'], fast=ns_parser.n_fast, slow=ns_parser.n_slow, + signal=ns_parser.n_signal, offset=ns_parser.n_offset).dropna() + plot_stock_and_ta(df_stock['4. close'], s_ticker, df_ta, "MACD") + + except: + print("ERROR!\n") + return + + +# ----------------------------------------------------- RSI ----------------------------------------------------- +def rsi(l_args, s_ticker, s_interval, df_stock): + parser = argparse.ArgumentParser(prog='rsi', + description=""" The Relative Strength Index (RSI) calculates a ratio of the + recent upward price movements to the absolute price movement. The RSI ranges + from 0 to 100. The RSI is interpreted as an overbought/oversold indicator when + the value is over 70/below 30. You can also look for divergence with price. If + the price is making new highs/lows, and the RSI is not, it indicates a reversal. """) + + parser.add_argument('-l', "--length", action="store", dest="n_length", type=check_positive, default=14, help='length') + parser.add_argument('-s', "--scalar", action="store", dest="n_scalar", type=check_positive, default=100, help='scalar') + parser.add_argument('-d', "--drift", action="store", dest="n_drift", type=check_positive, default=1, help='drift') + parser.add_argument('-o', "--offset", action="store", dest="n_offset", type=check_positive, default=0, help='offset') + + 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}") + + # Daily + if s_interval == "1440min": + df_ta = ta.rsi(df_stock['5. adjusted close'], length=ns_parser.n_length, scalar=ns_parser.n_scalar, + drift=ns_parser.n_drift, offset=ns_parser.n_offset).dropna() + plot_stock_and_ta(df_stock['5. adjusted close'], s_ticker, df_ta, "RSI") + # Intraday + else: + df_ta = ta.rsi(df_stock['4. close'], length=ns_parser.n_length, scalar=ns_parser.n_scalar, + drift=ns_parser.n_drift, offset=ns_parser.n_offset).dropna() + plot_stock_and_ta(df_stock['4. close'], s_ticker, df_ta, "RSI") + + except: + print("ERROR!\n") + return + + +# ----------------------------------------------------- STOCH ----------------------------------------------------- +def stoch(l_args, s_ticker, s_interval, df_stock): + parser = argparse.ArgumentParser(prog='stoch', + description=""" The Stochastic Oscillator measures where the close is in relation + to the recent trading range. The values range from zero to 100. %D values over 75 + indicate an overbought condition; values under 25 indicate an oversold condition. + When the Fast %D crosses above the Slow %D, it is a buy signal; when it crosses + below, it is a sell signal. The Raw %K is generally considered too erratic to use + for crossover signals. """) + + parser.add_argument('-k', "--fastkperiod", action="store", dest="n_fastkperiod", type=check_positive, default=14, + help='The time period of the fastk moving average') + parser.add_argument('-d', "--slowdperiod", action="store", dest="n_slowdperiod", type=check_positive, default=3, + help='TThe time period of the slowd moving average') + parser.add_argument("--slowkperiod", action="store", dest="n_slowkperiod", type=check_positive, default=3, + help='The time period of the slowk moving average') + parser.add_argument('-o', "--offset", action="store", dest="n_offset", type=check_positive, default=0, help='offset') + + 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}") + + # Daily + if s_interval == "1440min": + df_ta = ta.stoch(high=df_stock['2. high'], low=df_stock['3. low'], close=df_stock['5. adjusted close'], k=ns_parser.n_fastkperiod, + d=ns_parser.n_slowdperiod, smooth_k=ns_parser.n_slowkperiod, offset=ns_parser.n_offset).dropna() + plot_stock_and_ta(df_stock['5. adjusted close'], s_ticker, df_ta, "STOCH") + # Intraday + else: + df_ta = ta.stoch(high=df_stock['2. high'], low=df_stock['3. low'], close=df_stock['4. close'], k=ns_parser.n_fastkperiod, + d=ns_parser.n_slowdperiod, smooth_k=ns_parser.n_slowkperiod, offset=ns_parser.n_offset).dropna() + plot_stock_and_ta(df_stock['4. close'], s_ticker, df_ta, "STOCH") + + except: + print("ERROR!\n") + return + \ No newline at end of file diff --git a/technical_analysis/overlap.py b/technical_analysis/overlap.py new file mode 100644 index 00000000000..293ae15de7f --- /dev/null +++ b/technical_analysis/overlap.py @@ -0,0 +1,98 @@ +import argparse +import pandas_ta as ta +from stock_market_helper_funcs import * +from pandas.plotting import register_matplotlib_converters +register_matplotlib_converters() + +# ----------------------------------------------------- EMA ----------------------------------------------------- +def ema(l_args, s_ticker, s_interval, df_stock): + parser = argparse.ArgumentParser(prog='ema', + description=""" The Exponential Moving Average is a staple of technical + analysis and is used in countless technical indicators. 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. However, the Exponential + Moving Average is a cumulative calculation, including all data. Past values have + a diminishing contribution to the average, while more recent values have a greater + contribution. This method allows the moving average to be more responsive to changes + in the data. """) + + parser.add_argument('-l', "--length", action="store", dest="n_length", type=check_positive, default=10, help='length') + parser.add_argument('-o', "--offset", action="store", dest="n_offset", type=check_positive, default=0, help='offset') + + 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}") + + # Daily + if s_interval == "1440min": + df_ta = ta.ema(df_stock['5. adjusted close'], length=ns_parser.n_length, offset=ns_parser.n_offset).dropna() + plot_stock_ta(df_stock['5. adjusted close'], s_ticker, df_ta, "EMA") + # Intraday + else: + df_ta = ta.ema(df_stock['4. close'], length=ns_parser.n_length, offset=ns_parser.n_offset).dropna() + plot_stock_ta(df_stock['4. close'], s_ticker, df_ta, "EMA") + + except: + print("ERROR!\n") + return + + +# ----------------------------------------------------- SMA ----------------------------------------------------- +def sma(l_args, s_ticker, s_interval, df_stock): + parser = argparse.ArgumentParser(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=10, help='length') + parser.add_argument('-o', "--offset", action="store", dest="n_offset", type=check_positive, default=0, help='offset') + + 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}") + + # Daily + if s_interval == "1440min": + df_ta = ta.sma(df_stock['5. adjusted close'], length=ns_parser.n_length, offset=ns_parser.n_offset).dropna() + plot_stock_ta(df_stock['5. adjusted close'], s_ticker, df_ta, "SMA") + # Intraday + else: + df_ta = ta.sma(df_stock['4. close'], length=ns_parser.n_length, offset=ns_parser.n_offset).dropna() + plot_stock_ta(df_stock['4. close'], s_ticker, df_ta, "SMA") + + except: + print("ERROR!\n") + return + + +# ----------------------------------------------------- VWAP ----------------------------------------------------- +def vwap(l_args, s_ticker, s_interval, df_stock): + parser = argparse.ArgumentParser(prog='vwap', + description=""" The Volume Weighted Average Price that measures the average typical price + by volume. It is typically used with intraday charts to identify general direction. """) + + parser.add_argument('-o', "--offset", action="store", dest="n_offset", type=check_positive, default=0, help='offset') + + 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}") + + df_ta = ta.vwap(high=df_stock['2. high'], low=df_stock['3. low'], close=df_stock['4. close'], + volume=df_stock['5. volume'], offset=ns_parser.n_offset) + + plot_stock_ta(df_stock['4. close'], s_ticker, df_ta, "VWAP") + + except: + print("ERROR!\n") + return + \ No newline at end of file diff --git a/technical_analysis/trend.py b/technical_analysis/trend.py new file mode 100644 index 00000000000..cfb0b83b92e --- /dev/null +++ b/technical_analysis/trend.py @@ -0,0 +1,78 @@ +import argparse +import pandas_ta as ta +from stock_market_helper_funcs import * +from pandas.plotting import register_matplotlib_converters +register_matplotlib_converters() + +# ----------------------------------------------------- ADX ----------------------------------------------------- +def adx(l_args, s_ticker, s_interval, df_stock): + parser = argparse.ArgumentParser(prog='adx', + description=""" The ADX is a Welles Wilder style moving average of the Directional + Movement Index (DX). The values range from 0 to 100, but rarely get above 60. + To interpret the ADX, consider a high number to be a strong trend, and a low number, + a weak trend. """) + + parser.add_argument('-l', "--length", action="store", dest="n_length", type=check_positive, default=14, help='length') + parser.add_argument('-s', "--scalar", action="store", dest="n_scalar", type=check_positive, default=100, help='scalar') + parser.add_argument('-d', "--drift", action="store", dest="n_drift", type=check_positive, default=1, help='drift') + parser.add_argument('-o', "--offset", action="store", dest="n_offset", type=check_positive, default=0, help='offset') + + 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}") + + # Daily + if s_interval == "1440min": + df_ta = ta.adx(high=df_stock['2. high'], low=df_stock['3. low'], close=df_stock['5. adjusted close'], length=ns_parser.n_length, + scalar=ns_parser.n_scalar, drift=ns_parser.n_drift, offset=ns_parser.n_offset).dropna() + plot_stock_and_ta(df_stock['5. adjusted close'], s_ticker, df_ta, "ADX") + # Intraday + else: + df_ta = ta.adx(high=df_stock['2. high'], low=df_stock['3. low'], close=df_stock['4. close'], length=ns_parser.n_length, + scalar=ns_parser.n_scalar, drift=ns_parser.n_drift, offset=ns_parser.n_offset).dropna() + plot_stock_and_ta(df_stock['4. close'], s_ticker, df_ta, "ADX") + + except: + print("ERROR!\n") + return + + +# ----------------------------------------------------- AROON ----------------------------------------------------- +def aroon(l_args, s_ticker, s_interval, df_stock): + parser = argparse.ArgumentParser(prog='aroon', + description=""" The word aroon is Sanskrit for "dawn's early light." The Aroon + indicator attempts to show when a new trend is dawning. The indicator consists + of two lines (Up and Down) that measure how long it has been since the highest + high/lowest low has occurred within an n period range. \n \n When the Aroon Up is + staying between 70 and 100 then it indicates an upward trend. When the Aroon Down + is staying between 70 and 100 then it indicates an downward trend. A strong upward + trend is indicated when the Aroon Up is above 70 while the Aroon Down is below 30. + Likewise, a strong downward trend is indicated when the Aroon Down is above 70 while + the Aroon Up is below 30. Also look for crossovers. When the Aroon Down crosses above + the Aroon Up, it indicates a weakening of the upward trend (and vice versa). """) + + parser.add_argument('-l', "--length", action="store", dest="n_length", type=check_positive, default=14, help='length') + parser.add_argument('-s', "--scalar", action="store", dest="n_scalar", type=check_positive, default=100, help='scalar') + parser.add_argument('-o', "--offset", action="store", dest="n_offset", type=check_positive, default=0, help='offset') + + 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}") + + df_ta = ta.aroon(high=df_stock['2. high'], low=df_stock['3. low'], length=ns_parser.n_length, + scalar=ns_parser.n_scalar, offset=ns_parser.n_offset).dropna() + # Daily + if s_interval == "1440min": + plot_stock_and_ta(df_stock['5. adjusted close'], s_ticker, df_ta.iloc[:,-1], "AROON") + # Intraday + else: + plot_stock_and_ta(df_stock['4. close'], s_ticker, df_ta.iloc[:,-1], "AROON") + + except: + print("ERROR!\n") + return + \ No newline at end of file diff --git a/technical_analysis/volatility.py b/technical_analysis/volatility.py new file mode 100644 index 00000000000..0ae5fb83bbc --- /dev/null +++ b/technical_analysis/volatility.py @@ -0,0 +1,46 @@ +import argparse +import pandas_ta as ta +from stock_market_helper_funcs import * +from pandas.plotting import register_matplotlib_converters +register_matplotlib_converters() + +# ----------------------------------------------------- BBANDS ----------------------------------------------------- +def bbands(l_args, s_ticker, s_interval, df_stock): + parser = argparse.ArgumentParser(prog='bbands', + description=""" Bollinger Bands consist of three lines. The middle band is a simple + moving average (generally 20 periods) of the typical price (TP). The upper and lower + bands are F standard deviations (generally 2) above and below the middle band. + The bands widen and narrow when the volatility of the price is higher or lower, respectively. + \n \nBollinger Bands do not, in themselves, generate buy or sell signals; they are an + indicator of overbought or oversold conditions. When the price is near the upper or lower + band it indicates that a reversal may be imminent. The middle band becomes a support or + resistance level. The upper and lower bands can also be interpreted as price targets. + When the price bounces off of the lower band and crosses the middle band, then the + upper band becomes the price target. """) + + parser.add_argument('-l', "--length", action="store", dest="n_length", type=check_positive, default=5, help='length') + parser.add_argument('-s', "--std", action="store", dest="n_std", type=check_positive, default=2, help='std') + parser.add_argument('-m', "--mamode", action="store", dest="s_mamode", default="sma", help='mamode') + parser.add_argument('-o', "--offset", action="store", dest="n_offset", type=check_positive, default=0, help='offset') + + 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}") + + # Daily + if s_interval == "1440min": + df_ta = ta.bbands(close=df_stock['5. adjusted close'], length=ns_parser.n_length, std=ns_parser.n_std, + mamode=ns_parser.s_mamode, offset=ns_parser.n_offset).dropna() + plot_stock_ta(df_stock['5. adjusted close'], s_ticker, df_ta, "BBANDS") + # Intraday + else: + df_ta = ta.bbands(close=df_stock['4. close'], length=ns_parser.n_length, std=ns_parser.n_std, + mamode=ns_parser.s_mamode, offset=ns_parser.n_offset).dropna() + plot_stock_ta(df_stock['4. close'], s_ticker, df_ta, "BBANDS") + + except: + print("ERROR!\n") + return + \ No newline at end of file diff --git a/technical_analysis/volume.py b/technical_analysis/volume.py new file mode 100644 index 00000000000..96d7680705f --- /dev/null +++ b/technical_analysis/volume.py @@ -0,0 +1,91 @@ +import argparse +import pandas_ta as ta +from stock_market_helper_funcs import * +from pandas.plotting import register_matplotlib_converters +register_matplotlib_converters() + +# ------------------------------------------------------- AD ------------------------------------------------------- +def ad(l_args, s_ticker, s_interval, df_stock): + parser = argparse.ArgumentParser(prog='ad', + description=""" The Accumulation/Distribution Line is similar to the On Balance + Volume (OBV), which sums the volume times +1/-1 based on whether the close is + higher than the previous close. The Accumulation/Distribution indicator, however + multiplies the volume by the close location value (CLV). The CLV is based on the + movement of the issue within a single bar and can be +1, -1 or zero. \n \n + The Accumulation/Distribution Line is interpreted by looking for a divergence in + the direction of the indicator relative to price. If the Accumulation/Distribution + Line is trending upward it indicates that the price may follow. Also, if the + Accumulation/Distribution Line becomes flat while the price is still rising (or falling) + then it signals an impending flattening of the price.""") + + parser.add_argument('-o', "--offset", action="store", dest="n_offset", type=check_positive, default=0, help='offset') + parser.add_argument('--open', action="store_true", default=False, dest="b_use_open", help='uses open value of stock') + + 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}") + + # Daily + if s_interval == "1440min": + # Use open stock values + if ns_parser.b_use_open: + df_ta = ta.ad(high=df_stock['2. high'], low=df_stock['3. low'], close=df_stock['5. adjusted close'], + volume=df_stock['6. volume'], offset=ns_parser.n_offset, open_=df_stock['1. open']).dropna() + # Do not use open stock values + else: + df_ta = ta.ad(high=df_stock['2. high'], low=df_stock['3. low'], close=df_stock['5. adjusted close'], + volume=df_stock['6. volume'], offset=ns_parser.n_offset).dropna() + + plot_stock_and_ta(df_stock['5. adjusted close'], s_ticker, df_ta, "AD") + # Intraday + else: + # Use open stock values + if ns_parser.b_use_open: + df_ta = ta.ad(high=df_stock['2. high'], low=df_stock['3. low'], close=df_stock['4. close'], + volume=df_stock['5. volume'], offset=ns_parser.n_offset, open_=df_stock['1. open']).dropna() + # Do not use open stock values + else: + df_ta = ta.ad(high=df_stock['2. high'], low=df_stock['3. low'], close=df_stock['4. close'], + volume=df_stock['5. volume'], offset=ns_parser.n_offset).dropna() + + plot_stock_and_ta(df_stock['4. close'], s_ticker, df_ta, "AD") + + except: + print("ERROR!\n") + return + + +# ------------------------------------------------------- OBV ------------------------------------------------------- +def obv(l_args, s_ticker, s_interval, df_stock): + parser = argparse.ArgumentParser(prog='obv', + description=""" The On Balance Volume (OBV) is a cumulative total of the up and + down volume. When the close is higher than the previous close, the volume is added + to the running total, and when the close is lower than the previous close, the volume + is subtracted from the running total. \n \n To interpret the OBV, look for the OBV + to move with the price or precede price moves. If the price moves before the OBV, + then it is a non-confirmed move. A series of rising peaks, or falling troughs, in the + OBV indicates a strong trend. If the OBV is flat, then the market is not trending. """) + + parser.add_argument('-o', "--offset", action="store", dest="n_offset", type=check_positive, default=0, help='offset') + + 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}") + + # Daily + if s_interval == "1440min": + df_ta = ta.obv(close=df_stock['5. adjusted close'], volume=df_stock['6. volume'], offset=ns_parser.n_offset).dropna() + plot_stock_and_ta(df_stock['5. adjusted close'], s_ticker, df_ta, "OBV") + # Intraday + else: + df_ta = ta.obv(close=df_stock['4. close'], volume=df_stock['5. volume'], offset=ns_parser.n_offset).dropna() + plot_stock_and_ta(df_stock['4. close'], s_ticker, df_ta, "OBV") + + except: + print("ERROR!\n") + return + \ No newline at end of file