Skip to content

Commit e04278c

Browse files
committed
implement Sector and Industry
1 parent 6b7a511 commit e04278c

File tree

7 files changed

+457
-1
lines changed

7 files changed

+457
-1
lines changed

README.md

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,55 @@ data = yf.download("SPY AAPL", period="1mo")
223223

224224
#### `yf.download()` and `Ticker.history()` have many options for configuring fetching and processing. [Review the Wiki](https://github.com/ranaroussi/yfinance/wiki) for more options and detail.
225225

226+
### Sector and Industry
227+
228+
The `Sector` and `Industry` modules allow you to access the US market information.
229+
230+
To initialize, use the relevant sector or industry key as below. (Complete mapping of the keys is available in `domain.py`.)
231+
232+
```python
233+
import yfinance as yf
234+
235+
tech = yf.Sector('technology')
236+
software = yf.Industry('software-infrastructure')
237+
238+
# Common information
239+
tech.key
240+
tech.name
241+
tech.symbol
242+
tech.ticker
243+
tech.overview
244+
tech.top_companies
245+
tech.research_reports
246+
247+
# Sector information
248+
tech.top_etfs
249+
tech.top_mutual_funds
250+
tech.industries
251+
252+
# Industry information
253+
software.sector_key
254+
software.sector_name
255+
software.top_performing_companies
256+
software.top_growth_companies
257+
```
258+
259+
The modules can be chained with Ticker as below.
260+
```python
261+
import yfinance as yf
262+
263+
# Ticker to Sector and Industry
264+
msft = yf.Ticker('MSFT')
265+
tech = yf.Sector(msft.info.get('sectorKey'))
266+
software = yf.Industry(msft.info.get('industryKey'))
267+
268+
# Sector and Industry to Ticker
269+
tech_ticker = tech.ticker
270+
tech_ticker.info
271+
software_ticker = software.ticker
272+
software_ticker.history()
273+
```
274+
226275
### Logging
227276

228277
`yfinance` now uses the `logging` module to handle messages, default behaviour is only print errors. If debugging, use `yf.enable_debug_mode()` to switch logging to debug with custom formatting.

yfinance/__init__.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,13 @@
2525
from .multi import download
2626
from .utils import enable_debug_mode
2727
from .cache import set_tz_cache_location
28+
from .domain.sector import Sector
29+
from .domain.industry import Industry
2830

2931
__version__ = version.version
3032
__author__ = "Ran Aroussi"
3133

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

35-
__all__ = ['download', 'Ticker', 'Tickers', 'enable_debug_mode', 'set_tz_cache_location']
37+
__all__ = ['download', 'Ticker', 'Tickers', 'enable_debug_mode', 'set_tz_cache_location', 'Sector', 'Industry']

yfinance/const.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
_QUERY1_URL_ = 'https://query1.finance.yahoo.com'
12
_BASE_URL_ = 'https://query2.finance.yahoo.com'
23
_ROOT_URL_ = 'https://finance.yahoo.com'
34

yfinance/domain/__init__.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# domain/__init__.py
2+
from .sector import Sector
3+
from .industry import Industry
4+
5+
__all__ = ['Sector', 'Industry']

yfinance/domain/domain.py

