diff options
author | Chavithra PARANA <chavithra@gmail.com> | 2022-11-28 19:21:48 +0100 |
---|---|---|
committer | Chavithra PARANA <chavithra@gmail.com> | 2022-11-28 19:21:48 +0100 |
commit | 80aa4768c6e1c00c02aba9bbb8168e401fc32c9f (patch) | |
tree | 96b6171a3e97ee16233a35a4fa961dbe5d5a58e3 | |
parent | a4fce79bf7f151f25d32ac4f26c10430f888e22d (diff) | |
parent | c7d0c98aa8d804fb5063b41e91ba2489a5e165e4 (diff) |
Merge branch 'main' of github.com:OpenBB-finance/OpenBBTerminal
-rw-r--r-- | build/docker/README.md | 55 | ||||
-rw-r--r-- | build/docker/build.sh | 3 | ||||
-rw-r--r-- | build/docker/poetry.dockerfile | 10 | ||||
-rw-r--r-- | build/pyinstaller/hooks/hook-inspect.py | 39 | ||||
-rw-r--r-- | build/pyinstaller/terminal.spec | 4 | ||||
-rw-r--r-- | openbb_terminal/etf/discovery/disc_controller.py | 19 | ||||
-rw-r--r-- | openbb_terminal/etf/etf_controller.py | 104 | ||||
-rw-r--r-- | openbb_terminal/etf/screener/screener_controller.py | 33 | ||||
-rw-r--r-- | openbb_terminal/etf/technical_analysis/ta_controller.py | 183 | ||||
-rw-r--r-- | openbb_terminal/portfolio/portfolio_optimization/parameters/params_helpers.py | 41 | ||||
-rw-r--r-- | openbb_terminal/portfolio/portfolio_optimization/parameters/params_view.py | 11 | ||||
-rw-r--r-- | openbb_terminal/reports/reports_controller.py | 4 | ||||
-rw-r--r-- | pyproject.toml | 6 | ||||
-rw-r--r-- | tests/openbb_terminal/etf/technical_analysis/test_ta_controller.py | 4 |
14 files changed, 214 insertions, 302 deletions
diff --git a/build/docker/README.md b/build/docker/README.md deleted file mode 100644 index be6d097e4ea..00000000000 --- a/build/docker/README.md +++ /dev/null @@ -1,55 +0,0 @@ -# OpenBBTerminal Docker - -These files create our docker images. To use docker read [this](openbb_terminal/DOCKER_README.md). - -## Building the Docker Image - -Building the Docker image can be done easily. The following steps allow users to create a docker -image on their local machine: - -1. Enter the OpenBB directory `cd ~/OpenbbTerminal` -1. Open `docker/compose.env` and set `OPENBBTERMINAL_DOCKER_RELEASE_VERSION` to the desired version -1. Load the environment variables `bash compose/env` -1. Run the build script `bash docker/build.sh` - -### Important Notes - -1. The `build.sh` script requires bash 5.0 or newer. -1. We currently build without developer dependnencies such as pytest. If you want to develop using - this image please open `poetry.dockerfile` and replace `RUN poetry install --no-dev` with - `RUN poetry install` -1. If you have issues building on MacOs run the following commands: - - - `export DOCKER_BUILDKIT=0` - - `export COMPOSE_DOCKER_CLI_BUILD=0` - -## Testing the Docker Image - -Integration and unit tests can be run on the new docker image. Before running either set of tests -you need to start up an image with: - -- `docker run -it --rm ghcr.io/[BUILD_NAME]` - -Leave the terminal open and then navigate docker desktop. Find the currently running image and -select `open in terminal`. Now: - -- For integration tests run: `poetry run python terminal.py scripts -t` -- For unit tests run `poetry run pytest tests/` - -## Setup Explanation - -The `compose.env` file is responsible for loading in the correct environment variables before a -session begins. Once this is done the `build.sh` file creates a docker image with the appropriate -tag. The `poetry.dockerfile` is the file used to create the image. It has enhanced caching by -building in three stages. The stages are described below. - -- python: this stage creates a new `python:3.9-slim-bullseye` image. Slim-buster is a small linux - distro that comes with a lot of the functionality we need. We then set environment variables. - This image will only be reran when there is a new version of `python:3.9-slim-bullseye` or when - the environment variables are updated (there is almost never a reason to update them). -- poetry-deps: this stage installs necessary apt packages like curl and git, and then installs - poetry. This will be reran whenever dependencies change, or whenever `python` has been rerun. -- poetry: this takes the build from `poetry-deps` and then copies the terminal files into it. Then - this image runs the terminal. This image will be rebuilt every time files are changed in the - terminal or when `poetry-deps` has been rerun, however; this is not an issue because it builds - quickly. diff --git a/build/docker/build.sh b/build/docker/build.sh index 97d49fcc173..2b1451944ee 100644 --- a/build/docker/build.sh +++ b/build/docker/build.sh @@ -16,4 +16,5 @@ echo "OPENBBTERMINAL_DOCKER_RELEASE_VERSION = $OPENBBTERMINAL_DOCKER_RELEASE_VER # DISPLAY IMAGES NAMES echo "OPENBBTERMINAL_DOCKER_POETRY_IMAGE = $OPENBBTERMINAL_DOCKER_POETRY_IMAGE" -docker build -f docker/poetry.dockerfile -t "${OPENBBTERMINAL_DOCKER_POETRY_IMAGE}" . +# Docker command to build image +docker build -f build/docker/poetry.dockerfile -t "${OPENBBTERMINAL_DOCKER_POETRY_IMAGE}" .
\ No newline at end of file diff --git a/build/docker/poetry.dockerfile b/build/docker/poetry.dockerfile index 2028cb4c6a1..218c53079bc 100644 --- a/build/docker/poetry.dockerfile +++ b/build/docker/poetry.dockerfile @@ -45,16 +45,15 @@ RUN curl -sSL https://install.python-poetry.org | python3 - # copy project requirement files here to ensure they will be cached. WORKDIR $PYSETUP_PATH -# Copy poetry files and install git -COPY pyproject.toml openbb_terminal/SDK_README.md poetry.lock ./ +# Copy poetry files +COPY pyproject.toml website/content/sdk/quickstart/installation.md poetry.lock ./ RUN mkdir $PYSETUP_PATH/openbb_terminal -RUN mv SDK_README.md ./openbb_terminal +RUN mv installation.md ./website/content/sdk/quickstart RUN touch openbb_terminal/__init__.py # install runtime deps - uses $POETRY_VIRTUALENVS_IN_PROJECT internally -RUN poetry install -RUN poetry install -E optimization +RUN poetry install --no-dev --no-interaction -E optimization -E prediction ############################################### # Production Image openbb poetry build @@ -66,7 +65,6 @@ COPY --from=poetry-deps $PYSETUP_PATH $PYSETUP_PATH WORKDIR $PYSETUP_PATH COPY . . -RUN pip install "u8darts[torch]" RUN echo "OPENBB_LOGGING_APP_NAME=gst_docker" > .env diff --git a/build/pyinstaller/hooks/hook-inspect.py b/build/pyinstaller/hooks/hook-inspect.py new file mode 100644 index 00000000000..718972baf50 --- /dev/null +++ b/build/pyinstaller/hooks/hook-inspect.py @@ -0,0 +1,39 @@ +# Runtime hook copied from pyinstaller + + +import inspect +import os +import sys + +# pylint:disable=W0622,W0212,E1101 + +_orig_inspect_getsourcefile = inspect.getsourcefile + + +# Provide custom implementation of inspect.getsourcefile() for frozen applications that properly resolves relative +# filenames obtained from object (e.g., inspect stack-frames). See #5963. +def _pyi_getsourcefile(object): + filename = inspect.getfile(object) + if not os.path.isabs(filename): + # Check if given filename matches the basename of __main__'s __file__. + if hasattr(sys.modules["__main__"], "__file__"): + main_file = sys.modules["__main__"].__file__ + if filename == os.path.basename(main_file): + return main_file + + # If filename ends with .py suffix and does not correspond to frozen entry-point script, convert it to + # corresponding .pyc in sys._MEIPASS. + if filename.endswith(".py"): + filename = os.path.normpath(os.path.join(sys._MEIPASS, filename + "c")) + # Ensure the relative path did not try to jump out of sys._MEIPASS, just in case... + if filename.startswith(sys._MEIPASS): + return filename + elif filename.startswith(sys._MEIPASS) and filename.endswith(".pyc"): + # If filename is already PyInstaller-compatible, prevent any further processing (i.e., with original + # implementation). + return filename + # Use original implementation as a fallback. + return _orig_inspect_getsourcefile(object) + + +inspect.getsourcefile = _pyi_getsourcefile diff --git a/build/pyinstaller/terminal.spec b/build/pyinstaller/terminal.spec index 1d2dc508569..926e10f69f2 100644 --- a/build/pyinstaller/terminal.spec +++ b/build/pyinstaller/terminal.spec @@ -44,6 +44,8 @@ added_files = [ (os.path.join(pathex, "user_agent"), "user_agent"), (os.path.join(pathex, "vaderSentiment"), "vaderSentiment"), (os.path.join(pathex, "prophet"), "prophet"), + (os.path.join(pathex, "riskfolio"), "riskfolio"), + (os.path.join(pathex, "astropy"), "astropy"), (os.path.join(pathex, "frozendict", "VERSION"), "frozendict"), ( os.path.join(pathex, "linearmodels", "datasets"), @@ -91,6 +93,8 @@ hidden_imports = [ "_sysconfigdata__darwin_darwin", "prophet", "debugpy", + "riskfolio", + "astropy", ] diff --git a/openbb_terminal/etf/discovery/disc_controller.py b/openbb_terminal/etf/discovery/disc_controller.py index e4af43d3165..0c8ee2a9205 100644 --- a/openbb_terminal/etf/discovery/disc_controller.py +++ b/openbb_terminal/etf/discovery/disc_controller.py @@ -29,29 +29,14 @@ class DiscoveryController(BaseController): "active", ] PATH = "/etf/disc/" + CHOICES_GENERATION = True def __init__(self, queue: List[str] = None): """Constructor""" super().__init__(queue) if session and obbff.USE_PROMPT_TOOLKIT: - choices: dict = {c: {} for c in self.controller_choices} - - choices["gainers"] = { - "--limit": None, - "-l": "--limit", - } - choices["decliners"] = { - "--limit": None, - "-l": "--limit", - } - choices["active"] = { - "--limit": None, - "-l": "--limit", - } - - choices["support"] = self.SUPPORT_CHOICES - choices["about"] = self.ABOUT_CHOICES + choices: dict = self.choices_default self.completer = NestedCompleter.from_nested_dict(choices) diff --git a/openbb_terminal/etf/etf_controller.py b/openbb_terminal/etf/etf_controller.py index 626d92ce1d3..a131e4ca428 100644 --- a/openbb_terminal/etf/etf_controller.py +++ b/openbb_terminal/etf/etf_controller.py @@ -28,7 +28,6 @@ from openbb_terminal.etf.technical_analysis import ta_controller from openbb_terminal.helper_funcs import ( EXPORT_BOTH_RAW_DATA_AND_FIGURES, EXPORT_ONLY_RAW_DATA_ALLOWED, - check_non_negative_float, check_positive, export_data, valid_date, @@ -37,7 +36,7 @@ from openbb_terminal.helper_funcs import ( ) from openbb_terminal.menu import session from openbb_terminal.parent_classes import BaseController -from openbb_terminal.rich_config import console, MenuText, get_ordered_list_sources +from openbb_terminal.rich_config import console, MenuText from openbb_terminal.stocks import stocks_helper from openbb_terminal.stocks.comparison_analysis import ca_controller @@ -82,6 +81,7 @@ class ETFController(BaseController): PATH = "/etf/" FILE_PATH = os.path.join(os.path.dirname(__file__), "README.md") + CHOICES_GENERATION = True def __init__(self, queue: List[str] = None): """Constructor""" @@ -93,58 +93,7 @@ class ETFController(BaseController): self.TRY_RELOAD = True if session and obbff.USE_PROMPT_TOOLKIT: - choices: dict = {c: {} for c in self.controller_choices} - one_to_hundred: dict = {str(c): {} for c in range(1, 100)} - choices["search"] = { - "--name": None, - "-n": "--name", - "--description": None, - "-d": "--description", - "--source": { - c: {} for c in get_ordered_list_sources(f"{self.PATH}search") - }, - "--limit": None, - "-l": "--limit", - } - choices["load"] = { - "--ticker": None, - "-t": "--ticker", - "--start": None, - "-s": "--start", - "--end": None, - "-e": "--end", - "--limit": None, - "-l": "--limit", - } - choices["weights"] = {"--min": one_to_hundred, "-m": "--min", "--raw": {}} - - choices["candle"] = { - "--sort": {c: {} for c in self.CANDLE_COLUMNS}, - "-s": "--sort", - "--plotly": {}, - "-p": "--plotly", - "--ma": None, - "--reverse": {}, - "-r": "--reverse", - "--trend": {}, - "-t": "--trend", - "--raw": {}, - "--num": one_to_hundred, - "-n": "--num", - } - choices["pir"] = { - "--etfs": None, - "-e": "--etfs", - "--filename": None, - "--folder": None, - } - choices["compare"] = { - "--etfs": None, - "-e": "--etfs", - } - - choices["support"] = self.SUPPORT_CHOICES - choices["about"] = self.ABOUT_CHOICES + choices: dict = self.choices_default self.completer = NestedCompleter.from_nested_dict(choices) @@ -372,9 +321,6 @@ class ETFController(BaseController): help="Number of holdings to get", default=10, ) - if not self.etf_name: - console.print("Please load a ticker using <load name>. \n") - return if other_args and "-" not in other_args[0][0]: other_args.insert(0, "-l") @@ -382,12 +328,15 @@ class ETFController(BaseController): parser, other_args, export_allowed=EXPORT_ONLY_RAW_DATA_ALLOWED ) if ns_parser: - stockanalysis_view.view_holdings( - symbol=self.etf_name, - limit=ns_parser.limit, - export=ns_parser.export, - ) - console.print() + if self.etf_name: + stockanalysis_view.view_holdings( + symbol=self.etf_name, + limit=ns_parser.limit, + export=ns_parser.export, + ) + console.print() + else: + console.print("Please load a ticker using <load name>. \n") @log_start_end(log=logger) def call_news(self, other_args: List[str]): @@ -498,19 +447,14 @@ class ETFController(BaseController): ), ) parser.add_argument( - "--raw", - action="store_true", - dest="raw", - default=False, - help="Shows raw data instead of chart", - ) - parser.add_argument( "-n", "--num", type=check_positive, help="Number to show if raw selected", dest="num", default=20, + choices=range(1, 100), + metavar="NUM", ) parser.add_argument( "-t", @@ -532,7 +476,10 @@ class ETFController(BaseController): ) ns_parser = self.parse_known_args_and_warn( - parser, other_args, EXPORT_BOTH_RAW_DATA_AND_FIGURES + parser, + other_args, + EXPORT_BOTH_RAW_DATA_AND_FIGURES, + raw=True, ) if ns_parser: if not self.etf_name: @@ -655,22 +602,21 @@ class ETFController(BaseController): parser.add_argument( "-m", "--min", - type=check_non_negative_float, + type=check_positive, dest="min", help="Minimum positive float to display sector", default=5, - ) - parser.add_argument( - "--raw", - action="store_true", - dest="raw", - help="Only output raw data", + choices=range(1, 100), + metavar="MIN", ) if other_args and "-" not in other_args[0][0]: other_args.insert(0, "-l") ns_parser = self.parse_known_args_and_warn( - parser, other_args, export_allowed=EXPORT_BOTH_RAW_DATA_AND_FIGURES + parser, + other_args, + export_allowed=EXPORT_BOTH_RAW_DATA_AND_FIGURES, + raw=True, ) if ns_parser: yfinance_view.display_etf_weightings( diff --git a/openbb_terminal/etf/screener/screener_controller.py b/openbb_terminal/etf/screener/screener_controller.py index 42480232603..8536bdf1420 100644 --- a/openbb_terminal/etf/screener/screener_controller.py +++ b/openbb_terminal/etf/screener/screener_controller.py @@ -33,7 +33,8 @@ class ScreenerController(BaseController): "sbc", ] - preset_choices = screener_model.get_preset_choices() + PRESET_CHOICES = screener_model.get_preset_choices() + ETF_CATEGORY_LIST = financedatabase_model.get_etfs_categories() sortby_screen_choices = [ "Assets", @@ -53,6 +54,7 @@ class ScreenerController(BaseController): ] PATH = "/etf/scr/" + CHOICES_GENERATION = True def __init__(self, queue: List[str] = None): """Constructor""" @@ -62,15 +64,10 @@ class ScreenerController(BaseController): self.screen_tickers: List = list() if session and obbff.USE_PROMPT_TOOLKIT: - choices: dict = {c: {} for c in self.controller_choices} - choices["view"] = {c: None for c in self.preset_choices} - choices["set"] = {c: None for c in self.preset_choices} - choices["sbc"] = { - c: None for c in financedatabase_model.get_etfs_categories() - } - - choices["support"] = self.SUPPORT_CHOICES - choices["about"] = self.ABOUT_CHOICES + choices: dict = self.choices_default + choices["view"].update({c: None for c in self.PRESET_CHOICES}) + choices["set"].update({c: None for c in self.PRESET_CHOICES}) + choices["sbc"].update({c: None for c in self.ETF_CATEGORY_LIST}) self.completer = NestedCompleter.from_nested_dict(choices) @@ -103,7 +100,7 @@ class ScreenerController(BaseController): type=str, help="View specific custom preset", default="", - choices=self.preset_choices, + choices=self.PRESET_CHOICES, ) if other_args and "-" not in other_args[0][0]: other_args.insert(0, "-p") @@ -112,7 +109,7 @@ class ScreenerController(BaseController): if ns_parser.preset: preset_filter = configparser.RawConfigParser() preset_filter.optionxform = str # type: ignore - preset_filter.read(self.preset_choices[ns_parser.preset]) + preset_filter.read(self.PRESET_CHOICES[ns_parser.preset]) headers = [ "Price", @@ -144,9 +141,9 @@ class ScreenerController(BaseController): else: console.print("\nPresets:") - for preset in self.preset_choices: + for preset in self.PRESET_CHOICES: with open( - self.preset_choices[preset], + self.PRESET_CHOICES[preset], encoding="utf8", ) as f: description = "" @@ -174,7 +171,7 @@ class ScreenerController(BaseController): type=str, default="template", help="Filter presets", - choices=self.preset_choices, + choices=self.PRESET_CHOICES, ) if other_args and "-" not in other_args[0][0]: other_args.insert(0, "-p") @@ -251,6 +248,8 @@ class ScreenerController(BaseController): nargs="+", help="Category to look for", required="-h" not in other_args, + choices=self.ETF_CATEGORY_LIST, + metavar="CATEGORY", ) parser.add_argument( "-l", @@ -269,7 +268,7 @@ class ScreenerController(BaseController): ) if ns_parser: category = " ".join(ns_parser.category) - if category in financedatabase_model.get_etfs_categories(): + if category in self.ETF_CATEGORY_LIST: financedatabase_view.display_etf_by_category( category=category, limit=ns_parser.limit, @@ -278,5 +277,5 @@ class ScreenerController(BaseController): else: console.print( "The category selected does not exist, choose one from:" - f" {', '.join(financedatabase_model.get_etfs_categories())}\n" + f" {', '.join(self.ETF_CATEGORY_LIST)}\n" ) diff --git a/openbb_terminal/etf/technical_analysis/ta_controller.py b/openbb_terminal/etf/technical_analysis/ta_controller.py index b05664f75b1..d97b0d8fbc1 100644 --- a/openbb_terminal/etf/technical_analysis/ta_controller.py +++ b/openbb_terminal/etf/technical_analysis/ta_controller.py @@ -27,6 +27,7 @@ from openbb_terminal.common.technical_analysis import ( from openbb_terminal.decorators import log_start_end from openbb_terminal.helper_funcs import ( EXPORT_BOTH_RAW_DATA_AND_FIGURES, + check_non_negative, check_positive, check_positive_list, valid_date, @@ -72,6 +73,7 @@ class TechnicalAnalysisController(BaseController): ] PATH = "/etf/ta/" + CHOICES_GENERATION = True def __init__( self, @@ -90,112 +92,6 @@ class TechnicalAnalysisController(BaseController): if session and obbff.USE_PROMPT_TOOLKIT: choices: dict = {c: {} for c in self.controller_choices} - one_to_hundred: dict = {str(c): {} for c in range(1, 100)} - zero_to_hundred: dict = {str(c): {} for c in range(0, 100)} - ma = { - "--length": None, - "-l": "--length", - "--offset": zero_to_hundred, - "-o": "--offset", - } - choices["ema"] = ma - choices["sma"] = ma - choices["wma"] = ma - choices["hma"] = ma - choices["zlma"] = ma - choices["vwap"] = { - "--offset": zero_to_hundred, - "-o": "--offset", - "--start": None, - "--end": None, - } - choices["cci"] = { - "--length": one_to_hundred, - "-l": "--length", - "--scalar": None, - "-s": "--scalar", - } - choices["macd"] = { - "--fast": one_to_hundred, - "--slow": "--fast", - "--signal": "--fast", - } - choices["cci"] = { - "--length": one_to_hundred, - "-l": "--length", - "--scalar": None, - "-s": "--scalar", - "--drift": "--length", - "-d": "--drift", - } - choices["stoch"] = { - "--fastkperiod": one_to_hundred, - "-k": "--fastkperiod", - "--slowdperiod": "--fastkperiod", - "-d": "--slowdperiod", - "--slowkperiod": "--fastkperiod", - } - choices["fisher"] = { - "--length": one_to_hundred, - "-l": "--length", - } - choices["cg"] = { - "--length": one_to_hundred, - "-l": "--length", - } - choices["adx"] = { - "--length": one_to_hundred, - "-l": "--length", - "--scalar": None, - "-s": "--scalar", - "--drift": "--length", - "-d": "--drift", - } - choices["aroon"] = { - "--length": one_to_hundred, - "-l": "--length", - "--scalar": None, - "-s": "--scalar", - } - choices["bbands"] = { - "--length": one_to_hundred, - "-l": "--length", - "--std": {str(c): {} for c in np.arange(0.0, 10, 0.25)}, - "-s": "--std", - "--mamode": {c: {} for c in volatility_model.MAMODES}, - "-m": "--mamode", - } - choices["donchian"] = { - "--length_upper": one_to_hundred, - "-u": "--length_upper", - "--length_lower": "--length_upper", - "-l": "--length_lower", - } - choices["kc"] = { - "--length": one_to_hundred, - "-l": "--length", - "--scalar": None, - "-s": "--scalar", - "--mamode": {c: {} for c in volatility_model.MAMODES}, - "-m": "--mamode", - "--offset": zero_to_hundred, - "-o": "--offset", - } - choices["ad"]["--open"] = {} - choices["adosc"] = { - "--open": {}, - "--fast": one_to_hundred, - "--slow": "--fast", - } - choices["fib"] = { - "--period": {str(c): {} for c in range(1, 960)}, - "--start": None, - "--end": None, - } - - choices["support"] = self.SUPPORT_CHOICES - choices["about"] = self.ABOUT_CHOICES - self.completer = NestedCompleter.from_nested_dict(choices) def print_help(self): @@ -273,9 +169,11 @@ class TechnicalAnalysisController(BaseController): "--offset", action="store", dest="n_offset", - type=int, + type=check_non_negative, default=0, help="offset", + choices=range(0, 100), + metavar="N_OFFSET", ) if other_args and "-" not in other_args[0][0]: @@ -325,9 +223,11 @@ class TechnicalAnalysisController(BaseController): "--offset", action="store", dest="n_offset", - type=int, + type=check_non_negative, default=0, help="offset", + choices=range(0, 100), + metavar="N_OFFSET", ) if other_args and "-" not in other_args[0][0]: @@ -374,9 +274,11 @@ class TechnicalAnalysisController(BaseController): "--offset", action="store", dest="n_offset", - type=int, + type=check_non_negative, default=0, help="offset", + choices=range(0, 100), + metavar="N_OFFSET", ) if other_args and "-" not in other_args[0][0]: @@ -423,9 +325,11 @ |