From 0c89fcd8f74764599c8a524f938f3f38ce757fd9 Mon Sep 17 00:00:00 2001 From: ValueRaider Date: Tue, 19 Nov 2024 21:41:42 +0000 Subject: [PATCH 1/7] Version 0.2.50 --- CHANGELOG.rst | 9 +++++++++ meta.yaml | 2 +- yfinance/version.py | 2 +- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 56cc0234..d44aa13a 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,6 +1,15 @@ Change Log =========== +0.2.50 +------ +Fixes: +- price repair #2111 #2139 +- download() appearance 2109 +- isin() error #2099 +- growth_estimates #2127 +Also new docs #2132 + 0.2.49 ------ Fix prices-clean rarely discarding good data #2122 diff --git a/meta.yaml b/meta.yaml index 444528f9..aaea9148 100644 --- a/meta.yaml +++ b/meta.yaml @@ -1,5 +1,5 @@ {% set name = "yfinance" %} -{% set version = "0.2.49" %} +{% set version = "0.2.50" %} package: name: "{{ name|lower }}" diff --git a/yfinance/version.py b/yfinance/version.py index 76144501..756b7abb 100644 --- a/yfinance/version.py +++ b/yfinance/version.py @@ -1 +1 @@ -version = "0.2.49" +version = "0.2.50" From 1c834acc6388987d0cbeee29ce842a2a9063b807 Mon Sep 17 00:00:00 2001 From: R5dan Date: Sun, 8 Dec 2024 19:45:59 +0000 Subject: [PATCH 2/7] Add market summary --- yfinance/summary.py | 116 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 116 insertions(+) create mode 100644 yfinance/summary.py diff --git a/yfinance/summary.py b/yfinance/summary.py new file mode 100644 index 00000000..e9eba79c --- /dev/null +++ b/yfinance/summary.py @@ -0,0 +1,116 @@ +import json as _json +import time + +from . import utils +from .const import _QUERY1_URL_ +from .data import YfData + +class MarketSummary: + def __init__(self, data) -> None: + # Basic information + self.name: 'str' = data.get("shortName") + self.region: 'str' = data.get("region") + self.market: 'str' = data.get("market") + self.quote_type: 'str' = data.get("quoteType") + self.type_display: 'str' = data.get("typeDisp") + self.symbol: 'str' = data.get("symbol") + + # Market data + self.price: 'float' = data.get("regularMarketPrice") + self.change: 'float' = data.get("regularMarketChange") + self.change_percent: 'float' = data.get("regularMarketChangePercent") + self.previous_close: 'float' = data.get("regularMarketPreviousClose") + self.market_time: 'int' = data.get("regularMarketTime") + self.market_state: 'str' = data.get("marketState") + self.price_hint: 'int' = data.get("priceHint") + + # Exchange information + self.exchange: 'str' = data.get("exchange") + self.full_exchange_name: 'str' = data.get("fullExchangeName") + self.timezone: 'str' = data.get("exchangeTimezoneName") + self.timezone_short: 'str' = data.get("exchangeTimezoneShortName") + self.gmt_offset: 'int' = data.get("gmtOffSetMilliseconds") + self.exchange_delay: 'int' = data.get("exchangeDataDelayedBy") + + # Quote information + self.quote_source: 'str' = data.get("quoteSourceName") + self.source_interval: 'int' = data.get("sourceInterval") + + # Trading properties + self.triggerable: 'bool' = data.get("triggerable") + self.tradeable: 'bool' = data.get("tradeable") + self.crypto_tradeable: 'bool' = data.get("cryptoTradeable") + self.has_pre_post_market: 'bool' = data.get("hasPrePostMarketData") + self.first_trade_date: 'int' = data.get("firstTradeDateMilliseconds") + + # Additional properties + self.esg_populated: 'bool' = data.get("esgPopulated") + self.price_alert_confidence: 'str' = data.get("customPriceAlertConfidence") + + + +class Summary: + def __init__(self, market, region="US", session=None, proxy=None, timeout=30, raise_errors=True, refresh=3600): + """ + market: The market area you want to get the summary for. + region: Can only be US + refresh: The number of seconds to wait before refreshing the data. + """ + self.market = market + self.region = region + + self.session = session + self.proxy = proxy + self.timeout = timeout + self.raise_errors = raise_errors + + self.refresh = refresh + + self._data = YfData(session=session) + self._logger = utils.get_yf_logger() + self._last_refresh = 0 + self._last_data = [] + + def _request(self, formatted=False, fields=["shortName", "regularMarketPrice", "regularMarketChange", "regularMarketChangePercent"]): + url = f"{_QUERY1_URL_}/v6/finance/quote/marketSummary" + params = { + "fields": fields, + "formatted": formatted, + "lang": "en-US", + "market": self.market, + "region": self.region + } + + self._logger.debug(f'{self.market}: Yahoo GET parameters: {str(dict(params))}') + + data = self._data.cache_get(url=url, params=params, proxy=self.proxy, timeout=self.timeout) + if data is None or "Will be right back" in data.text: + raise RuntimeError("*** YAHOO! FINANCE IS CURRENTLY DOWN! ***\n" + "Our engineers are working quickly to resolve " + "the issue. Thank you for your patience.") + try: + data = data.json() + except _json.JSONDecodeError: + self._logger.error(f"{self.market}: Failed to retrieve the market summary and received faulty response instead.") + data = {} + + return data + + def refresh_data(self, formatted=False, fields=["shortName", "regularMarketPrice", "regularMarketChange", "regularMarketChangePercent"], force=False): + if force or time.time() - self._last_refresh > self.refresh: + # As the data is very unlikely to change, we can cache it for a long time. + self._last_refresh = time.time() + self._last_request = self._request(formatted=formatted, fields=fields)["marketSummaryResponse"] + self._convert_data() + + return self._last_request + + def _convert_data(self): + self._last_data = [MarketSummary(data) for data in self._last_request["results"]] + + def __getitem__(self, name: str) -> 'MarketSummary': + self.refresh_data() + for data in self._last_data: + if data.name == name: + return data + raise AttributeError(f"{name} not found") From eabc6904cb54ce05f59be2ae9f928fcccaf67628 Mon Sep 17 00:00:00 2001 From: R5dan Date: Sun, 8 Dec 2024 19:47:32 +0000 Subject: [PATCH 3/7] Add MarketSummary to `__init__` --- yfinance/__init__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/yfinance/__init__.py b/yfinance/__init__.py index 7a825558..99fe5ae7 100644 --- a/yfinance/__init__.py +++ b/yfinance/__init__.py @@ -29,6 +29,7 @@ from .domain.industry import Industry from .screener.screener import Screener from .screener.screener_query import EquityQuery +from .summary import MarketSummary __version__ = version.version __author__ = "Ran Aroussi" @@ -37,4 +38,4 @@ warnings.filterwarnings('default', category=DeprecationWarning, module='^yfinance') __all__ = ['download', 'Ticker', 'Tickers', 'enable_debug_mode', 'set_tz_cache_location', 'Sector', 'Industry', - 'EquityQuery','Screener'] + 'EquityQuery','Screener', 'MarketSummary'] From 31da3da818e1452e182fdffc1e957f5b1725bfd4 Mon Sep 17 00:00:00 2001 From: R5dan Date: Sun, 8 Dec 2024 20:02:26 +0000 Subject: [PATCH 4/7] Change Summary names to export the correct one --- yfinance/summary.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/yfinance/summary.py b/yfinance/summary.py index e9eba79c..126c9cb2 100644 --- a/yfinance/summary.py +++ b/yfinance/summary.py @@ -5,7 +5,7 @@ from .const import _QUERY1_URL_ from .data import YfData -class MarketSummary: +class Summary: def __init__(self, data) -> None: # Basic information self.name: 'str' = data.get("shortName") @@ -49,7 +49,7 @@ def __init__(self, data) -> None: -class Summary: +class MarketSummary: def __init__(self, market, region="US", session=None, proxy=None, timeout=30, raise_errors=True, refresh=3600): """ market: The market area you want to get the summary for. From b9139d10f6c1059b9f44d1ecef7109bc6c294d1a Mon Sep 17 00:00:00 2001 From: R5dan Date: Sun, 8 Dec 2024 20:02:26 +0000 Subject: [PATCH 5/7] Change Summary names to export the correct one --- yfinance/summary.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/yfinance/summary.py b/yfinance/summary.py index e9eba79c..b470f38c 100644 --- a/yfinance/summary.py +++ b/yfinance/summary.py @@ -5,7 +5,7 @@ from .const import _QUERY1_URL_ from .data import YfData -class MarketSummary: +class Summary: def __init__(self, data) -> None: # Basic information self.name: 'str' = data.get("shortName") @@ -49,7 +49,7 @@ def __init__(self, data) -> None: -class Summary: +class MarketSummary: def __init__(self, market, region="US", session=None, proxy=None, timeout=30, raise_errors=True, refresh=3600): """ market: The market area you want to get the summary for. @@ -106,9 +106,9 @@ def refresh_data(self, formatted=False, fields=["shortName", "regularMarketPrice return self._last_request def _convert_data(self): - self._last_data = [MarketSummary(data) for data in self._last_request["results"]] + self._last_data = [Summary(data) for data in self._last_request["results"]] - def __getitem__(self, name: str) -> 'MarketSummary': + def __getitem__(self, name: str) -> 'Summary': self.refresh_data() for data in self._last_data: if data.name == name: From 539dbeda4217050c98eea37684031284637e537d Mon Sep 17 00:00:00 2001 From: R5dan Date: Sun, 8 Dec 2024 20:23:47 +0000 Subject: [PATCH 6/7] Docs --- .../reference/examples/market_summary.py | 43 +++++++++++++++++++ doc/source/reference/index.rst | 2 + .../reference/yfinance.market_status.rst | 22 ++++++++++ 3 files changed, 67 insertions(+) create mode 100644 doc/source/reference/examples/market_summary.py create mode 100644 doc/source/reference/yfinance.market_status.rst diff --git a/doc/source/reference/examples/market_summary.py b/doc/source/reference/examples/market_summary.py new file mode 100644 index 00000000..701b622e --- /dev/null +++ b/doc/source/reference/examples/market_summary.py @@ -0,0 +1,43 @@ +import yfinance as yf +europe = yf.MarketSummary("EUROPE") + +par = europe["^N100"] + +par.name +par.region +par.market +par.quote_type +par.type_display +par.symbol + +# Market data +par.price +par.change +par.change_percent +par.previous_close +par.market_time +par.market_state +par.price_hint + +# Exchange information +par.exchange +par.full_exchange_name +par.timezone +par.timezone_short +par.gmt_offset +par.exchange_delay + +# Quote information +par.quote_source +par.source_interval + +# Trading properties +par.triggerable +par.tradeable +par.crypto_tradeable +par.has_pre_post_market +par.first_trade_date + +# Additional properties +par.esg_populated +par.price_alert_confidence \ No newline at end of file diff --git a/doc/source/reference/index.rst b/doc/source/reference/index.rst index f1807da2..31da4cff 100644 --- a/doc/source/reference/index.rst +++ b/doc/source/reference/index.rst @@ -15,6 +15,7 @@ The following are the publicly available classes, and functions exposed by the ` - :attr:`Ticker `: Class for accessing single ticker data. - :attr:`Tickers `: Class for handling multiple tickers. +- :attr:`MarketSummary `: Class for accessing market summary data. - :attr:`Sector `: Domain class for accessing sector information. - :attr:`Industry `: Domain class for accessing industry information. - :attr:`download `: Function to download market data for multiple tickers. @@ -30,6 +31,7 @@ The following are the publicly available classes, and functions exposed by the ` yfinance.ticker_tickers yfinance.stock + yfinance.market_status yfinance.financials yfinance.analysis yfinance.sector_industry diff --git a/doc/source/reference/yfinance.market_status.rst b/doc/source/reference/yfinance.market_status.rst new file mode 100644 index 00000000..3843fd9c --- /dev/null +++ b/doc/source/reference/yfinance.market_status.rst @@ -0,0 +1,22 @@ +===================== +Market Summary +===================== + +.. currentmodule:: yfinance + + +Class +------------ +The `MarketSummary` class, allows you to access market summary data in a Pythonic way. + +.. autosummary:: + :toctree: api/ + + MarketSummary + +Market Summary Sample Code +-------------------------- +The `MarketSummary` class, allows you to access market summary data in a Pythonic way. + +.. literalinclude:: examples/market_summary.py + :language: python \ No newline at end of file From 158b8b3be02a28da6f221bb0dbed8689c7da7454 Mon Sep 17 00:00:00 2001 From: R5dan Date: Sun, 8 Dec 2024 20:29:56 +0000 Subject: [PATCH 7/7] Update README --- README.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index bd47e8f3..2509ad66 100644 --- a/README.md +++ b/README.md @@ -36,11 +36,12 @@ Yahoo! finance API is intended for personal use only.** ## Main components -- `Ticker`: single ticker data -- `Tickers`: multiple tickers' data -- `download`: download market data for multiple tickers -- `Sector` and `Industry`: sector and industry information -- `EquityQuery` and `Screener`: build query to screen market +- `Ticker`: single ticker data +- `Tickers`: multiple tickers' data +- `MarketSummary`: market summary data +- `download`: download market data for multiple tickers +- `Sector` and `Industry`: sector and industry information +- `EquityQuery` and `Screener`: build query to screen market ## **NEW DOCUMENTATION WEBSITE**: [ranaroussi.github.io/yfinance](https://ranaroussi.github.io/yfinance/index.html) @@ -48,7 +49,7 @@ Yahoo! finance API is intended for personal use only.** Install `yfinance` from PYPI using `pip`: -``` {.sourceCode .bash} +```{.sourceCode .bash} $ pip install yfinance ``` @@ -80,4 +81,3 @@ details on your rights to use the actual data downloaded. Please drop me a note with any feedback you have. **Ran Aroussi** -