From 1561eafbc7dfa575c8bb7197bf64163c3df2665c Mon Sep 17 00:00:00 2001 From: Artem Veremey Date: Tue, 9 Mar 2021 09:43:26 -0800 Subject: [PATCH 1/8] Adding ARK orders --- gamestonk_terminal/discovery/ark_api.py | 93 ++++++++++++++++++++++ gamestonk_terminal/discovery/disc_menu.py | 6 ++ gamestonk_terminal/sentiment/reddit_api.py | 2 +- notebooks/templates/due_diligence.ipynb | 2 +- tests/test_discovery_ark_api.py | 10 +++ 5 files changed, 111 insertions(+), 2 deletions(-) create mode 100755 gamestonk_terminal/discovery/ark_api.py mode change 100644 => 100755 notebooks/templates/due_diligence.ipynb create mode 100755 tests/test_discovery_ark_api.py diff --git a/gamestonk_terminal/discovery/ark_api.py b/gamestonk_terminal/discovery/ark_api.py new file mode 100755 index 00000000000..45cddec38c1 --- /dev/null +++ b/gamestonk_terminal/discovery/ark_api.py @@ -0,0 +1,93 @@ +import argparse +import json +from pandas.core.base import DataError +from pandas.core.frame import DataFrame +import requests +from colorama import Fore, Style +from bs4 import BeautifulSoup +import pandas as pd + +from gamestonk_terminal.helper_funcs import ( + check_positive, + get_user_agent, + patch_pandas_text_adjustment, + parse_known_args_and_warn, +) +from gamestonk_terminal.config_terminal import USE_COLOR + + +def direction_color_red_green(val: str) -> str: + if val == "Buy": + ret = Fore.GREEN + val + Style.RESET_ALL + elif val == "Sell": + ret = Fore.RED + val + Style.RESET_ALL + else: + ret = val + + return ret + + +def get_ark_orders() -> DataFrame: + url_orders = "https://cathiesark.com/ark-funds-combined/trades" + + raw_page = requests.get(url_orders, headers={"User-Agent": get_user_agent()}).text + + parsed_script = BeautifulSoup(raw_page, "lxml").find( + "script", {"id": "__NEXT_DATA__"} + ) + + parsed_json = json.loads(parsed_script.string) + + df_orders = pd.json_normalize(parsed_json["props"]["pageProps"]["arkTrades"]) + df_orders.drop( + [ + "everything", + "everything.profile.customThumbnail", + "hidden", + "images.thumbnail", + ], + axis=1, + inplace=True, + ) + + df_orders["date"] = pd.to_datetime(df_orders["date"], format="%Y-%m-%dZ").dt.date + + return df_orders + + +def ark_orders(l_args): + parser = argparse.ArgumentParser( + prog="ARK Orders", + description=""" + Orders by ARK Investment Management LLC - https://ark-funds.com/. [Source: https://cathiesark.com] + """, + ) + + parser.add_argument( + "-n", + "--num", + action="store", + dest="n_num", + type=check_positive, + default=20, + help="Last N orders.", + ) + + ns_parser = parse_known_args_and_warn(parser, l_args) + + df_orders = get_ark_orders() + + if USE_COLOR: + df_orders["direction"] = df_orders["direction"].apply(direction_color_red_green) + + patch_pandas_text_adjustment() + + df_orders["link"] = "https://finviz.com/quote.ashx?t=" + df_orders["ticker"] + + pd.set_option("display.max_colwidth", None) + pd.set_option("display.max_rows", None) + print("") + print("Orders by ARK Investment Management LLC") + print("") + print(df_orders.head(ns_parser.n_num)) + print("") diff --git a/gamestonk_terminal/discovery/disc_menu.py b/gamestonk_terminal/discovery/disc_menu.py index bfabf65877b..e59a59f506b 100644 --- a/gamestonk_terminal/discovery/disc_menu.py +++ b/gamestonk_terminal/discovery/disc_menu.py @@ -5,6 +5,7 @@ from gamestonk_terminal.discovery import finviz_api from gamestonk_terminal.discovery import short_interest_api from gamestonk_terminal.discovery import seeking_alpha_api from gamestonk_terminal.discovery import fidelity_api +from gamestonk_terminal.discovery import ark_api from gamestonk_terminal.discovery import simply_wallst_api from gamestonk_terminal.discovery import spachero_api from gamestonk_terminal.discovery import unusual_whales_api @@ -24,6 +25,7 @@ def print_discovery(): print(" sectors show sectors performance [Alpha Vantage]") print(" gainers show latest top gainers [Yahoo Finance]") print(" orders orders by Fidelity Customers [Fidelity]") + print(" ark_orders orders by ARK Investment Management LLC") print(" up_earnings upcoming earnings release dates [Seeking Alpha]") print( " high_short show top high short interest stocks of over 20% ratio [www.highshortinterest.com]" @@ -53,6 +55,7 @@ def disc_menu(): "gainers", "spacs", "orders", + "ark_orders", "spachero", "high_short", "low_float", @@ -107,6 +110,9 @@ def disc_menu(): elif ns_known_args.cmd == "orders": fidelity_api.orders(l_args) + elif ns_known_args.cmd == "ark_orders": + ark_api.ark_orders(l_args) + elif ns_known_args.cmd == "simply_wallst": simply_wallst_api.simply_wallst(l_args) diff --git a/gamestonk_terminal/sentiment/reddit_api.py b/gamestonk_terminal/sentiment/reddit_api.py index ee29e03d1a3..a29a8863e23 100644 --- a/gamestonk_terminal/sentiment/reddit_api.py +++ b/gamestonk_terminal/sentiment/reddit_api.py @@ -308,7 +308,7 @@ def popular_tickers(l_args): n_top_stocks += 1 except HTTPError as e: if e.response.status_code != 404: - print(f"Unexpected exception from Fiviz: {e}") + print(f"Unexpected exception from Finviz: {e}") except Exception as e: print(e) diff --git a/notebooks/templates/due_diligence.ipynb b/notebooks/templates/due_diligence.ipynb old mode 100644 new mode 100755 index 460924d725e..139a074132b --- a/notebooks/templates/due_diligence.ipynb +++ b/notebooks/templates/due_diligence.ipynb @@ -102,7 +102,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.5" + "version": "3.8.8" } }, "nbformat": 4, diff --git a/tests/test_discovery_ark_api.py b/tests/test_discovery_ark_api.py new file mode 100755 index 00000000000..efb7dc17394 --- /dev/null +++ b/tests/test_discovery_ark_api.py @@ -0,0 +1,10 @@ +import unittest + +from gamestonk_terminal.discovery.ark_api import ( + ark_orders, +) + + +class TestDiscoveryArkApi(unittest.TestCase): + def test_ark_orders(self): + ark_orders([]) From e65446e22bba838dc69113d8945c40d56fcce6da Mon Sep 17 00:00:00 2001 From: Artem Veremey Date: Tue, 9 Mar 2021 09:44:26 -0800 Subject: [PATCH 2/8] Update filemod --- gamestonk_terminal/discovery/ark_api.py | 0 notebooks/templates/due_diligence.ipynb | 0 tests/test_discovery_ark_api.py | 0 3 files changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 gamestonk_terminal/discovery/ark_api.py mode change 100755 => 100644 notebooks/templates/due_diligence.ipynb mode change 100755 => 100644 tests/test_discovery_ark_api.py diff --git a/gamestonk_terminal/discovery/ark_api.py b/gamestonk_terminal/discovery/ark_api.py old mode 100755 new mode 100644 diff --git a/notebooks/templates/due_diligence.ipynb b/notebooks/templates/due_diligence.ipynb old mode 100755 new mode 100644 diff --git a/tests/test_discovery_ark_api.py b/tests/test_discovery_ark_api.py old mode 100755 new mode 100644 From 90215648abfbdf770bb33fe0bc7b2d47874ec99a Mon Sep 17 00:00:00 2001 From: Artem Veremey Date: Tue, 9 Mar 2021 09:49:19 -0800 Subject: [PATCH 3/8] Removing unused import --- gamestonk_terminal/discovery/ark_api.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/gamestonk_terminal/discovery/ark_api.py b/gamestonk_terminal/discovery/ark_api.py index 45cddec38c1..7299f8e4a9f 100644 --- a/gamestonk_terminal/discovery/ark_api.py +++ b/gamestonk_terminal/discovery/ark_api.py @@ -1,11 +1,10 @@ import argparse import json -from pandas.core.base import DataError -from pandas.core.frame import DataFrame import requests from colorama import Fore, Style from bs4 import BeautifulSoup import pandas as pd +from pandas.core.frame import DataFrame from gamestonk_terminal.helper_funcs import ( check_positive, From 192a3a70ca585963ff90f3a03c67abaacc919c50 Mon Sep 17 00:00:00 2001 From: Ricardo Ferraz Leal Date: Tue, 9 Mar 2021 20:09:43 -0500 Subject: [PATCH 4/8] Tests with prompt-toolkit --- gamestonk_terminal/discovery/disc_menu.py | 47 +++++++++++++---------- gamestonk_terminal/menu.py | 7 ++++ requirements-full.txt | 1 + requirements-old.txt | 1 + requirements-win.txt | 1 + requirements.txt | 1 + terminal.py | 47 +++++++++++++---------- 7 files changed, 63 insertions(+), 42 deletions(-) create mode 100644 gamestonk_terminal/menu.py diff --git a/gamestonk_terminal/discovery/disc_menu.py b/gamestonk_terminal/discovery/disc_menu.py index bfabf65877b..e6d05739121 100644 --- a/gamestonk_terminal/discovery/disc_menu.py +++ b/gamestonk_terminal/discovery/disc_menu.py @@ -11,6 +11,9 @@ from gamestonk_terminal.discovery import unusual_whales_api from gamestonk_terminal.helper_funcs import get_flair +from gamestonk_terminal.menu import session +from prompt_toolkit.completion import WordCompleter + def print_discovery(): """ Print help """ @@ -42,33 +45,35 @@ def disc_menu(): # Add list of arguments that the discovery parser accepts disc_parser = argparse.ArgumentParser(prog="discovery", add_help=False) - disc_parser.add_argument( - "cmd", - choices=[ - "help", - "q", - "quit", - "map", - "sectors", - "gainers", - "spacs", - "orders", - "spachero", - "high_short", - "low_float", - "up_earnings", - "simply_wallst", - "uwhales", - "mill", - ], - ) + choices = [ + "help", + "q", + "quit", + "map", + "sectors", + "gainers", + "spacs", + "orders", + "spachero", + "high_short", + "low_float", + "up_earnings", + "simply_wallst", + "uwhales", + "mill", + ] + disc_parser.add_argument("cmd", choices=choices) + word_completer = WordCompleter(choices) print_discovery() # Loop forever and ever while True: # Get input command from user - as_input = input(f"{get_flair()} (disc)> ") + as_input = session.prompt( + f"{get_flair()} (disc)> ", + completer=word_completer, + ) # Parse fundamental analysis command of the list of possible commands try: diff --git a/gamestonk_terminal/menu.py b/gamestonk_terminal/menu.py new file mode 100644 index 00000000000..4c898945042 --- /dev/null +++ b/gamestonk_terminal/menu.py @@ -0,0 +1,7 @@ +import os + +from prompt_toolkit import PromptSession +from prompt_toolkit.history import FileHistory + +history_file = os.path.join(os.path.expanduser("~"), ".gamestonk_terminal.his") +session = PromptSession(history=FileHistory(history_file)) diff --git a/requirements-full.txt b/requirements-full.txt index 4ee3b88a656..2618656e3f1 100644 --- a/requirements-full.txt +++ b/requirements-full.txt @@ -156,3 +156,4 @@ wrapt==1.12.1; python_version >= "3.6" and python_full_version < "3.0.0" or pyth yarl==1.6.3; python_version >= "3.6" yfinance==0.1.55 zipp==3.4.1; python_version < "3.8" and python_version >= "3.6" +prompt-toolkit==3.0.16; python_version >= "3.6" diff --git a/requirements-old.txt b/requirements-old.txt index 01857adc3ce..a6b15ffebcc 100644 --- a/requirements-old.txt +++ b/requirements-old.txt @@ -133,3 +133,4 @@ wrapt==1.12.1; python_version >= "3.6" and python_full_version < "3.0.0" or pyth yarl==1.6.3; python_version >= "3.6" yfinance==0.1.55 zipp==3.4.0; python_version >= "3.6" and python_full_version < "3.0.0" and python_version < "3.8" or python_full_version >= "3.2.0" and python_version >= "3.6" and python_version < "3.8" +prompt-toolkit==3.0.16; python_version >= "3.6" diff --git a/requirements-win.txt b/requirements-win.txt index b77624f1fc1..6049dad70ca 100644 --- a/requirements-win.txt +++ b/requirements-win.txt @@ -133,3 +133,4 @@ wrapt==1.12.1; python_version >= "3.6" and python_full_version < "3.0.0" or pyth yarl==1.6.3; python_version >= "3.6" yfinance==0.1.55 zipp==3.4.0; python_version >= "3.6" and python_full_version < "3.0.0" and python_version < "3.8" or python_full_version >= "3.2.0" and python_version >= "3.6" and python_version < "3.8" +prompt-toolkit==3.0.16; python_version >= "3.6" diff --git a/requirements.txt b/requirements.txt index 81e052a160e..c08fd5316b7 100644 --- a/requirements.txt +++ b/requirements.txt @@ -90,3 +90,4 @@ websocket-client==0.58.0; python_version >= "3.6" and python_full_version < "3.0 yarl==1.6.3; python_version >= "3.6" yfinance==0.1.55 zipp==3.4.1; python_version < "3.8" and python_version >= "3.6" +prompt-toolkit==3.0.16; python_version >= "3.6" diff --git a/terminal.py b/terminal.py index 4c982d6106f..c954e3329fa 100644 --- a/terminal.py +++ b/terminal.py @@ -15,6 +15,9 @@ from gamestonk_terminal.sentiment import sen_menu as sm from gamestonk_terminal.papermill import papermill_menu as mill from gamestonk_terminal import res_menu as rm from gamestonk_terminal import config_terminal as cfg +from gamestonk_terminal.menu import session +from prompt_toolkit.completion import WordCompleter + # import warnings # warnings.simplefilter("always") @@ -42,26 +45,25 @@ def main(): # Add list of arguments that the main parser accepts menu_parser = argparse.ArgumentParser(prog="gamestonk_terminal", add_help=False) - menu_parser.add_argument( - "opt", - choices=[ - "help", - "quit", - "q", - "clear", - "load", - "view", - "export", - "disc", - "mill", - "sen", - "res", - "fa", - "ta", - "dd", - "pred", - ], - ) + choices = [ + "help", + "quit", + "q", + "clear", + "load", + "view", + "export", + "disc", + "mill", + "sen", + "res", + "fa", + "ta", + "dd", + "pred", + ] + menu_parser.add_argument("opt", choices=choices) + word_completer = WordCompleter(choices) # Print first welcome message and help print("") @@ -77,7 +79,10 @@ def main(): should_print_help = False # Get input command from user - as_input = input(f"{get_flair()}> ") + as_input = session.prompt( + f"{get_flair()}> ", + completer=word_completer, + ) # Is command empty if not as_input: From c71754db23d59ca23c34e22662f8b9f54925a095 Mon Sep 17 00:00:00 2001 From: Artem Veremey Date: Tue, 9 Mar 2021 23:00:03 -0800 Subject: [PATCH 5/8] Adding order total and candle info --- gamestonk_terminal/discovery/ark_api.py | 43 ++++++++++++++++++++++++- tests/test_discovery_ark_api.py | 2 +- 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/gamestonk_terminal/discovery/ark_api.py b/gamestonk_terminal/discovery/ark_api.py index 7299f8e4a9f..7dd5fb4d665 100644 --- a/gamestonk_terminal/discovery/ark_api.py +++ b/gamestonk_terminal/discovery/ark_api.py @@ -1,10 +1,13 @@ import argparse +from datetime import timedelta import json import requests from colorama import Fore, Style from bs4 import BeautifulSoup +import numpy as np import pandas as pd from pandas.core.frame import DataFrame +import yfinance as yf from gamestonk_terminal.helper_funcs import ( check_positive, @@ -54,6 +57,40 @@ def get_ark_orders() -> DataFrame: return df_orders +def add_order_total(df_orders: DataFrame) -> DataFrame: + start_date = df_orders["date"].iloc[-1] - timedelta(days=1) + + tickers = " ".join(df_orders["ticker"].unique()) + + print("") + + prices = yf.download(tickers, start=start_date, progress=False) + + for i, candle in enumerate(["Volume", "Open", "Close", "High", "Low", "Total"]): + df_orders.insert(i + 3, candle.lower(), 0) + + for i, _ in df_orders.iterrows(): + if np.isnan( + prices["Open"][df_orders.loc[i, "ticker"]][ + df_orders.loc[i, "date"].strftime("%Y-%m-%d") + ] + ): + for candle in ["Volume", "Open", "Close", "High", "Low", "Total"]: + df_orders.loc[i, candle.lower()] = 0 + continue + + for candle in ["Volume", "Open", "Close", "High", "Low"]: + df_orders.loc[i, candle.lower()] = prices[candle][ + df_orders.loc[i, "ticker"] + ][df_orders.loc[i, "date"].strftime("%Y-%m-%d")] + + df_orders.loc[i, "total"] = ( + df_orders.loc[i, "close"] * df_orders.loc[i, "shares"] + ) + + return df_orders + + def ark_orders(l_args): parser = argparse.ArgumentParser( prog="ARK Orders", @@ -76,6 +113,9 @@ def ark_orders(l_args): df_orders = get_ark_orders() + pd.set_option("mode.chained_assignment", None) + df_orders = add_order_total(df_orders.head(ns_parser.n_num)) + if USE_COLOR: df_orders["direction"] = df_orders["direction"].apply(direction_color_red_green) @@ -85,8 +125,9 @@ def ark_orders(l_args): pd.set_option("display.max_colwidth", None) pd.set_option("display.max_rows", None) + pd.set_option("display.float_format", "{:,.2f}".format) print("") print("Orders by ARK Investment Management LLC") print("") - print(df_orders.head(ns_parser.n_num)) + print(df_orders.to_string(index=False)) print("") diff --git a/tests/test_discovery_ark_api.py b/tests/test_discovery_ark_api.py index efb7dc17394..c9589f13dc2 100644 --- a/tests/test_discovery_ark_api.py +++ b/tests/test_discovery_ark_api.py @@ -7,4 +7,4 @@ from gamestonk_terminal.discovery.ark_api import ( class TestDiscoveryArkApi(unittest.TestCase): def test_ark_orders(self): - ark_orders([]) + ark_orders(["-n", "2"]) From 5095ac9cb2f73ae07b9f7147cffd5cde84248da2 Mon Sep 17 00:00:00 2001 From: DidierRLopes Date: Wed, 10 Mar 2021 21:34:08 +0000 Subject: [PATCH 6/8] Update ROADMAP.md --- ROADMAP.md | 27 +++++---------------------- 1 file changed, 5 insertions(+), 22 deletions(-) diff --git a/ROADMAP.md b/ROADMAP.md index 92ac7a66635..cb48d6dcab9 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -21,51 +21,43 @@ ## Discovery ### Short term -* Add Cathy's ARK trading activity (@aia) * Top Losers (@didier) -### Medium term -* Add screeners (@didier) ### Long term +* Add screeners (@didier) ## Behavioral Analysis ### Short term * Implement a better Twitter client (@aia) -### Medium term: -* Add Stocktwits (@aia) ### Long term +* Add Stocktwits (@aia) ## Sell-side Equity Research ### Short term -### Medium term ### Long term ## Fundamental Analysis ### Short term * Multi-ticker comparison (@didier) -### Medium term +* Rearrange FA menu to have AV and FMP as submenus (@didier) ### Long term ## Technical Analysis ### Short term -### Medium term * Add auto-recognition of major TA patterns (@didier) ### Long term ## Due Diligence ### Short term -### Medium term ### Long term ## Prediction Techniques ### Short term -* Implement several exponential smoothing methods (@didier) -### Medium term ### Long term ### Reports @@ -73,40 +65,34 @@ ### Short term * Expand Due Diligence report * Add multi-ticker comparison report -### Medium term ### Long term ## Portfolio Analysis ### Short term -### Medium term ### Long term ## Credit Analysis ### Short term -### Medium term ### Long term ## Cryptocurrencies ### Short term -### Medium term ### Long term ## Backend ### Short term -### Medium term +### Long term * Add caching * APIs -### Long term * GraphQL ## Frontend ### Short term -### Medium term ### Long term ## Developer Experience @@ -114,13 +100,10 @@ ### Short term * Add Windows CI (@aia) * Write a developer guide -### Medium term ### Long term ## User Experience ### Short term -### Medium term -* Add a WHL installation ### Long term - +* Add a WHL installation From 0405cd79ad53c8333be4744c72744757f489da9f Mon Sep 17 00:00:00 2001 From: DidierRLopes Date: Wed, 10 Mar 2021 21:34:35 +0000 Subject: [PATCH 7/8] Update ROADMAP.md --- ROADMAP.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ROADMAP.md b/ROADMAP.md index cb48d6dcab9..4080bece07e 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -60,7 +60,7 @@ ### Short term ### Long term -### Reports +## Reports ### Short term * Expand Due Diligence report From 5ba8b6ac76aee3f298065410eaa69d0e1c938945 Mon Sep 17 00:00:00 2001 From: DidierRLopes Date: Wed, 10 Mar 2021 21:43:12 +0000 Subject: [PATCH 8/8] Update README.md --- gamestonk_terminal/discovery/README.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/gamestonk_terminal/discovery/README.md b/gamestonk_terminal/discovery/README.md index a8de67a3bf4..c97af26a238 100644 --- a/gamestonk_terminal/discovery/README.md +++ b/gamestonk_terminal/discovery/README.md @@ -10,6 +10,8 @@ This menu aims to discover new stocks, and the usage of the following commands a * show latest top gainers [Yahoo Finance] * [orders](#orders) * orders by Fidelity Customers [Fidelity] +* [ark_orders](#ark_orders) + * orders by ARK Investment Management LLC [https://cathiesark.com] * [up_earnings](#up_earnings) * upcoming earnings release dates [Seeking Alpha] * [high_short](#high_short) @@ -70,6 +72,19 @@ Orders by Fidelity customers. Information shown in the table below is based on t Captura de ecrã 2021-02-20, às 11 45 43 +## ark_orders + +```shell +usage: ark_orders [-n N_NUM] +``` + + Orders by ARK Investment Management LLC - https://ark-funds.com/. [Source: https://cathiesark.com] + +* -n : Last N orders to be printed. Default 20. + +Captura de ecrã 2021-03-10, às 21 36 38 + + ## up_earnings ```shell