Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add market Summary #2175

Merged
merged 1 commit into from
Dec 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ Yahoo! finance API is intended for personal use only.**
- `Ticker`: single ticker data
- `Tickers`: multiple tickers' data
- `download`: download market data for multiple tickers
- `Market`: get infomation about a market
- `Search`: quotes and news from search
- `Sector` and `Industry`: sector and industry information
- `EquityQuery` and `Screener`: build query to screen market
Expand Down
6 changes: 6 additions & 0 deletions doc/source/reference/examples/market.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import yfinance as yf

EUROPE = yf.Market("EUROPE")

status = EUROPE.status
summary = EUROPE.summary
2 changes: 2 additions & 0 deletions doc/source/reference/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ The following are the publicly available classes, and functions exposed by the `

- :attr:`Ticker <yfinance.Ticker>`: Class for accessing single ticker data.
- :attr:`Tickers <yfinance.Tickers>`: Class for handling multiple tickers.
- :attr:`MarketSummary <yfinance.MarketSummary>`: Class for accessing market summary.
- :attr:`Search <yfinance.Search>`: Class for accessing search results.
- :attr:`Sector <yfinance.Sector>`: Domain class for accessing sector information.
- :attr:`Industry <yfinance.Industry>`: Domain class for accessing industry information.
Expand All @@ -33,6 +34,7 @@ The following are the publicly available classes, and functions exposed by the `
yfinance.stock
yfinance.financials
yfinance.analysis
yfinance.marketsummary
yfinance.search
yfinance.sector_industry
yfinance.functions
Expand Down
16 changes: 16 additions & 0 deletions doc/source/reference/yfinance.market.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
=====================
Market Summary
=====================
.. currentmodule:: yfinance
Class
------------
The `Market` class, allows you to access market data in a Pythonic way.
.. autosummary::
:toctree: api/
Market

Market Sample Code
--------------------------
The `Market` class, allows you to access market summary data in a Pythonic way.
.. literalinclude:: examples/market.py
:language: python
3 changes: 2 additions & 1 deletion yfinance/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,13 @@
from .domain.industry import Industry
from .screener.screener import Screener
from .screener.screener_query import EquityQuery
from .domain.market import Market

__version__ = version.version
__author__ = "Ran Aroussi"

import warnings
warnings.filterwarnings('default', category=DeprecationWarning, module='^yfinance')

__all__ = ['download', 'Search', 'Ticker', 'Tickers', 'enable_debug_mode', 'set_tz_cache_location', 'Sector',
__all__ = ['download', 'Market', 'Search', 'Ticker', 'Tickers', 'enable_debug_mode', 'set_tz_cache_location', 'Sector',
'Industry', 'EquityQuery', 'Screener']
100 changes: 100 additions & 0 deletions yfinance/domain/market.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import datetime as dt

from ..data import YfData
from ..data import utils
from ..const import _QUERY1_URL_
import json as _json

class Market():
def __init__(self, market:'str', session=None, proxy=None, timeout=30):
self.market = market
self.session = session
self.proxy = proxy
self.timeout = timeout

self._data = YfData(session=self.session)
self._logger = utils.get_yf_logger()

self._status = None
self._summary = None

def _fetch_json(self, url, 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:
return data.json()
except _json.JSONDecodeError:
self._logger.error(f"{self.market}: Failed to retrieve market data and recieved faulty data.")
return {}

def _parse_data(self):
# Fetch both to ensure they are at the same time
if (self._status is not None) and (self._summary is not None):
return

self._logger.debug(f"{self.market}: Parsing market data")

# Summary

summary_url = f"{_QUERY1_URL_}/v6/finance/quote/marketSummary"
summary_fields = ["shortName", "regularMarketPrice", "regularMarketChange", "regularMarketChangePercent"]
summary_params = {
"fields": ",".join(summary_fields),
"formatted": False,
"lang": "en-US",
"market": self.market
}

status_url = f"{_QUERY1_URL_}/v6/finance/markettime"
status_params = {
"formatted": True,
"key": "finance",
"lang": "en-GB",
"market": self.market
}

self._summary = self._fetch_json(summary_url, summary_params)
self._status = self._fetch_json(status_url, status_params)

try:
self._summary = self._summary['marketSummaryResponse']['result']
self._summary = {x['exchange']:x for x in self._summary}
except Exception as e:
self._logger.error(f"{self.market}: Failed to parse market summary")
self._logger.debug(f"{type(e)}: {e}")


try:
# Unpack
self._status = self._status['finance']['marketTimes'][0]['marketTime'][0]
self._status['timezone'] = self._status['timezone'][0]
del self._status['time'] # redundant
try:
self._status.update(
open = dt.datetime.fromisoformat(self._status["open"]),
close = dt.datetime.fromisoformat(self._status["close"]),
tz = dt.timezone(self._status["timezone"]["gmtoffset"], self._status["timezone"]["short"])
)
except Exception as e:
self._logger.error(f"{self.market}: Failed to update market status")
self._logger.debug(f"{type(e)}: {e}")
except Exception as e:
self._logger.error(f"{self.market}: Failed to parse market status")
self._logger.debug(f"{type(e)}: {e}")




@property
def status(self):
self._parse_data()
return self._status


@property
def summary(self):
self._parse_data()
return self._summary
Loading