Skip to main content

Morningstar scraping utilities

Project description

MorningstarFetcher

MorningstarFetcher is a Python package designed to interact with Morningstar’s public endpoints, simplifying access to financial data across various asset types (stocks, ETFs, mutual funds). It provides an interface for running market screeners and retrieving detailed information on specific securities. Its main goal is to streamline data retrieval for asset management—for example, to analyze portfolios, compare funds, or monitor risk and performance metrics.

Table of Contents


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.DataFrame for 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

The 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)
The returned DataFrame contains one row per security, each with a unique 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:

The ETF, Fund, and Stock classes each represent a specific asset type and automatically retrieve relevant data from Morningstar when instantiated with a 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

morningstarfetcher-6.0.1.tar.gz (27.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

morningstarfetcher-6.0.1-py3-none-any.whl (27.1 kB view details)

Uploaded Python 3

File details

Details for the file morningstarfetcher-6.0.1.tar.gz.

File metadata

  • Download URL: morningstarfetcher-6.0.1.tar.gz
  • Upload date:
  • Size: 27.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.10.2

File hashes

Hashes for morningstarfetcher-6.0.1.tar.gz
Algorithm Hash digest
SHA256 987654a670d0e22f47e8a7a96e1b09bbc8c086728cef23d8bb9bb68032e4ee4e
MD5 4596a6b53bfef7f331c9322e1a28d7db
BLAKE2b-256 96c5324a73367b395deb2943b16e727c2eda5a0f50b597414c5500d511c3bf4f

See more details on using hashes here.

File details

Details for the file morningstarfetcher-6.0.1-py3-none-any.whl.

File metadata

File hashes

Hashes for morningstarfetcher-6.0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 77171d03ea0edb525b8fdcaeddfb12da6d374b58f796b4cfad2478e3f94ae94e
MD5 60c460f9fa7b2ae59e328ca456cad8c8
BLAKE2b-256 27eef8f7f5f80285e14a4ba67085e0e758df9faa8cf26ca96abb3bdfc7c6637e

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page