diff --git a/ROADMAP.md b/ROADMAP.md
index 92ac7a66635..4080bece07e 100644
--- a/ROADMAP.md
+++ b/ROADMAP.md
@@ -21,92 +21,78 @@
## 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
+## Reports
### 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
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
+## 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.
+
+
+
+
## up_earnings
```shell
diff --git a/gamestonk_terminal/discovery/ark_api.py b/gamestonk_terminal/discovery/ark_api.py
new file mode 100644
index 00000000000..7dd5fb4d665
--- /dev/null
+++ b/gamestonk_terminal/discovery/ark_api.py
@@ -0,0 +1,133 @@
+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,
+ 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 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",
+ 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()
+
+ 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)
+
+ patch_pandas_text_adjustment()
+
+ df_orders["link"] = "https://finviz.com/quote.ashx?t=" + df_orders["ticker"]
+
+ pd.set_option("display.max_colwidth", None)
+ pd.set_option("display.max_rows", None)
+ pd.set_option("display.float_format", "{:,.2f}".format)
+ print("")
+ print("Orders by ARK Investment Management LLC")
+ print("")
+ print(df_orders.to_string(index=False))
+ print("")
diff --git a/gamestonk_terminal/discovery/disc_menu.py b/gamestonk_terminal/discovery/disc_menu.py
index bfabf65877b..bc6c3717efc 100644
--- a/gamestonk_terminal/discovery/disc_menu.py
+++ b/gamestonk_terminal/discovery/disc_menu.py
@@ -5,12 +5,16 @@ 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
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 """
@@ -24,6 +28,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]"
@@ -42,33 +47,36 @@ 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",
+ "ark_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:
@@ -107,6 +115,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/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/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
index 460924d725e..139a074132b 100644
--- 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/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 8ac585ebe99..a4e13d7a71f 100644
--- a/terminal.py
+++ b/terminal.py
@@ -16,6 +16,9 @@ from gamestonk_terminal.papermill import papermill_menu as mill
from gamestonk_terminal.comparison_analysis import ca_menu as cam
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")
@@ -43,27 +46,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",
- "ca",
- "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("\nWelcome to Gamestonk Terminal 🚀\n")
@@ -77,7 +78,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:
diff --git a/tests/test_discovery_ark_api.py b/tests/test_discovery_ark_api.py
new file mode 100644
index 00000000000..c9589f13dc2
--- /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(["-n", "2"])