From 47b84083a2c408b8cf12f392f6b4e4b978092d05 Mon Sep 17 00:00:00 2001 From: didier Date: Sun, 7 Mar 2021 14:13:25 +0000 Subject: [PATCH 1/5] fix typo in overlap ema pred --- gamestonk_terminal/technical_analysis/overlap.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gamestonk_terminal/technical_analysis/overlap.py b/gamestonk_terminal/technical_analysis/overlap.py index 8e6ba2db373..4139aeb6841 100644 --- a/gamestonk_terminal/technical_analysis/overlap.py +++ b/gamestonk_terminal/technical_analysis/overlap.py @@ -82,7 +82,7 @@ def ema(l_args, s_ticker, s_interval, df_stock): plt.plot(df_ta.index, df_ta.values) # Pandas series if len(df_ta.shape) == 1: - l_legend = ["{ns_parser.n_length} EMA"] + l_legend = [f"{ns_parser.n_length} EMA"] # Pandas dataframe else: l_legend = df_ta.columns.tolist() From ad42962ee60db128c95028b4adf09b8a03d84245 Mon Sep 17 00:00:00 2001 From: didier Date: Sun, 7 Mar 2021 14:14:04 +0000 Subject: [PATCH 2/5] get main data from quandl and not alpha vantage --- gamestonk_terminal/helper_funcs.py | 7 +++ gamestonk_terminal/main_helper.py | 73 ++++++++++++++++++++++++------ 2 files changed, 66 insertions(+), 14 deletions(-) diff --git a/gamestonk_terminal/helper_funcs.py b/gamestonk_terminal/helper_funcs.py index d1167c838b5..ca59f38e8fa 100644 --- a/gamestonk_terminal/helper_funcs.py +++ b/gamestonk_terminal/helper_funcs.py @@ -301,3 +301,10 @@ def lett_to_num(word: str) -> str: for (a, b) in replacements: word = word.replace(a, b) return word + + +def check_sources(source: str) -> str: + available_historical_price_sources = ["quandl", "av"] + if source in available_historical_price_sources: + return source + raise argparse.ArgumentTypeError("This source for historical data is not available.") \ No newline at end of file diff --git a/gamestonk_terminal/main_helper.py b/gamestonk_terminal/main_helper.py index 0f6e81e4fd7..ed9055887e1 100644 --- a/gamestonk_terminal/main_helper.py +++ b/gamestonk_terminal/main_helper.py @@ -2,6 +2,7 @@ import argparse from sys import stdout import pandas as pd from alpha_vantage.timeseries import TimeSeries +import yfinance as yf from gamestonk_terminal.helper_funcs import ( valid_date, @@ -9,6 +10,7 @@ from gamestonk_terminal.helper_funcs import ( parse_known_args_and_warn, check_ohlc, lett_to_num, + check_sources, ) from gamestonk_terminal import config_terminal as cfg @@ -82,7 +84,7 @@ def clear(l_args, s_ticker, s_start, s_interval, df_stock): def load(l_args, s_ticker, s_start, s_interval, df_stock): parser = argparse.ArgumentParser( - prog="load", description=""" Load a stock in order to perform analysis""" + prog="load", description=""" Load a stock in order to perform analysis.""" ) parser.add_argument( "-t", @@ -110,6 +112,16 @@ def load(l_args, s_ticker, s_start, s_interval, df_stock): help="Intraday stock minutes", ) + parser.add_argument( + "--source", + action="store", + dest="source", + type=check_sources, + default="quandl", + help="Source of historical data. Intraday: Only 'av' available." + "Daily: 'quandl' and 'av' available.", + ) + try: # For the case where a user uses: 'load BB' if l_args: @@ -128,21 +140,56 @@ def load(l_args, s_ticker, s_start, s_interval, df_stock): s_interval = str(ns_parser.n_interval) + "min" try: - ts = TimeSeries(key=cfg.API_KEY_ALPHAVANTAGE, output_format="pandas") # Daily if s_interval == "1440min": - # pylint: disable=unbalanced-tuple-unpacking - df_stock, _ = ts.get_daily_adjusted( - symbol=ns_parser.s_ticker, outputsize="full" - ) + + if ns_parser.source == "av": + ts = TimeSeries(key=cfg.API_KEY_ALPHAVANTAGE, output_format="pandas") + # pylint: disable=unbalanced-tuple-unpacking + df_stock, _ = ts.get_daily_adjusted( + symbol=ns_parser.s_ticker, outputsize="full" + ) + df_stock.sort_index(ascending=True, inplace=True) + + # Slice dataframe from the starting date YYYY-MM-DD selected + df_stock = df_stock[ns_parser.s_start_date :] + + elif ns_parser.source == "quandl": + df_stock = yf.download( + ns_parser.s_ticker, start=ns_parser.s_start_date, progress=False + ) + # Check that a stock was successfully retrieved + if df_stock.empty: + print("") + return [s_ticker, s_start, s_interval, df_stock] + + df_stock = df_stock.rename( + columns={ + "Open": "1. open", + "High": "2. high", + "Low": "3. low", + "Close": "4. close", + "Adj Close": "5. adjusted close", + "Volume": "6. volume", + } + ) # Intraday else: - # pylint: disable=unbalanced-tuple-unpacking - df_stock, _ = ts.get_intraday( - symbol=ns_parser.s_ticker, outputsize="full", interval=s_interval - ) + if ns_parser.source == "av": + ts = TimeSeries(key=cfg.API_KEY_ALPHAVANTAGE, output_format="pandas") + # pylint: disable=unbalanced-tuple-unpacking + df_stock, _ = ts.get_intraday( + symbol=ns_parser.s_ticker, outputsize="full", interval=s_interval + ) + df_stock.sort_index(ascending=True, inplace=True) - df_stock.sort_index(ascending=True, inplace=True) + # Slice dataframe from the starting date YYYY-MM-DD selected + df_stock = df_stock[ns_parser.s_start_date :] + + elif ns_parser.source == "quandl": + print( + "Unfortunately, quandl historical data doesn't contain intraday prices" + ) except Exception as e: print(e) @@ -152,8 +199,6 @@ def load(l_args, s_ticker, s_start, s_interval, df_stock): s_intraday = (f"Intraday {s_interval}", "Daily")[s_interval == "1440min"] if s_start: - # Slice dataframe from the starting date YYYY-MM-DD selected - df_stock = df_stock[ns_parser.s_start_date :] print( f"Loading {s_intraday} {s_ticker} stock with starting period {s_start.strftime('%Y-%m-%d')} for analysis." ) @@ -289,7 +334,7 @@ def view(l_args, s_ticker, s_start, s_interval, df_stock): def export(l_args, df_stock): parser = argparse.ArgumentParser( prog="export", - description="Exports the historical data from this ticker to a file or stdout", + description="Exports the historical data from this ticker to a file or stdout.", ) parser.add_argument( "-f", From 78196121f894295b4b9bb5a5976f1ff461deeb3c Mon Sep 17 00:00:00 2001 From: didier Date: Sun, 7 Mar 2021 14:14:16 +0000 Subject: [PATCH 3/5] Improve research menu --- gamestonk_terminal/res_menu.py | 57 ++++++++-------------------------- terminal.py | 6 ++-- 2 files changed, 17 insertions(+), 46 deletions(-) diff --git a/gamestonk_terminal/res_menu.py b/gamestonk_terminal/res_menu.py index 78fcb10cfbc..97940ac24f9 100644 --- a/gamestonk_terminal/res_menu.py +++ b/gamestonk_terminal/res_menu.py @@ -2,10 +2,16 @@ import argparse import webbrowser -# ----------------------------------------------------------------------------------------------------------------------- -def print_research(): +def print_research(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("\nResearch Mode:") print(" help show this fundamental analysis menu again") print(" q quit this menu, and shows back to main menu") @@ -33,8 +39,7 @@ def print_research(): print("") -# ---------------------------------------------------- MENU ---------------------------------------------------- -def res_menu(s_ticker): +def res_menu(s_ticker, s_start, s_interval): # Add list of arguments that the research parser accepts res_parser = argparse.ArgumentParser(prog="discovery", add_help=False) res_parser.add_argument( @@ -64,7 +69,7 @@ def res_menu(s_ticker): ], ) - print_research() + print_research(s_ticker, s_start, s_interval) # Loop forever and ever while True: @@ -80,7 +85,7 @@ def res_menu(s_ticker): try: if ns_known_args.cmd == "help": - print_research() + print_research(s_ticker, s_start, s_interval) elif ns_known_args.cmd == "q": # Just leave the RES menu @@ -90,116 +95,80 @@ def res_menu(s_ticker): # Abandon the program return True - # ------------------------------------------------------------------------------------------------------------ elif ns_known_args.cmd == "macroaxis": webbrowser.open(f"https://www.macroaxis.com/invest/market/{s_ticker}") - print("") - # ------------------------------------------------------------------------------------------------------------ elif ns_known_args.cmd == "yahoo": webbrowser.open(f"https://finance.yahoo.com/quote/{s_ticker}") - print("") - # ------------------------------------------------------------------------------------------------------------ elif ns_known_args.cmd == "finviz": webbrowser.open(f"https://finviz.com/quote.ashx?t={s_ticker}") - print("") - # ------------------------------------------------------------------------------------------------------------ elif ns_known_args.cmd == "marketwatch": webbrowser.open( f"https://www.marketwatch.com/investing/stock/{s_ticker}" ) - print("") - # ------------------------------------------------------------------------------------------------------------ elif ns_known_args.cmd == "fool": webbrowser.open(f"https://www.fool.com/quote/{s_ticker}") - print("") - # ------------------------------------------------------------------------------------------------------------ elif ns_known_args.cmd == "businessinsider": webbrowser.open( f"https://markets.businessinsider.com/stocks/{s_ticker}-stock/" ) - print("") - # ------------------------------------------------------------------------------------------------------------ elif ns_known_args.cmd == "fmp": webbrowser.open( f"https://financialmodelingprep.com/financial-summary/{s_ticker}" ) - print("") - # ------------------------------------------------------------------------------------------------------------ elif ns_known_args.cmd == "fidelity": webbrowser.open( f"https://eresearch.fidelity.com/eresearch/goto/evaluate/snapshot.jhtml?symbols={s_ticker}" ) - print("") - # ------------------------------------------------------------------------------------------------------------ elif ns_known_args.cmd == "tradingview": webbrowser.open(f"https://www.tradingview.com/symbols/{s_ticker}") - print("") - # ------------------------------------------------------------------------------------------------------------ elif ns_known_args.cmd == "marketchameleon": webbrowser.open(f"https://marketchameleon.com/Overview/{s_ticker}") - print("") - # ------------------------------------------------------------------------------------------------------------ elif ns_known_args.cmd == "stockrow": webbrowser.open(f"https://stockrow.com/{s_ticker}") - print("") - # ------------------------------------------------------------------------------------------------------------ elif ns_known_args.cmd == "barchart": webbrowser.open( f"https://www.barchart.com/stocks/quotes/{s_ticker}/overview" ) - print("") - # ------------------------------------------------------------------------------------------------------------ elif ns_known_args.cmd == "grufity": webbrowser.open(f"https://grufity.com/stock/{s_ticker}") - print("") - # ------------------------------------------------------------------------------------------------------------ elif ns_known_args.cmd == "fintel": webbrowser.open(f"https://fintel.io/s/us/{s_ticker}") - print("") - # ------------------------------------------------------------------------------------------------------------ elif ns_known_args.cmd == "zacks": webbrowser.open(f"https://www.zacks.com/stock/quote/{s_ticker}") - print("") - # ------------------------------------------------------------------------------------------------------------ elif ns_known_args.cmd == "macrotrends": webbrowser.open( f"https://www.macrotrends.net/stocks/charts/{s_ticker}/{s_ticker}/market-cap" ) - print("") - # ------------------------------------------------------------------------------------------------------------ elif ns_known_args.cmd == "newsfilter": webbrowser.open(f"https://newsfilter.io/search?query={s_ticker}") - print("") - # ------------------------------------------------------------------------------------------------------------ elif ns_known_args.cmd == "resources": # webbrowser.open(f"https://www.tradinganalysisresources.com/2020/05/free-references-and-resources.html") webbrowser.open( "https://moongangcapital.com/free-stock-market-resources/" ) - print("") - - # ------------------------------------------------------------------------------------------------------------ else: print("Command not recognized!") + print("") + except SystemExit: print("") return False diff --git a/terminal.py b/terminal.py index f61d9121061..18dc78e8bac 100644 --- a/terminal.py +++ b/terminal.py @@ -127,7 +127,7 @@ def main(): b_quit = sm.sen_menu(s_ticker, s_start) elif ns_known_args.opt == "res": - b_quit = rm.res_menu(s_ticker) + b_quit = rm.res_menu(s_ticker, s_start, s_interval) elif ns_known_args.opt == "fa": b_quit = fam.fa_menu(s_ticker, s_start, s_interval) @@ -163,7 +163,9 @@ def main(): if s_interval == "1440min": b_quit = pm.pred_menu(df_stock, s_ticker, s_start, s_interval) # If stock data is intradaily, we need to get data again as prediction - # techniques work on daily adjusted data + # techniques work on daily adjusted data. By default we load data from + # Alpha Vantage because the historical data loaded gives a larger + # dataset than the one provided by quandl else: try: ts = TimeSeries( From 7b75da36e45a9075f90d24e72127c9ccda35e5b7 Mon Sep 17 00:00:00 2001 From: didier Date: Sun, 7 Mar 2021 14:21:25 +0000 Subject: [PATCH 4/5] make lint happy --- gamestonk_terminal/helper_funcs.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/gamestonk_terminal/helper_funcs.py b/gamestonk_terminal/helper_funcs.py index ca59f38e8fa..0aa4a1a40a4 100644 --- a/gamestonk_terminal/helper_funcs.py +++ b/gamestonk_terminal/helper_funcs.py @@ -307,4 +307,6 @@ def check_sources(source: str) -> str: available_historical_price_sources = ["quandl", "av"] if source in available_historical_price_sources: return source - raise argparse.ArgumentTypeError("This source for historical data is not available.") \ No newline at end of file + raise argparse.ArgumentTypeError( + "This source for historical data is not available." + ) From e87ec05ce017d2a92d2cc745856719540f0fc7cb Mon Sep 17 00:00:00 2001 From: didier Date: Sun, 7 Mar 2021 14:28:09 +0000 Subject: [PATCH 5/5] Fix name from quandl to yf --- gamestonk_terminal/helper_funcs.py | 2 +- gamestonk_terminal/main_helper.py | 13 ++++++------- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/gamestonk_terminal/helper_funcs.py b/gamestonk_terminal/helper_funcs.py index 0aa4a1a40a4..521d15f1801 100644 --- a/gamestonk_terminal/helper_funcs.py +++ b/gamestonk_terminal/helper_funcs.py @@ -304,7 +304,7 @@ def lett_to_num(word: str) -> str: def check_sources(source: str) -> str: - available_historical_price_sources = ["quandl", "av"] + available_historical_price_sources = ["yf", "av"] if source in available_historical_price_sources: return source raise argparse.ArgumentTypeError( diff --git a/gamestonk_terminal/main_helper.py b/gamestonk_terminal/main_helper.py index ed9055887e1..4416e5f1bcc 100644 --- a/gamestonk_terminal/main_helper.py +++ b/gamestonk_terminal/main_helper.py @@ -111,15 +111,14 @@ def load(l_args, s_ticker, s_start, s_interval, df_stock): choices=[1, 5, 15, 30, 60], help="Intraday stock minutes", ) - parser.add_argument( "--source", action="store", dest="source", type=check_sources, - default="quandl", + default="yf", help="Source of historical data. Intraday: Only 'av' available." - "Daily: 'quandl' and 'av' available.", + "Daily: 'yf' and 'av' available.", ) try: @@ -154,7 +153,7 @@ def load(l_args, s_ticker, s_start, s_interval, df_stock): # Slice dataframe from the starting date YYYY-MM-DD selected df_stock = df_stock[ns_parser.s_start_date :] - elif ns_parser.source == "quandl": + elif ns_parser.source == "yf": df_stock = yf.download( ns_parser.s_ticker, start=ns_parser.s_start_date, progress=False ) @@ -186,14 +185,14 @@ def load(l_args, s_ticker, s_start, s_interval, df_stock): # Slice dataframe from the starting date YYYY-MM-DD selected df_stock = df_stock[ns_parser.s_start_date :] - elif ns_parser.source == "quandl": + elif ns_parser.source == "yf": print( - "Unfortunately, quandl historical data doesn't contain intraday prices" + "Unfortunately, yahoo finance historical data doesn't contain intraday prices" ) except Exception as e: print(e) - print("Either the ticker or the API_KEY are invalids. Try again!") + print("Either the ticker or the API_KEY are invalids. Try again!\n") return [s_ticker, s_start, s_interval, df_stock] s_intraday = (f"Intraday {s_interval}", "Daily")[s_interval == "1440min"]