From 3762693df7a1f8cdfeba5e14c4438f993a2eead0 Mon Sep 17 00:00:00 2001 From: DidierRLopes Date: Thu, 20 Oct 2022 01:35:23 +0100 Subject: [PATCH] Add intro command + improve plot style + internationalisation consistency (#2899) * improve style of plots * remove the blend which doesnt look nice in some machines * remove translation for arguments to be coherent * Add intro command * add check to understand if its first time user to run intro by default * intro doesnt require docs * silly catch * fix line length * anoter lengthy line * unused import * unused import * words * allow to quit earlier * style * fix thing for u didi * actual fix * last try Co-authored-by: Colin Delahunty <72827203+colin99d@users.noreply.github.com> Co-authored-by: james --- .github/workflows/test.yml | 2 +- openbb_terminal/keys_controller.py | 14 ++ openbb_terminal/miscellaneous/i18n/en.yml | 19 +- .../styles/default/dark.mplstyle | 6 +- openbb_terminal/rich_config.py | 11 +- openbb_terminal/stocks/stocks_controller.py | 38 ++-- openbb_terminal/terminal_controller.py | 190 +++++++++++++++++- 7 files changed, 226 insertions(+), 54 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index bd40316aaa5..a72559eb029 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -27,7 +27,7 @@ jobs: key: ${{ runner.os }}-v1-linting restore-keys: ${{ runner.os }}-v1-linting - - run: python custom_pre_commit/check_doc.py --ignore-files=settings_controller.py,keys_controller.py,featflags_controller.py,degiro_controller.py,oanda_controller.py --ignore-commands=login,al_swe,info_swe,goodness,resources,yf,yolo,featflags,guess,settings,survey + - run: python custom_pre_commit/check_doc.py --ignore-files=settings_controller.py,keys_controller.py,featflags_controller.py,degiro_controller.py,oanda_controller.py --ignore-commands=login,al_swe,info_swe,goodness,resources,yf,yolo,featflags,guess,settings,survey,intro - run: pip install bandit black codespell flake8 mypy pyupgrade safety pylint==2.15.2 - run: pip install types-pytz types-requests types-termcolor types-tabulate types-PyYAML types-python-dateutil types-setuptools types-six - run: bandit -x ./tests -r . || true diff --git a/openbb_terminal/keys_controller.py b/openbb_terminal/keys_controller.py index 8d7259e9678..e7643d570ff 100644 --- a/openbb_terminal/keys_controller.py +++ b/openbb_terminal/keys_controller.py @@ -56,6 +56,20 @@ class KeysController(BaseController): # pylint: disable=too-many-public-methods for api in tqdm(self.API_LIST, desc="Checking keys status"): self.status_dict[api] = getattr(keys_model, "check_" + str(api) + "_key")() + def is_there_at_least_one_key_defined(self) -> bool: + """Check if there is at least 1 API key defined. + This is a good proxy to understand whether we are in presence of a first time user or not + + Returns + ------- + bool + True if at least 1 key is defined, False otherwise + """ + for api in self.API_LIST: + if getattr(keys_model, "check_" + str(api) + "_key")() != "not defined": + return True + return False + def print_help(self): """Print help""" self.check_keys_status() diff --git a/openbb_terminal/miscellaneous/i18n/en.yml b/openbb_terminal/miscellaneous/i18n/en.yml index 4204c97bc96..07b468a8016 100644 --- a/openbb_terminal/miscellaneous/i18n/en.yml +++ b/openbb_terminal/miscellaneous/i18n/en.yml @@ -13,6 +13,7 @@ en: wiki: search for an expression in Wikipedia (https://www.wikipedia.org/) record: record session to be converted into a .openbb routine stop: stop session recording + intro: introduction on the OpenBB Terminal _configure_: Configure your own terminal _main_menu_: Main menu keys/_keys_: This menu allows you to set your own API keys. Type 'about' for more information @@ -85,31 +86,13 @@ en: dashboards: interactive dashboards using voila and jupyter notebooks reports: customizable research reports through jupyter notebooks stocks/search: search a specific stock ticker for analysis - stocks/SEARCH: Show companies matching the search query - stocks/SEARCH_query: The search term used to find company tickers - stocks/SEARCH_country: Search by country to find stocks matching the criteria - stocks/SEARCH_sector: Search by sector to find stocks matching the criteria - stocks/SEARCH_industry: Search by industry to find stocks matching the criteria - stocks/SEARCH_exchange: Search by a specific exchange country to find stocks matching the criteria stocks/load: load a specific stock ticker and additional info for analysis stocks/_ticker: Stock stocks/quote: view the current price for a specific stock ticker stocks/tob: view top of book for loaded ticker (US exchanges only) - stocks/QUOTE: Current quote for stock ticker - stocks/QUOTE_ticker: Stock ticker stocks/candle: view a candle chart for a specific stock ticker - stocks/CANDLE: Shows historic data for a stock - stocks/CANDLE_plotly: Flag to show interactive plotly chart - stocks/CANDLE_sort: Choose a column to sort by. Only works when raw data is displayed. - stocks/CANDLE_descending: Sort selected column descending. Only works when raw data is displayed. - stocks/CANDLE_raw: Shows raw data instead of chart. If sort is set those are the top ones, otherwise we grab latest data to date - stocks/CANDLE_trend: Flag to add high and low trends to candle - stocks/CANDLE_mov_avg: Add moving average in number of days to plot and separate by a comma stocks/news: latest news of the company stocks/codes: FIGI, SIK and SIC codes codes - stocks/NEWS_date: The starting date (format YYYY-MM-DD) to search articles from - stocks/NEWS_oldest: Show oldest articles first - stocks/NEWS_article: Show news only from the sources specified (e.g bbc yahoo.com) stocks/th: trading hours, check open markets stocks/options: options menu, chains, open interest, greeks, parity stocks/disc: discover trending stocks, map, sectors, high short interest diff --git a/openbb_terminal/miscellaneous/styles/default/dark.mplstyle b/openbb_terminal/miscellaneous/styles/default/dark.mplstyle index 52ac57cf4dd..7613947e631 100644 --- a/openbb_terminal/miscellaneous/styles/default/dark.mplstyle +++ b/openbb_terminal/miscellaneous/styles/default/dark.mplstyle @@ -2,7 +2,7 @@ # LINES # http://matplotlib.org/api/artist_api.html#module-matplotlib.lines -lines.linewidth: 1.1 +lines.linewidth: 3 lines.color: F5EFF3 lines.linestyle: - lines.marker: None @@ -26,7 +26,7 @@ font.style: normal font.variant: normal font.weight: medium font.stretch: normal -font.size: 13 +font.size: 20 text.color: F5EFF3 @@ -34,7 +34,7 @@ axes.spines.left: true axes.spines.bottom: true axes.spines.top: true axes.spines.right: true -axes.linewidth: 0.2 +axes.linewidth: 0.4 axes.labelsize: small axes.titlelocation: left diff --git a/openbb_terminal/rich_config.py b/openbb_terminal/rich_config.py index 2372fbbd842..c78b6c7438d 100644 --- a/openbb_terminal/rich_config.py +++ b/openbb_terminal/rich_config.py @@ -8,7 +8,6 @@ from typing import Tuple from rich import panel from rich.console import Console, Theme from rich.text import Text -from rich.color import Color import i18n from openbb_terminal.core.config.paths import MISCELLANEOUS_DIRECTORY from openbb_terminal import config_terminal as cfg @@ -291,15 +290,7 @@ class ConsoleAndPanel: if kwargs and "text" in list(kwargs) and "menu" in list(kwargs): if not os.getenv("TEST_MODE"): if obbff.ENABLE_RICH_PANEL: - version = self.blend_text( - f"OpenBB Terminal v{obbff.VERSION}", - Color.parse("#00AAFF").triplet, - Color.parse("#E4003A").triplet, - ) - link = " (https://openbb.co)" - link_text = Text(link) - link_text.stylize("#FCED00", 0, len(link)) - version += link_text + version = f"[param]OpenBB Terminal v{obbff.VERSION}[/param] (https://openbb.co)" self.console.print( panel.Panel( "\n" + kwargs["text"], diff --git a/openbb_terminal/stocks/stocks_controller.py b/openbb_terminal/stocks/stocks_controller.py index cc2e1dbb1df..c5172f53053 100644 --- a/openbb_terminal/stocks/stocks_controller.py +++ b/openbb_terminal/stocks/stocks_controller.py @@ -227,7 +227,7 @@ class StocksController(StockBaseController): add_help=False, formatter_class=argparse.ArgumentDefaultsHelpFormatter, prog="search", - description=translate("stocks/SEARCH"), + description="Show companies matching the search query", ) parser.add_argument( "-q", @@ -237,7 +237,7 @@ class StocksController(StockBaseController): type=str.lower, default="", nargs="+", - help=translate("stocks/SEARCH_query"), + help="The search term used to find company tickers", ) parser.add_argument( "-c", @@ -246,7 +246,7 @@ class StocksController(StockBaseController): nargs=argparse.ONE_OR_MORE, action=choice_check_after_action(AllowArgsWithWhiteSpace, self.country), dest="country", - help=translate("stocks/SEARCH_country"), + help="Search by country to find stocks matching the criteria", ) parser.add_argument( "-s", @@ -255,7 +255,7 @@ class StocksController(StockBaseController): nargs=argparse.ONE_OR_MORE, action=choice_check_after_action(AllowArgsWithWhiteSpace, self.sector), dest="sector", - help=translate("stocks/SEARCH_sector"), + help="Search by sector to find stocks matching the criteria", ) parser.add_argument( "-i", @@ -264,7 +264,7 @@ class StocksController(StockBaseController): nargs=argparse.ONE_OR_MORE, action=choice_check_after_action(AllowArgsWithWhiteSpace, self.industry), dest="industry", - help=translate("stocks/SEARCH_industry"), + help="Search by industry to find stocks matching the criteria", ) parser.add_argument( "-e", @@ -272,7 +272,7 @@ class StocksController(StockBaseController): default="", choices=list(stocks_helper.market_coverage_suffix.keys()), dest="exchange_country", - help=translate("stocks/SEARCH_exchange"), + help="Search by a specific exchange country to find stocks matching the criteria", ) if other_args and "-" not in other_args[0][0]: other_args.insert(0, "-q") @@ -336,7 +336,7 @@ class StocksController(StockBaseController): add_help=False, formatter_class=argparse.ArgumentDefaultsHelpFormatter, prog="quote", - description=translate("stocks/QUOTE"), + description="Current quote for stock ticker", ) if self.ticker: parser.add_argument( @@ -345,7 +345,7 @@ class StocksController(StockBaseController): action="store", dest="s_ticker", default=ticker, - help=translate("stocks/QUOTE_ticker"), + help="Stock ticker", ) else: parser.add_argument( @@ -386,7 +386,7 @@ class StocksController(StockBaseController): add_help=False, formatter_class=argparse.ArgumentDefaultsHelpFormatter, prog="candle", - description=translate("stocks/CANDLE"), + description="Shows historic data for a stock", ) parser.add_argument( "-p", @@ -394,7 +394,7 @@ class StocksController(StockBaseController): dest="plotly", action="store_false", default=True, - help=translate("stocks/CANDLE_plotly"), + help="Flag to show interactive plotly chart", ) parser.add_argument( "--sort", @@ -402,7 +402,7 @@ class StocksController(StockBaseController): default="", type=str, dest="sort", - help=translate("stocks/CANDLE_sort"), + help="Choose a column to sort by. Only works when raw data is displayed.", ) parser.add_argument( "-d", @@ -410,28 +410,28 @@ class StocksController(StockBaseController): action="store_false", dest="descending", default=True, - help=translate("stocks/CANDLE_descending"), + help="Sort selected column descending. Only works when raw data is displayed.", ) parser.add_argument( "--raw", action="store_true", dest="raw", default=False, - help=translate("stocks/CANDLE_raw"), + help="Shows raw data instead of chart.", ) parser.add_argument( "-t", "--trend", action="store_true", default=False, - help=translate("stocks/CANDLE_trend"), + help="Flag to add high and low trends to candle", dest="trendlines", ) parser.add_argument( "--ma", dest="mov_avg", type=str, - help=translate("stocks/CANDLE_mov_avg"), + help="Add moving average in number of days to plot and separate by a comma", default=None, ) parser.add_argument( @@ -514,7 +514,7 @@ class StocksController(StockBaseController): parser = argparse.ArgumentParser( add_help=False, prog="news", - description=translate("stocks/news"), + description="latest news of the company", ) parser.add_argument( "-d", @@ -523,7 +523,7 @@ class StocksController(StockBaseController): dest="n_start_date", type=valid_date, default=datetime.now() - timedelta(days=7), - help=translate("stocks/NEWS_date"), + help="The starting date (format YYYY-MM-DD) to search articles from", ) parser.add_argument( "-o", @@ -531,7 +531,7 @@ class StocksController(StockBaseController): action="store_false", dest="n_oldest", default=True, - help=translate("stocks/NEWS_oldest"), + help="Show oldest articles first", ) parser.add_argument( "-s", @@ -539,7 +539,7 @@ class StocksController(StockBaseController): dest="sources", default=[], nargs="+", - help=translate("stocks/NEWS_sources"), + help="Show news only from the sources specified (e.g bbc yahoo.com)", ) if other_args and "-" not in other_args[0][0]: other_args.insert(0, "-l") diff --git a/openbb_terminal/terminal_controller.py b/openbb_terminal/terminal_controller.py index a775a85a19d..573261eff8f 100644 --- a/openbb_terminal/terminal_controller.py +++ b/openbb_terminal/terminal_controller.py @@ -11,6 +11,7 @@ import sys import webbrowser from typing import List import dotenv +from rich import panel from prompt_toolkit import PromptSession from prompt_toolkit.completion import NestedCompleter @@ -19,7 +20,9 @@ from prompt_toolkit.formatted_text import HTML import pandas as pd from openbb_terminal import feature_flags as obbff +from openbb_terminal import keys_controller from openbb_terminal.terminal_helper import is_packaged_application + from openbb_terminal.core.config.paths import ( HOME_DIRECTORY, MISCELLANEOUS_DIRECTORY, @@ -39,7 +42,7 @@ from openbb_terminal.loggers import setup_logging from openbb_terminal.core.log.generation.settings_logger import log_all_settings from openbb_terminal.menu import session from openbb_terminal.parent_classes import BaseController -from openbb_terminal.rich_config import console, MenuText, translate +from openbb_terminal.rich_config import console, MenuText from openbb_terminal.terminal_helper import ( bootup, check_for_updates, @@ -53,7 +56,8 @@ from openbb_terminal.terminal_helper import ( from openbb_terminal.helper_funcs import parse_and_split_input from openbb_terminal.common import feedparser_view -# pylint: disable=too-many-public-methods,import-outside-toplevel,too-many-branches,no-member,C0302 +# pylint: disable=too-many-public-methods,import-outside-toplevel +# pylint: disable=too-many-branches,no-member,C0302,too-many-return-statements logger = logging.getLogger(__name__) @@ -72,6 +76,7 @@ class TerminalController(BaseController): "exe", "guess", "news", + "intro", ] CHOICES_MENUS = [ "stocks", @@ -135,6 +140,7 @@ class TerminalController(BaseController): """Print help""" mt = MenuText("") mt.add_info("_home_") + mt.add_cmd("intro") mt.add_cmd("about") mt.add_cmd("support") mt.add_cmd("survey") @@ -177,7 +183,7 @@ class TerminalController(BaseController): parse = argparse.ArgumentParser( add_help=False, prog="news", - description=translate("news"), + description="display news articles based on term and data sources", ) parse.add_argument( "-t", @@ -450,6 +456,180 @@ class TerminalController(BaseController): self.queue = self.load_class(SourcesController, self.queue) + def call_intro(self, _): + """Process intro command""" + console.print(panel.Panel("[purple]Welcome to the OpenBB Terminal.[/purple]")) + console.print( + "\nThe following walkthrough will guide you towards making the most out of the OpenBB Terminal.\n\n" + "Press Enter to continue or 'q' followed by Enter to exit." + ) + if input("") == "q": + return + console.print("\n") + + console.print(panel.Panel("[purple]#1 - Commands vs menu.[/purple]")) + console.print( + "\nMenus are a collection of 'commands' and 'sub-menus'.\n" + "You can identify them through their distinct color and a '>' at the beginning of the line\n\n" + "For instance:\n" + "[menu]> stocks access historical pricing data, options, sector [/menu]" + "[menu]and industry, and overall due diligence [/menu]\n\n\n" + "Commands are expected to return data either as a chart or table.\n" + "You can identify them through their distinct color\n\n" + "For instance:\n" + "[cmds]> news display news articles based on term and data sources [/cmds]" + ) + if input("") == "q": + return + console.print("\n") + + console.print(panel.Panel("[purple]#2 - Using commands[/purple]")) + console.print( + "\nCommands throughout the terminal can have additional arguments.\n\n" + "Let's say that in the current menu, you want to have more information about the command 'news'. \n\n" + "You can either see the available arguments in the terminal, using: [param]news -h[/param]\n\n", + "or you can find out more about it with an output example on the browser, using: [param]about news[/param]", + ) + if input("") == "q": + return + console.print("\n") + + console.print(panel.Panel("[purple]#3 - Setting API Keys[/purple]")) + console.print( + "\nThe OpenBB Terminal does not own any of the data you have access to.\n\n" + "Instead, we provide the infrastructure to access over 100 different data sources from a single location.\n\n" + "Thus, it is necessary for each user to set their own API keys for the various third party sources\n\n" + "You can find more about this on the '[param]keys[/param]' menu.\n\n" + "For many commands, there are multiple data sources that can be selected.\n\n" + "The help menu shows the data sources supported by each command.\n\n" + "For instance:\n" + "[cmds] load load a specific stock ticker and additional info for analysis [/cmds]" + "[src][YahooFinance, IEXCloud, AlphaVantage, Polygon, EODHD] [/src]\n\n" + "The user can go into the '[param]sources[/param]' menu and select their preferred default data source." + ) + if input("") == "q": + return + console.print("\n") + + console.print( + panel.Panel("[purple]#4 - Symbol dependent menus and commands[/purple]") + ) + console.print( + "\nThroughout the terminal, you will see commands and menus greyed out.\n\n" + "These menus or commands cannot be accessed until an object is loaded.\n\n" + "Let's take as an example the '[param]stocks[/param]' menu.\n\n" + "You will see that the command '[param]disc[/param]' is available as its goal is to discover new tickers:\n" + "[menu]> stocks access historical pricing data, options, sector [/menu]\n\n" + "On the other hand, '[param]fa[/param]' menu (fundamental analysis) requires a ticker to be loaded.\n\n" + "And therefore, appears as:\n" + "[dim]> fa fundamental analysis of loaded ticker [/dim]\n\n" + "Once a ticker is loaded with: [param]load TSLA[/param]\n\n" + "The '[param]fa[/param]' menu will be available as:\n" + "[menu]> fa fundamental analysis of loaded ticker [/menu]" + ) + if input("") == "q": + return + console.print("\n") + + console.print(panel.Panel("[purple]#5 - Terminal Navigation[/purple]")) + console.print( + "\nThe terminal has a tree like structure, where menus branch off into new menus.\n\n" + "The users current location is displayed before the text prompt.\n\n" + "For instance, if the user is inside the menu disc which is inside stocks, the following prompt " + "will appear: \n2022 Oct 18, 21:53 (🦋) [param]/stocks/disc/[/param] $\n\n" + "If the user wants to go back to the menu above, all they need to do is type '[param]q[/param]'.\n\n" + "If the user wants to go back to the home of the terminal, they can type '[param]/[/param]' instead.\n\n" + "Note: Always type '[param]h[/param]' to know what commands are available in each menu" + ) + if input("") == "q": + return + console.print("\n") + + console.print(panel.Panel("[purple]#6 - Command Pipeline[/purple]")) + console.print( + "\nThe terminal offers the capability of allowing users to speed up their navigation and command execution." + "\n\nTherefore, typing the following prompt is valid:\n" + "2022 Oct 18, 21:53 (🦋) / $ [param]stocks/load TSLA/dd/pt[/param]\n\n" + "In this example, the terminal - in a single action - will go into '[param]stocks[/param]' menu, " + "run command '[param]load[/param]' with '[param]TSLA[/param]' as input, \n" + "go into sub-menu '[param]dd[/param]' (due diligence) and run the command '[param]pt[/param]' (price target)." + ) + if input("") == "q": + return + console.print("\n") + + console.print(panel.Panel("[purple]#6 - OpenBB Scripts[/purple]")) + console.print( + "\nThe command pipeline capability is great, but the user experience wasn't great copy-pasting large " + "lists of commands.\n\n" + "We allow the user to create a text file of the form:\n\n" + "[param]FOLDER_PATH/my_script.openbb[/param]\n" + "stocks\nload TSLA\ndd\npt\n\n" + "which can be run through the '[param]exe[/param]' command in the home menu, with:\n" + "2022 Oct 18, 22:33 (🦋) / $ [param]exe FOLDER_PATH/my_script.openbb[/param]\n\n" + ) + if input("") == "q": + return + console.print("\n") + + console.print( + panel.Panel("[purple]#7 - OpenBB Scripts with Arguments[/purple]") + ) + console.print( + "\nThe user can create a script that includes arguments for the commands.\n\n" + "Example:\n\n" + "[param]FOLDER_PATH/my_script_with_variable_input.openbb[/param]\n" + "stocks\n# this is a comment\nload $ARGV[0]\ndd\npt\nq\nload $ARGV[1]\ncandle\n\n" + "and then, if this script is run with:\n" + "2022 Oct 18, 22:33 (🦋) / $ [param]exe FOLDER_PATH/my_script_with_variable_input.openbb " + "-i AAPL,MSFT[/param]\n\n" + "This means that the [param]pt[/param] will run on [param]AAPL[/param] while " + "[param]candle[/param] on [param]MSFT[/param]" + ) + if input("") == "q": + return + console.print("\n") + + console.print(panel.Panel("[purple]#8 - OpenBB Script Generation/purple]")) + console.print( + "\n" + "To make it easier for users to create scripts, we have created a " + "command that 'records' user commands " + "directly into a script.\n\n" + "From the home menu, the user can run:\n" + "2022 Oct 18, 22:33 (🦋) / $ [param]record[/param]\n\n" + "and then perform your typical investment research workflow before entering\n\n" + "2022 Oct 18, 22:33 (🦋) / $ [param]stop[/param]\n\n" + "After stopping, the script will be saved to the 'scripts' folder." + ) + if input("") == "q": + return + console.print("\n") + + console.print(panel.Panel("[purple]#9 - Terminal Customization[/purple]")) + console.print( + "\nUsers should explore the [param]settings[/param] and [param]featflags[/param] menus " + "to configure their terminal.\n\n" + "The fact that our terminal is fully open source allows users to be able to customize " + "anything they want.\n\n" + "If you are interested in contributing to the project, please check:\n" + "[param]https://github.com/OpenBB-finance/OpenBBTerminal[/param]" + ) + if input("") == "q": + return + console.print("\n") + + console.print(panel.Panel("[purple]#10 - Support[/purple]")) + console.print( + "\n" + "We are nothing without our community, hence we put a lot of effort in being here for you.\n\n" + "If you find any bug that you wish to report to improve the terminal you can do so with:\n" + "2022 Oct 18, 22:33 (🦋) / $ [param]support CMD[/param]\n\n" + "which should open a form in your browser where you can report the bug in said 'CMD'.\n\n" + "If you want to know more, or have any further question. Please join us on Discord:\n" + "[param]https://openbb.co/discord[/param]" + ) + def call_exe(self, other_args: List[str]): """Process exe command""" # Merge rest of string path to other_args and remove queue since it is a dir @@ -638,6 +818,10 @@ def terminal(jobs_cmds: List[str] = None, test_mode=False): bootup() if not jobs_cmds: welcome_message() + + if not keys_controller.KeysController().is_there_at_least_one_key_defined(): + t_controller.call_intro(None) + t_controller.print_help() check_for_updates()