Morningstar scraping utilities
Project description
MorningstarFetcher
Table of Contents
- Features
- Installation
- Documentation
- Screener Class Overview
- Asset Classes Overview
- Example: Fetching and Analyzing Mutual Funds in France
- Usage Note & License
Features
- Asynchronous Screener: Query Morningstar’s screener to filter and list securities by market, investment type, etc.
- Asset Classes: Dedicated classes (
ETF,Stock,Fund) that automatically fetch and expose data attributes. - Pandas Integration: Screener results are returned as
pandas.DataFramefor seamless data analysis.
Installation
Pypi: https://pypi.org/project/morningstarFetcher/
pip install morningstarFetcher
Documentation
Detailed attribute listings and extended examples are available in the docs/ directory:
Screener Class Overview
Screener class enables you to access Morningstar’s global screener, allowing you to filter and list securities by investment universe and geographic market. Supported universes include "stocks", "etfs", and "mutual_funds". Use screener.get() with your chosen type to retrieve results for that universe. The class provides available markets via the markets attribute and country codes via country_codes, making it easy to target specific regions. Results from get() are returned as a pandas.DataFrame with columns such as securityID, name, and isin. You can further refine your search using custom filters based on fields available for each investment type. To see all filterable fields, access the {your_investment_type}_fields attribute. For full details, refer to the Screener documentation.
Instantiation Example
from morningstarFetcher import Screener
# Initialize the screener and inspect available markets
screener = Screener()
print("Available markets:", screener.markets)
print("Country codes:", screener.country_codes.keys())
# Fetch the first page of ETFs on the French market
results_df = screener.get("etfs", "fr")
print(results_df.head(5)) # DataFrame with securityID, name, isin, etc.
# Extract the first securityID
default_id = results_df.iloc[0]["securityID"]
print("First French ETF securityID:", default_id)
securityID. You can use this identifier with the ETF, Stock, or Fund classes to retrieve comprehensive details and attributes for that security.
Asset Classes Overview:
securityID. These classes provide direct access to key attributes such as price, performance, portfolio holdings, fund managers, insider transactions, and financial statements, depending on the asset type. Each class is designed for intuitive exploration of available data fields and methods. For comprehensive attribute and method documentation, see the documentation.
Instantiation Example:
from morningstarFetcher import ETF, Fund, Stock
etf_id = "your_etf_id"
fund_id = "your_fund_id"
stock_id = "your_stock_id"
etf = ETF(etf_id)
fund = Fund(fund_id)
stock = Stock(stock_id)
print("ETF price info:", etf.price)
print("Fund managers:", fund.people)
print("Stock valuation metrics:", stock.valuation)
Each object automatically retrieves all available fields for the given securityID.
Example: Fetching and Analyzing Mutual Funds in France
The following example demonstrates how to use the library to retrieve and analyze fund data for mutual funds. In this example we will focus on mutual funds domiciled in France with specific performance metrics. For this, we will use the Screener class to filter funds based on their 5-year total return and alpha, and then retrieve detailed portfolio holdings for each fund.
First we will set up the screener with the desired filters, then fetch the top mutual funds in France based on these filters.
import morningstarFetcher as mf
from pprint import pprint
screener = mf.Screener() # Initialize the screener
filters = [
["totalReturn[5y]", ">", "20"], # 5 year total return > 20%
["alpha[5yMonthly]", ">", "1"], # 5 year monthly alpha > 1
["domicile", "=", "FRA"] # Domicile in France
]
Note: The filters can be adjusted based on your specific requirements. The above filters are just examples to demonstrate the functionality. You can apply filter to any field included in the {investment_type}_fields attribute of the Screener class.
We then proceed to fetch the mutual funds using these filters and extract their security IDs to create Fund objects.
french_mkt_funds_df = screener.get("mutual_funds", "fr", sort_by="totalReturn[5y]:desc", pages=1, filters=filters) # Fetch top mutual funds in France based on previous filters
french_mkt_funds_ids = french_mkt_funds_df["securityID"].tolist() # Extract security IDs of the funds
french_mkt_funds = [mf.Fund(sec_id, lazy=True) for sec_id in french_mkt_funds_ids] # Create Fund objects for each security ID
The french_mkt_funds_df DataFrame has more than 230 columns, including detailed performance metrics, risk assessments, and other valuable information about each fund. You can explore the Screener class documentation or its {investment_type}_fields attribute to see all available fields.
Next, we will iterate through each fund to extract its portfolio holdings and summarize the data. We will create a dictionary to hold the portfolio data for each fund, including its holdings summary and detailed holdings.
french_market_funds_portfolios = {} # Dictionary to hold fund portfolios
for fund in french_mkt_funds:
fund_id = fund.security_metadata['securityID'] if 'securityID' in fund.security_metadata else fund.security_metadata['secId']
fund_isin = fund.security_metadata['isin']
fund_name = fund.security_metadata['name']
fund_holdings_summary = fund.portfolio_holdings.get('holdingSummary', {}) # Summary of holdings
fund_equity_holdings = fund.portfolio_holdings.get('equityHoldingPage', {}).get('holdingList', []) # Raw list of equity holdings
fund_bond_holdings = fund.portfolio_holdings.get('boldHoldingPage', {}).get('holdingList', []) # Raw list of bond holdings
fund_other_holdings = fund.portfolio_holdings.get('otherHoldingPage', {}).get('holdingList', []) # Raw list of other holdings
fund_holdings = {
"equity": [
{
"id": security.get("securityID", None) or security.get("secId", None),
"isin": security.get("isin", None),
"name": security.get("securityName", None),
"sector": security.get("sector", None),
"country": security.get("country", None),
"weighting": security.get("weighting", None),
"firstBoughtDate": security.get("firstBoughtDate", None),
} for security in fund_equity_holdings # "Cleaned" List of equity holdings
],
"bonds": [
{
"id": security.get("securityID", None) or security.get("secId", None),
"isin": security.get("isin", None),
"name": security.get("securityName", None),
"sector": security.get("sector", None),
"country": security.get("country", None),
"weighting": security.get("weighting", None),
"firstBoughtDate": security.get("firstBoughtDate", None),
} for security in fund_bond_holdings # "Cleaned" List of bond holdings
],
"other": [
{
"id": security.get("securityID", None) or security.get("secId", None),
"isin": security.get("isin", None),
"name": security.get("securityName", None),
"sector": security.get("superSectorName", None),
"country": security.get("country", None),
"weighting": security.get("weighting", None),
"firstBoughtDate": security.get("firstBoughtDate", None),
} for security in fund_other_holdings # "Cleaned" List of other holdings
]
} # Consolidated holdings data
french_market_funds_portfolios[fund_id] = {
'name': fund_name,
'isin': fund_isin,
'holdings_summary': fund_holdings_summary,
'holdings': fund_holdings
} # Store the portfolio data
Now that we have the portfolio data for each fund, we can analyze and print the holdings summary and detailed holdings for a specific fund.
id = french_mkt_funds_ids[0] # Example: Use the first fund's ID to retrieve its portfolio data
data = french_market_funds_portfolios[id] # Retrieve the portfolio data for the selected fund
holdings_summary = data['holdings_summary']
print("Holdings Summary:", end=f'\n{"-"*80}\n')
pprint(holdings_summary, compact=True, sort_dicts=False) # Print holdings summary
print()
equity_holdings = pd.DataFrame(data['holdings']['equity']).sort_values(by='weighting', ascending=False)
print("Equity Holdings:", end=f'\n{"-"*80}\n')
pprint(equity_holdings, compact=False, sort_dicts=False) # Print equity holdings
other_holdings = pd.DataFrame(data['holdings']['other']).sort_values(by='weighting', ascending=False)
print("Other Holdings:", end=f'\n{"-"*80}\n')
pprint(other_holdings, compact=False, sort_dicts=False) # Print other holdings
print()
equity_weight = equity_holdings['weighting'].sum()
print(f"Equity Weight: {equity_weight}") # Check total equity weight
other_weight = other_holdings['weighting'].sum()
print(f"Other Weight: {other_weight}") # Check total other weight
total = equity_weight + other_weight
print(f"Total Weight: {total}") # Check total weight of all holdings
The output is as follows:
Holdings Summary:
------------------------------------------------------------------------------------------------------------------------------------------------------
'portfolioDate': '2025-05-31T05:00:00.000',
'topHoldingWeighting': 47.54024,
'equityNumberOfHolding': 35,
'fixedIncomeNumberOfHolding': 0,
'numberOfHolding': 36,
'numberOfOtherHolding': 1,
'lastTurnover': -51.3,
'LastTurnoverDate': '2011-06-30T05:00:00.000',
'secId': 'F000010ELX',
'averageTurnoverRatio': None,
'womenDirectors': 42.84,
'womenExecutives': 22.09
Equity Holdings:
------------------------------------------------------------------------------------------------------------------------------------------------------
id isin name sector country weighting firstBoughtDate
0 0P00009QNO DE0008404005 Allianz SE Financial Services Germany 7.08596 2022-09-30T05:00:00.000
1 0P0000A5JA ES0113900J37 Banco Santander SA Financial Services Spain 5.93349 2022-11-30T06:00:00.000
2 0P0000A5GW CH0011075394 Zurich Insurance Group AG Financial Services Switzerland 5.26197 2022-06-30T05:00:00.000
3 0P00009DOL IT0005239360 UniCredit SpA Financial Services Italy 4.78387 2024-12-31T06:00:00.000
4 0P00009QR8 DE0008430026 Munchener Ruckversicherungs-Gesellschaft AG Financial Services Germany 4.66989 2021-05-31T05:00:00.000
5 0P00009DL7 IT0000072618 Intesa Sanpaolo Financial Services Italy 4.59693 2024-12-31T06:00:00.000
6 0P00009WBE FR0000120628 AXA SA Financial Services France 4.57784 2021-12-31T06:00:00.000
7 0P00009QOT DE0005810055 Deutsche Boerse AG Financial Services Germany 3.72079 2022-06-30T05:00:00.000
8 0P000090MW GB00BM8PJY71 NatWest Group PLC Financial Services United Kingdom 3.46696 2021-12-31T06:00:00.000
9 0P0000TDIK CH0126881561 Swiss Re AG Financial Services Switzerland 3.42261 2022-11-30T06:00:00.000
10 0P00009QOR DE0005140008 Deutsche Bank AG Financial Services Germany 3.31545 2025-05-31T05:00:00.000
11 0P00009WPY FR0000130809 Societe Generale SA Financial Services France 2.92195 2025-05-31T05:00:00.000
12 0P00009DKL IT0000062072 Generali Financial Services Italy 2.69185 2024-12-31T06:00:00.000
13 0P0000AYAS ES0140609019 CaixaBank SA Financial Services Spain 2.68746 2022-09-30T05:00:00.000
14 0P0000A5RZ ES0113211835 Banco Bilbao Vizcaya Argentaria SA Financial Services Spain 2.58784 2022-12-31T06:00:00.000
15 0P0000A6NH FI4000552500 Sampo Oyj Class A Financial Services Finland 2.42717 2021-12-31T06:00:00.000
16 0P000090RJ GB00BPQY8M80 Aviva PLC Financial Services United Kingdom 2.30656 2022-11-30T06:00:00.000
17 0P00009QQ2 DE0008402215 Hannover Rueck SE Registered Shares Financial Services Germany 2.18706 2023-06-30T05:00:00.000
18 0P0000CG34 IE00BF0L3536 AIB Group PLC Financial Services Ireland 2.17107 2022-12-31T06:00:00.000
19 0P00013KYD NL0010773842 NN Group NV Financial Services Netherlands 2.14498 2025-04-30T05:00:00.000
20 0P0000C2OL IE00BD1RP616 Bank of Ireland Group PLC Financial Services Ireland 2.02803 2022-12-31T06:00:00.000
21 0P00009DM4 IT0000062957 Mediobanca SpA Financial Services Italy 1.97023 2025-05-31T05:00:00.000
22 0P00013DKO NL0006294274 Euronext NV Financial Services Netherlands 1.95561 2024-06-30T05:00:00.000
23 0P00007NVV GB00B02J6398 Admiral Group PLC Financial Services United Kingdom 1.93806 2024-03-31T05:00:00.000
24 0P000184F7 NL0011872643 ASR Nederland NV Financial Services Netherlands 1.89784 2025-04-30T05:00:00.000
25 0P00016X4J IT0003796171 Poste Italiane SpA Industrials Italy 1.89779 2023-04-30T05:00:00.000
26 0P0000A5MB BE0974264930 Ageas SA/ NV Financial Services Belgium 1.85755 2021-12-31T06:00:00.000
27 0P0000X4GY DE000TLX1005 Talanx AG Financial Services Germany 1.81255 2023-06-30T05:00:00.000
28 0P0000A5RI DK0060636678 Tryg AS Financial Services Denmark 1.80850 2021-12-31T06:00:00.000
29 0P00009DON IT0004810054 Unipol Assicurazioni SpA Financial Services Italy 1.77975 2024-12-31T06:00:00.000
30 0P00007OS9 GB0007099541 Prudential PLC Financial Services United Kingdom 1.27519 2025-04-30T05:00:00.000
31 0P0000A5MC BE0003797140 Groupe Bruxelles Lambert SA Financial Services Belgium 1.14945 2025-04-30T05:00:00.000
32 0P0000RXLJ NO0010582521 Gjensidige Forsikring ASA Financial Services Norway 0.91182 2025-04-30T05:00:00.000
33 0P0000A63I NL0011821202 ING Groep NV Financial Services Netherlands 0.87152 2025-05-31T05:00:00.000
34 0P0000A6PJ BMG0112X1056 Aegon Ltd Financial Services Netherlands 0.44186 2025-05-31T05:00:00.000
Other Holdings:
------------------------------------------------------------------------------------------------------------------------------------------------------
id isin name sector country weighting firstBoughtDate
0 E0GBR00IH4 GB00B1YW4409 3i Group Ord None United Kingdom 3.44254 None
Equity Weight: 96.55745
Other Weight: 3.44254
Total Weight: 99.99999
---
Usage Note & License
This library is intended for personal and educational use only. It is not affiliated with or endorsed by Morningstar. I do not encourage or condone scraping or any activity that violates Morningstar’s Terms of Service. Refer to the MIT License in this repository for warranty and liability information.Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file morningstarfetcher-6.0.0.tar.gz.
File metadata
- Download URL: morningstarfetcher-6.0.0.tar.gz
- Upload date:
- Size: 27.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.10.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c41f710ec99b8800a7facaae359b82f7de04162cf20bce24e638ab0bdc15afd9
|
|
| MD5 |
39929212f7cd356e75304647526fee37
|
|
| BLAKE2b-256 |
9d027002e100e81f9d7710b95ce953692d02500dfb5a8f17806ade507e636b77
|
File details
Details for the file morningstarfetcher-6.0.0-py3-none-any.whl.
File metadata
- Download URL: morningstarfetcher-6.0.0-py3-none-any.whl
- Upload date:
- Size: 26.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.10.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a56cc4cb1269866cb4c27a4c853292eced010f66ba3995d55f41ed5baf6dbe56
|
|
| MD5 |
0f398ee5003d1b0db212bdc68c60dd22
|
|
| BLAKE2b-256 |
a3bbc7c8de3cb7db6db62f756065904174f31e01f492c6572510ead2af1e16c4
|