Lines changed: 247 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,247 @@
1+
from ..ticker import Ticker
2+
from ..const import _QUERY1_URL_
3+
from ..data import YfData
4+
from typing import Dict, List, Optional
5+
6+
import pandas as _pd
7+
8+
_QUERY_URL_ = f'{_QUERY1_URL_}/v1/finance'
9+
10+
class Domain:
11+
def __init__(self, key: str, session=None, proxy=None):
12+
self._key: str = key
13+
self.proxy = proxy
14+
self.session = session
15+
self._data: YfData = YfData(session=session)
16+
17+
self._name: Optional[str] = None
18+
self._symbol: Optional[str] = None
19+
self._overview: Optional[Dict] = None
20+
self._top_companies: Optional[_pd.DataFrame] = None
21+
self._research_report: Optional[List[Dict[str, str]]] = None
22+
23+
@property
24+
def key(self) -> str:
25+
return self._key
26+
27+
@property
28+
def name(self) -> str:
29+
self._ensure_fetched(self._name)
30+
return self._name
31+
32+
@property
33+
def symbol(self) -> str:
34+
self._ensure_fetched(self._symbol)
35+
return self._symbol
36+
37+
@property
38+
def ticker(self) -> Ticker:
39+
self._ensure_fetched(self._symbol)
40+
return Ticker(self._symbol)
41+
42+
@property
43+
def overview(self) -> Dict:
44+
self._ensure_fetched(self._overview)
45+
return self._overview
46+
47+
@property
48+
def top_companies(self) -> Optional[_pd.DataFrame]:
49+
self._ensure_fetched(self._top_companies)
50+
return self._top_companies
51+
52+
@property
53+
def research_reports(self) -> List[Dict[str, str]]:
54+
self._ensure_fetched(self._research_reports)
55+
return self._research_reports
56+
57+
def _fetch(self, query_url, proxy) -> Dict:
58+
params_dict = {"formatted": "true", "withReturns": "true", "lang": "en-US", "region": "US"}
59+
result = self._data.get_raw_json(query_url, user_agent_headers=self._data.user_agent_headers, params=params_dict, proxy=proxy)
60+
return result
61+
62+
def _parse_and_assign_common(self, data) -> None:
63+
self._name = data.get('name')
64+
self._symbol = data.get('symbol')
65+
self._overview = self._parse_overview(data.get('overview', {}))
66+
self._top_companies = self._parse_top_companies(data.get('topCompanies', {}))
67+
self._research_reports = data.get('researchReports')
68+
69+
def _parse_overview(self, overview) -> Dict:
70+
return {
71+
"companies_count": overview.get('companiesCount', None),
72+
"market_cap": overview.get('marketCap', {}).get('raw', None),
73+
"message_board_id": overview.get('messageBoardId', None),
74+
"description": overview.get('description', None),
75+
"industries_count": overview.get('industriesCount', None),
76+
"market_weight": overview.get('marketWeight', {}).get('raw', None),
77+
"employee_count": overview.get('employeeCount', {}).get('raw', None)
78+
}
79+
80+
def _parse_top_companies(self, top_companies) -> Optional[_pd.DataFrame]:
81+
top_companies_column = ['symbol', 'name', 'rating', 'market weight']
82+
top_companies_values = [(c.get('symbol'),
83+
c.get('name'),
84+
c.get('rating'),
85+
c.get('marketWeight',{}).get('raw',None)) for c in top_companies]
86+
87+
if not top_companies_values:
88+
return None
89+
90+
return _pd.DataFrame(top_companies_values, columns = top_companies_column).set_index('symbol')
91+
92+
def _fetch_and_parse(self) -> None:
93+
raise NotImplementedError("_fetch_and_parse() needs to be implemented by children classes")
94+
95+
def _ensure_fetched(self, attribute) -> None:
96+
if attribute is None:
97+
self._fetch_and_parse()
98+
99+
100+
# map last updated as of 2024.09.18
101+
SECTOR_INDUSTY_MAPPING = {
102+
'basic-materials': {'specialty-chemicals',
103+
'gold',
104+
'building-materials',
105+
'copper',
106+
'steel',
107+
'agricultural-inputs',
108+
'chemicals',
109+
'other-industrial-metals-mining',
110+
'lumber-wood-production',
111+
'aluminum',
112+
'other-precious-metals-mining',
113+
'coking-coal',
114+
'paper-paper-products',
115+
'silver'},
116+
'communication-services': {'internet-content-information',
117+
'telecom-services',
118+
'entertainment',
119+
'electronic-gaming-multimedia',
120+
'advertising-agencies',
121+
'broadcasting',
122+
'publishing'},
123+
'consumer-cyclical': {'internet-retail',
124+
'auto-manufacturers',
125+
'restaurants',
126+
'home-improvement-retail',
127+
'travel-services',
128+
'specialty-retail',
129+
'apparel-retail',
130+
'residential-construction',
131+
'footwear-accessories',
132+
'packaging-containers',
133+
'lodging',
134+
'auto-parts',
135+
'auto-truck-dealerships',
136+
'gambling',
137+
'resorts-casinos',
138+
'leisure',
139+
'apparel-manufacturing',
140+
'personal-services',
141+
'furnishings-fixtures-appliances',
142+
'recreational-vehicles',
143+
'luxury-goods',
144+
'department-stores',
145+
'textile-manufacturing'},
146+
'consumer-defensive': {'discount-stores',
147+
'beverages-non-alcoholic',
148+
'household-personal-products',
149+
'packaged-foods',
150+
'tobacco',
151+
'confectioners',
152+
'farm-products',
153+
'food-distribution',
154+
'grocery-stores',
155+
'beverages-brewers',
156+
'education-training-services',
157+
'beverages-wineries-distilleries'},
158+
'energy': {'oil-gas-integrated',
159+
'oil-gas-midstream',
160+
'oil-gas-e-p',
161+
'oil-gas-equipment-services',
162+
'oil-gas-refining-marketing',
163+
'uranium',
164+
'oil-gas-drilling',
165+
'thermal-coal'},
166+
'financial-services': {'banks-diversified',
167+
'credit-services',
168+
'asset-management',
169+
'insurance-diversified',
170+
'banks-regional',
171+
'capital-markets',
172+
'financial-data-stock-exchanges',
173+
'insurance-property-casualty',
174+
'insurance-brokers',
175+
'insurance-life',
176+
'insurance-specialty',
177+
'mortgage-finance',
178+
'insurance-reinsurance',
179+
'shell-companies',
180+
'financial-conglomerates'},
181+
'healthcare': {'drug-manufacturers-general',
182+
'healthcare-plans',
183+
'biotechnology',
184+
'medical-devices',
185+
'diagnostics-research',
186+
'medical-instruments-supplies',
187+
'medical-care-facilities',
188+
'drug-manufacturers-specialty-generic',
189+
'health-information-services',
190+
'medical-distribution',
191+
'pharmaceutical-retailers'},
192+
'industrials': {'aerospace-defense',
193+
'specialty-industrial-machinery',
194+
'railroads',
195+
'building-products-equipment',
196+
'farm-heavy-construction-machinery',
197+
'specialty-business-services',
198+
'integrated-freight-logistics',
199+
'waste-management',
200+
'conglomerates',
201+
'industrial-distribution',
202+
'engineering-construction',
203+
'rental-leasing-services',
204+
'consulting-services',
205+
'trucking',
206+
'electrical-equipment-parts',
207+
'airlines',
208+
'tools-accessories',
209+
'pollution-treatment-controls',
210+
'security-protection-services',
211+
'marine-shipping',
212+
'metal-fabrication',
213+
'infrastructure-operations',
214+
'staffing-employment-services',
215+
'airports-air-services',
216+
'business-equipment-supplies'},
217+
'real-estate': {'reit-specialty',
218+
'reit-industrial',
219+
'reit-retail',
220+
'reit-residential',
221+
'reit-healthcare-facilities',
222+
'real-estate-services',
223+
'reit-office',
224+
'reit-diversified',
225+
'reit-mortgage',
226+
'reit-hotel-motel',
227+
'real-estate-development',
228+
'real-estate-diversified'},
229+
'technology': {'software-infrastructure',
230+
'semiconductors',
231+
'consumer-electronics',
232+
'software-application',
233+
'information-technology-services',
234+
'semiconductor-equipment-materials',
235+
'communication-equipment',
236+
'computer-hardware',
237+
'electronic-components',
238+
'scientific-technical-instruments',
239+
'solar',
240+
'electronics-computer-distribution'},
241+
'utilities': {'utilities-regulated-electric',
242+
'utilities-renewable',
243+
'utilities-diversified',
244+
'utilities-regulated-gas',
245+
'utilities-independent-power-producers',
246+
'utilities-regulated-water'}
247+
}

0 commit comments

Comments
 (0)