diff --git a/.github/workflows/unit-test.yml b/.github/workflows/unit-test.yml index 07f1885e435..664f017a64b 100644 --- a/.github/workflows/unit-test.yml +++ b/.github/workflows/unit-test.yml @@ -35,7 +35,7 @@ jobs: check-changes: ${{ steps.check-changes.outputs.check-changes }} steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v1 # v1 is used to preserve the git history and works with the git diff command with: fetch-depth: 100 # The GitHub token is preserved by default but this job doesn't need @@ -46,20 +46,16 @@ jobs: - name: Check for changes to files to trigger unit test id: check-changes run: | - source_branch=$(jq -r .pull_request.head.ref "$GITHUB_EVENT_PATH") - target_branch=$(jq -r .pull_request.base.ref "$GITHUB_EVENT_PATH") + current_branch=$(jq -r .pull_request.base.ref "$GITHUB_EVENT_PATH") - if git diff --name-only origin/$target_branch HEAD | grep -E ".py$|openbb_terminal\/.*|pyproject.toml|poetry.lock|requirements.txt|requirements-full.txt"; then + if git diff --name-only origin/$current_branch HEAD | grep -E ".py$|openbb_terminal\/.*|pyproject.toml|poetry.lock|requirements.txt|requirements-full.txt"; then echo "check-changes=true" >> $GITHUB_OUTPUT else echo "check-changes=false" >> $GITHUB_OUTPUT fi - name: Show output of previous step - run: | - # echo "python-changes=${{ steps.python-changes.outputs.python-changes }}" - # echo "folder-changes=${{ steps.folder-changes.outputs.folder-changes }}" - echo "check-changes=${{ steps.check-changes.outputs.check-changes }}" + run: echo "check-changes=${{ steps.check-changes.outputs.check-changes }}" base-test: name: Base Tests - Ubuntu-latest - Python 3.9 diff --git a/openbb_terminal/portfolio/attribution_model.py b/openbb_terminal/portfolio/attribution_model.py index 639b25672cb..8e91bb859bb 100644 --- a/openbb_terminal/portfolio/attribution_model.py +++ b/openbb_terminal/portfolio/attribution_model.py @@ -9,23 +9,23 @@ import pandas as pd import yfinance as yf from openbb_terminal.decorators import log_start_end -from openbb_terminal.rich_config import console +from openbb_terminal.etf import fmp_model logger = logging.getLogger(__name__) SPY_SECTORS_MAP = { - "S&P 500 Materials (Sector)": "basic_materials", - "S&P 500 Industrials (Sector)": "industrials", - "S&P 500 Consumer Discretionary (Sector)": "consumer_cyclical", - "S&P 500 Consumer Staples (Sector)": "consumer_defensive", - "S&P 500 Health Care (Sector)": "healthcare", - "S&P 500 Financials (Sector)": "financial_services", - "S&P 500 Information Technology (Sector)": "technology", - "S&P 500 Telecommunication Services (Sector)": "communication_services", - "S&P 500 Utilities (Sector)": "utilities", - "S&P 500 Real Estate (Sector)": "realestate", - "S&P 500 Energy (Sector)": "energy", + "S&P 500 Materials (Sector)": "Basic Materials", + "S&P 500 Industrials (Sector)": "Industrials", + "S&P 500 Consumer Discretionary (Sector)": "Consumer Cyclical", + "S&P 500 Consumer Staples (Sector)": "Consumer Defensive", + "S&P 500 Health Care (Sector)": "Healthcare", + "S&P 500 Financials (Sector)": "Financial Services", + "S&P 500 Information Technology (Sector)": "Technology", + "S&P 500 Telecommunication Services (Sector)": "Communication Services", + "S&P 500 Utilities (Sector)": "Utilities", + "S&P 500 Real Estate (Sector)": "Real Estate", + "S&P 500 Energy (Sector)": "Energy", } PF_SECTORS_MAP = { @@ -64,23 +64,18 @@ def get_spy_sector_contributions( """ # Sector Map - sectors_ticker = "SPY" # Load in info sp500_tickers_data = get_daily_sector_prices(start_date, end_date) - try: - weight_data = yf.Ticker(sectors_ticker).info["sectorWeightings"] - except Exception as _: # noqa - console.print( - "[red]This functionality is currently unstable and will be removed in the near future." - ) - return pd.DataFrame() + weight_data = fmp_model.get_etf_sector_weightings(sectors_ticker) # reformat Data weights: Dict[str, dict] = {"SPY": {}} + for sector in weight_data: - weights[sectors_ticker].update(sector) + weight_formatted = float(sector["weightPercentage"].strip("%")) / 100 + weights[sectors_ticker][sector["sector"]] = weight_formatted # add the sectors + dates + adj close to the dataframe records = [] diff --git a/openbb_terminal/portfolio/portfolio_controller.py b/openbb_terminal/portfolio/portfolio_controller.py index 57c4de75dce..4525e608331 100644 --- a/openbb_terminal/portfolio/portfolio_controller.py +++ b/openbb_terminal/portfolio/portfolio_controller.py @@ -206,7 +206,7 @@ class PortfolioController(BaseController): mt.add_info("_risk_") mt.add_cmd("var", self.portfolio_name and self.benchmark_name) mt.add_cmd("es", self.portfolio_name and self.benchmark_name) - mt.add_cmd("os", self.portfolio_name and self.benchmark_name) + mt.add_cmd("om", self.portfolio_name and self.benchmark_name) console.print(text=mt.menu_text, menu="Portfolio - Portfolio Optimization") self.update_choices() @@ -894,7 +894,7 @@ class PortfolioController(BaseController): ) else: console.print( - "[red]Please first define the portfolio (via 'load')[/red]\n" + "[red]Please define the portfolio first (via 'load')[/red]\n" ) @log_start_end(log=logger) diff --git a/openbb_terminal/reports/reports_model.py b/openbb_terminal/reports/reports_model.py index 8e6aad76b6d..602cabef263 100644 --- a/openbb_terminal/reports/reports_model.py +++ b/openbb_terminal/reports/reports_model.py @@ -282,7 +282,7 @@ def create_output_path(input_path: str, parameters_dict: Dict[str, Any]) -> str: + "_" + f"{report_name}{args_to_output}" ) - output_path = report_output_name.replace(".", "_") + report_output_name = report_output_name.replace(".", "_") output_path = str(USER_REPORTS_DIRECTORY / report_output_name) return output_path diff --git a/openbb_terminal/sdk_core/trailmap.py b/openbb_terminal/sdk_core/trailmap.py index 364c9daa462..1fc0724d2f8 100644 --- a/openbb_terminal/sdk_core/trailmap.py +++ b/openbb_terminal/sdk_core/trailmap.py @@ -115,7 +115,7 @@ class FuncAttr: trail = ".".join([t for t in location_path if t != ""]) sdk_name = class_attr if not view else f"{class_attr}_chart" - trail = trail.lstrip("root.") # pylint: disable=E1310 + trail = trail.replace("root.", "") sdk_path = f"{f'openbb.{trail}' if trail else 'openbb'}.{sdk_name}" return f"{sdk_path}({definition })" diff --git a/openbb_terminal/stocks/sector_industry_analysis/financedatabase_model.py b/openbb_terminal/stocks/sector_industry_analysis/financedatabase_model.py index 0ecc16fd395..be428d59927 100644 --- a/openbb_terminal/stocks/sector_industry_analysis/financedatabase_model.py +++ b/openbb_terminal/stocks/sector_industry_analysis/financedatabase_model.py @@ -6,7 +6,7 @@ import logging from typing import Optional import financedatabase as fd -import yfinance as yf +import yahooquery as yq from requests.exceptions import ReadTimeout from tqdm import tqdm @@ -179,22 +179,12 @@ def get_json(symbol: str) -> dict: Dictionary of json data """ - data_stores = yf.data.TickerData(symbol).get_json_data_stores() - - if "QuoteSummaryStore" not in data_stores: - # Problem in data. Either delisted, or Yahoo spam triggered - return {} - - data = data_stores["QuoteSummaryStore"] - # add data about Shares Outstanding for companies' tickers if they are available + data = dict() try: - data["annualBasicAverageShares"] = data_stores["QuoteTimeSeriesStore"][ - "timeSeries" - ]["annualBasicAverageShares"] + data["summaryProfile"] = yq.Ticker(symbol).summary_profile[symbol] + return data except Exception: - pass - - return data + return data @log_start_end(log=logger) diff --git a/openbb_terminal/stocks/stocks_controller.py b/openbb_terminal/stocks/stocks_controller.py index 99642b1e2bb..dd2bfc10f7c 100644 --- a/openbb_terminal/stocks/stocks_controller.py +++ b/openbb_terminal/stocks/stocks_controller.py @@ -264,7 +264,8 @@ class StocksController(StockBaseController): "--ticker", action="store", dest="s_ticker", - required="-h" not in other_args and not self.ticker, + required=not any(x in other_args for x in ["-h", "--help"]) + and not self.ticker, help="Ticker to get data for", ) parser.add_argument( @@ -363,7 +364,8 @@ class StocksController(StockBaseController): help="Ticker to analyze", type=str, default=None, - required="-h" not in other_args and not self.ticker, + required=not any(x in other_args for x in ["-h", "--help"]) + and not self.ticker, ) parser.add_argument( "-p", @@ -495,7 +497,8 @@ class StocksController(StockBaseController): "--ticker", action="store", dest="ticker", - required="-h" not in other_args and not self.ticker, + required=not any(x in other_args for x in ["-h", "--help"]) + and not self.ticker, help="Ticker to get data for", ) parser.add_argument( diff --git a/poetry.lock b/poetry.lock index 3d364ce283d..278c65d002f 100644 --- a/poetry.lock +++ b/poetry.lock @@ -6467,6 +6467,21 @@ urllib3 = ">=1.21.1,<1.27" socks = ["PySocks (>=1.5.6,!=1.5.7)"] use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] +[[package]] +name = "requests-futures" +version = "1.0.0" +description = "Asynchronous Python HTTP for Humans." +category = "main" +optional = false +python-versions = "*" +files = [ + {file = "requests-futures-1.0.0.tar.gz", hash = "sha256:35547502bf1958044716a03a2f47092a89efe8f9789ab0c4c528d9c9c30bc148"}, + {file = "requests_futures-1.0.0-py2.py3-none-any.whl", hash = "sha256:633804c773b960cef009efe2a5585483443c6eac3c39cc64beba2884013bcdd9"}, +] + +[package.dependencies] +requests = ">=1.2.0" + [[package]] name = "requests-oauthlib" version = "1.3.1" @@ -8691,6 +8706,29 @@ files = [ {file = "y_py-0.5.4.tar.gz", hash = "sha256:1ee01dc64427308ccf13ffb6b7fecb9cd27594b76a3c2ff19a23cb33474b1318"}, ] +[[package]] +name = "yahooquery" +version = "2.3.0" +description = "Python interface to unofficial Yahoo Finance API endpoints" +category = "main" +optional = false +python-versions = "*" +files = [ + {file = "yahooquery-2.3.0-py2.py3-none-any.whl", hash = "sha256:760c885da53ca25104000291c58fe53fe3df4b832ea424c32f8c429d2825e911"}, + {file = "yahooquery-2.3.0.tar.gz", hash = "sha256:c51aee71ab90de52d1fa7e1288bc466f5ea0dfb6ac20f2c62c9dde461985f63b"}, +] + +[package.dependencies] +lxml = ">=4.9.1" +pandas = ">=0.24.0" +requests-futures = ">=1.0.0" +tqdm = ">=4.54.1" + +[package.extras] +doc = ["mkdocs (>=1.1.2,<2.0.0)", "mkdocs-jupyter (>=0.12.0,<0.13.0)", "mkdocs-material (>=6.1.7,<7.0.0)"] +premium = ["selenium (>=3.141.0)"] +test = ["coverage (==5.2.1)", "pytest (==6.0.2)", "pytest-cov (==2.10.1)", "selenium (>=3.141.0)"] + [[package]] name = "yarl" version = "1.8.2" @@ -8885,4 +8923,4 @@ optimization = ["Riskfolio-Lib"] [metadata] lock-version = "2.0" python-versions = "^3.8,<3.11, !=3.9.7" -content-hash = "8a7372187c8ee5d9012fa0a65109fe3cfc71ca8f0159c5efd65df4415f5ac229" +content-hash = "ecb2e6b98d259e95edb86faaeed404755d6f60146607891de7e4ea30f54f6e76" diff --git a/pyproject.toml b/pyproject.toml index 72c27bcb6c7..4ebfbba72d8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -112,6 +112,7 @@ y-py = "!=0.5.5" # Untraceable third level dependency that requires cargo to be psutil = "!=5.9.4" # Forecasting menu and IPyKernel dependency broken on MacOs tenacity = "<8.0.0" # Finviz, papermill and plotly dep. Pinned to avoid pip resolution conflict due to finviz 1.4.5 release bug intrinio-sdk = "^6.22.2" +yahooquery = "^2.3.0" [tool.poetry.dev-dependencies] pytest = "^6.2.2" diff --git a/requirements-full.txt b/requirements-full.txt index 03492bf0522..30599b500dc 100644 --- a/requirements-full.txt +++ b/requirements-full.txt @@ -260,6 +260,7 @@ quandl==3.7.0 ; python_version >= "3.8" and python_full_version != "3.9.7" and p rapidfuzz==2.13.7 ; python_version >= "3.8" and python_full_version != "3.9.7" and python_version < "3.11" rdflib==6.2.0 ; python_version >= "3.8" and python_full_version != "3.9.7" and python_version < "3.11" regex==2022.10.31 ; python_version >= "3.8" and python_full_version != "3.9.7" and python_version < "3.11" +requests-futures==1.0.0 ; python_version >= "3.8" and python_full_version != "3.9.7" and python_version < "3.11" requests-oauthlib==1.3.1 ; python_version >= "3.8" and python_full_version != "3.9.7" and python_version < "3.11" requests==2.28.2 ; python_version >= "3.8" and python_version < "3.11" and python_full_version != "3.9.7" retrying==1.3.4 ; python_version >= "3.8" and python_full_version != "3.9.7" and python_version < "3.11" @@ -359,6 +360,7 @@ xarray==2023.1.0 ; python_version >= "3.8" and python_full_version != "3.9.7" an xgboost==1.7.3 ; python_version >= "3.8" and python_full_version != "3.9.7" and python_version < "3.11" xlsxwriter==3.0.8 ; python_version >= "3.8" and python_full_version != "3.9.7" and python_version < "3.11" y-py==0.5.4 ; python_version >= "3.8" and python_full_version != "3.9.7" and python_version < "3.11" +yahooquery==2.3.0 ; python_version >= "3.8" and python_full_version != "3.9.7" and python_version < "3.11" yarl==1.8.2 ; python_version >= "3.8" and python_full_version != "3.9.7" and python_version < "3.11" yfinance==0.2.12 ; python_version >= "3.8" and python_full_version != "3.9.7" and python_version < "3.11" zipp==3.13.0 ; python_full_version != "3.9.7" and python_version < "3.11" and python_version >= "3.8" diff --git a/requirements.txt b/requirements.txt index ec5ace17ed5..a51e7c3342d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -187,6 +187,7 @@ quandl==3.7.0 ; python_version >= "3.8" and python_full_version != "3.9.7" and p rapidfuzz==2.13.7 ; python_version >= "3.8" and python_full_version != "3.9.7" and python_version < "3.11" rdflib==6.2.0 ; python_version >= "3.8" and python_full_version != "3.9.7" and python_version < "3.11" regex==2022.10.31 ; python_version >= "3.8" and python_full_version != "3.9.7" and python_version < "3.11" +requests-futures==1.0.0 ; python_version >= "3.8" and python_full_version != "3.9.7" and python_version < "3.11" requests-oauthlib==1.3.1 ; python_version >= "3.8" and python_full_version != "3.9.7" and python_version < "3.11" requests==2.28.2 ; python_version >= "3.8" and python_version < "3.11" and python_full_version != "3.9.7" retrying==1.3.4 ; python_version >= "3.8" and python_full_version != "3.9.7" and python_version < "3.11" @@ -248,6 +249,7 @@ widgetsnbextension==4.0.5 ; python_version >= "3.8" and python_full_version != " win32-setctime==1.1.0 ; python_version >= "3.8" and python_full_version != "3.9.7" and python_version < "3.11" and sys_platform == "win32" wrapt==1.14.1 ; python_version >= "3.8" and python_version < "3.11" and python_full_version != "3.9.7" y-py==0.5.4 ; python_version >= "3.8" and python_full_version != "3.9.7" and python_version < "3.11" +yahooquery==2.3.0 ; python_version >= "3.8" and python_full_version != "3.9.7" and python_version < "3.11" yarl==1.8.2 ; python_version >= "3.8" and python_full_version != "3.9.7" and python_version < "3.11" yfinance==0.2.12 ; python_version >= "3.8" and python_full_version != "3.9.7" and python_version < "3.11" zipp==3.13.0 ; python_version >= "3.8" and python_full_version != "3.9.7" and python_version < "3.11" diff --git a/tests/openbb_terminal/portfolio/txt/test_portfolio_controller/test_print_help.txt b/tests/openbb_terminal/portfolio/txt/test_portfolio_controller/test_print_help.txt index f5411fe0905..1476f1b9dfc 100644 --- a/tests/openbb_terminal/portfolio/txt/test_portfolio_controller/test_print_help.txt +++ b/tests/openbb_terminal/portfolio/txt/test_portfolio_controller/test_print_help.txt @@ -30,5 +30,5 @@ Metrics: Risk Metrics: [unvl] var display value at risk[/unvl] [unvl] es display expected shortfall[/unvl] -[unvl] os portfolio/os[/unvl] +[unvl] om display omega ratio[/unvl]