diff --git a/openbb_terminal/core/models/preferences_model.py b/openbb_terminal/core/models/preferences_model.py index 2f255cf9c25..4ec1fab0697 100644 --- a/openbb_terminal/core/models/preferences_model.py +++ b/openbb_terminal/core/models/preferences_model.py @@ -26,8 +26,8 @@ class PreferencesModel: # See more: https://matplotlib.org/stable/tutorials/introductory/usage.html#the-builtin-backends PLOT_BACKEND: Optional[str] = None PLOT_DPI: PositiveInt = 100 - PLOT_HEIGHT: PositiveInt = 500 - PLOT_WIDTH: PositiveInt = 800 + PLOT_HEIGHT: PositiveInt = 762 + PLOT_WIDTH: PositiveInt = 1400 PLOT_HEIGHT_PERCENTAGE: PositiveFloat = 50.0 PLOT_WIDTH_PERCENTAGE: PositiveFloat = 70.0 # Whether to open plot image exports after they are created diff --git a/openbb_terminal/core/plots/backend.py b/openbb_terminal/core/plots/backend.py index 25e09dbaaaa..3badbf83062 100644 --- a/openbb_terminal/core/plots/backend.py +++ b/openbb_terminal/core/plots/backend.py @@ -62,13 +62,18 @@ class Backend(pywry.PyWry): and not strtobool(os.environ.get("OPENBB_ENABLE_QUICK_EXIT", False)) and current_process().name == "MainProcess" ) + self.WIDTH, self.HEIGHT = 1400, 762 atexit.register(self.close) - def set_window_dimensions(self, width: int, height: int): + def set_window_dimensions(self): """Set the window dimensions.""" - self.WIDTH, self.HEIGHT = int(width) * 100, (int(height) * 100) + 62 + current_user = get_current_user() + width = current_user.preferences.PLOT_WIDTH or 1400 + height = current_user.preferences.PLOT_HEIGHT or 762 + + self.WIDTH, self.HEIGHT = int(width), int(height) def inject_path_to_html(self): """Update the script tag in html with local path.""" @@ -100,6 +105,7 @@ class Backend(pywry.PyWry): def get_plotly_html(self) -> str: """Get the plotly html file.""" + self.set_window_dimensions() if not self.plotly_html.exists(): self.inject_path_to_html() return self.get_plotly_html() @@ -108,6 +114,7 @@ class Backend(pywry.PyWry): def get_table_html(self) -> str: """Get the table html file.""" + self.set_window_dimensions() if self.table_html.exists(): return str(self.table_html) console.print( diff --git a/openbb_terminal/economy/economy_controller.py b/openbb_terminal/economy/economy_controller.py index 533cecdd0e0..956c1e52b57 100644 --- a/openbb_terminal/economy/economy_controller.py +++ b/openbb_terminal/economy/economy_controller.py @@ -894,7 +894,11 @@ class EconomyController(BaseController): return self.queue if indices: - for i, index in enumerate(indices): + # We create a list of dataframes and a list of columns + # We then concatenate the dataframes and set the columns + dfs_indices, columns = [], [] + + for index in indices: df = yfinance_model.get_index( index, interval=ns_parser.interval, @@ -902,6 +906,7 @@ class EconomyController(BaseController): end_date=ns_parser.end_date, column=ns_parser.column, ) + dfs_indices.append(df) if not df.empty: self.DATASETS["index"][index] = df @@ -909,26 +914,42 @@ class EconomyController(BaseController): self.stored_datasets = ( economy_helpers.update_stored_datasets_string(self.DATASETS) ) + columns.append(index) - # display only once in the last iteration - if i == len(indices) - 1: - yfinance_view.show_indices( - indices=indices, - interval=ns_parser.interval, - start_date=ns_parser.start_date, - end_date=ns_parser.end_date, - column=ns_parser.column, - raw=ns_parser.raw, - export=ns_parser.export, - sheet_name=" ".join(ns_parser.sheet_name) - if ns_parser.sheet_name - else None, - returns=ns_parser.returns, - ) + # If no data is found, we print a message and return + if not dfs_indices: + text = "Indices" if len(indices) > 1 else "Index" + console.print(f"[red]No data found for the given {text}[/red]") + return self.queue - self.update_runtime_choices() - if get_current_user().preferences.ENABLE_EXIT_AUTO_HELP: - self.print_help() + # We concatenate the dataframes here to avoid having + # to regrab the data in the view + indices_data = pd.concat(dfs_indices, axis=1) + indices_data.columns = columns + + # If returns are requested, we calculate them here as well + if ns_parser.returns: + indices_data = indices_data.pct_change().dropna() + indices_data = indices_data + 1 + indices_data = indices_data.cumprod() + + yfinance_view.show_indices( + indices=indices_data, + interval=ns_parser.interval, + start_date=ns_parser.start_date, + end_date=ns_parser.end_date, + column=ns_parser.column, + raw=ns_parser.raw, + export=ns_parser.export, + sheet_name=" ".join(ns_parser.sheet_name) + if ns_parser.sheet_name + else None, + returns=ns_parser.returns, + ) + + self.update_runtime_choices() + if get_current_user().preferences.ENABLE_EXIT_AUTO_HELP: + self.print_help() @log_start_end(log=logger) def call_treasury(self, other_args: List[str]): diff --git a/openbb_terminal/economy/yfinance_view.py b/openbb_terminal/economy/yfinance_view.py index f4bf4d4da06..fdaaae35fca 100644 --- a/openbb_terminal/economy/yfinance_view.py +++ b/openbb_terminal/economy/yfinance_view.py @@ -16,13 +16,14 @@ from openbb_terminal.economy.yfinance_model import ( get_search_indices, ) from openbb_terminal.helper_funcs import export_data, print_rich_table, reindex_dates +from openbb_terminal.rich_config import console logger = logging.getLogger(__name__) @log_start_end(log=logger) def show_indices( - indices: list, + indices: Union[list, pd.DataFrame], interval: str = "1d", start_date: Optional[int] = None, end_date: Optional[int] = None, @@ -37,8 +38,8 @@ def show_indices( """Load (and show) the selected indices over time [Source: Yahoo Finance] Parameters ---------- - indices: list - A list of indices you wish to load (and plot). + indices: Union[list, pd.DataFrame] + A list of indices to load in, or a DataFrame with indices as columns (to plot) Available indices can be accessed through economy.available_indices(). interval: str Valid intervals: 1m,2m,5m,15m,30m,60m,90m,1h,1d,5d,1wk,1mo,3mo @@ -61,8 +62,17 @@ def show_indices( ------- Plots the Series. """ - - indices_data = get_indices(indices, interval, start_date, end_date, column, returns) + if isinstance(indices, list): + indices_data = get_indices( + indices, interval, start_date, end_date, column, returns + ) + elif isinstance(indices, pd.DataFrame): + indices_data = indices + indices = indices_data.columns + else: + return console.print( + "Indices must be a list or a DataFrame with indices values as columns (column names = indices)" + ) fig = OpenBBFigure(title="Indices") @@ -96,6 +106,7 @@ def show_indices( if len(indices) < 2: fig.update_layout(title=f"{' - '.join(new_title)}", yaxis=dict(side="right")) + fig.show(external=external_axes) if raw: @@ -121,7 +132,7 @@ def show_indices( ) if (output := indices_data) is not None and external_axes: - output = (indices_data, fig.show(external_axes=external_axes)) + output = (indices_data, fig.show(external=external_axes)) return output diff --git a/openbb_terminal/helper_funcs.py b/openbb_terminal/helper_funcs.py index a911e43e1c2..c0dcf9e5c79 100644 --- a/openbb_terminal/helper_funcs.py +++ b/openbb_terminal/helper_funcs.py @@ -1260,9 +1260,6 @@ def plot_autoscale(): return x, y -plots_backend().set_window_dimensions(*plot_autoscale()) - - def get_last_time_market_was_open(dt): """Get last time the US market was open.""" # Check if it is a weekend diff --git a/tests/openbb_terminal/economy/test_economy_controller.py b/tests/openbb_terminal/economy/test_economy_controller.py index 930d8734bbd..1d61f2963bc 100644 --- a/tests/openbb_terminal/economy/test_economy_controller.py +++ b/tests/openbb_terminal/economy/test_economy_controller.py @@ -983,19 +983,7 @@ def test_call_index(mocker): controller.choices = {} controller.call_index(["-i", "SP500,DOW_DJUS", "-s", "2022-10-01"]) - mock.assert_called_once_with( - **dict( - indices=["SP500", "DOW_DJUS"], - start_date="2022-10-01", - end_date=None, - raw=False, - export="", - sheet_name=None, - interval="1d", - column="Adj Close", - returns=False, - ) - ) + mock.assert_called_once() MOCK_TREASURY_DEFAULT = pd.DataFrame.from_dict(