One Python call for the price of any mutual fund, ETF or pension plan in the world.
Look it up by ISIN, ticker or its local code; no API keys, no accounts.
Over 350,000 funds and 38,000 ETF listings worldwide, plus 45,000+ funds and pension plans from national sources.
import fundly
fundly.quote("VTSAX").price # 182.82 US mutual fund, by ticker
fundly.quote("ES0112611001").price # 367.82113 Spanish fund, by ISIN
fundly.quote("cl-afp:HABITAT-A").price # 100365.02 Chilean pension fund, local code
fundly.history("INF179K01XQ0").to_pandas() # Indian fund, daily history as a pandas Series
Why fundly
Ticker-based tools leave most of the world's savings out: European share classes, Indian schemes, Chilean AFPs, Spanish pension plans. fundly starts from the identifiers people actually have, asks several sources, and tells you exactly what kind of price you got.
| fundly | yfinance | mstarpy | |
|---|---|---|---|
| Look up by ISIN | ✅ | via search | via search |
| Local codes (AMFI, CAFCI, AFP, DGS…) | ✅ | ❌ | ❌ |
| Pension plans in 7 countries | ✅ | ❌ | ❌ |
| Says whether a price is NAV, exchange close or index | ✅ | ❌ | ❌ |
| Several sources with automatic fallback | ✅ | ❌ | ❌ |
| Cross-check sources side by side | ✅ | ❌ | ❌ |
| Needs a browser / Selenium | no | no | yes (v10+) |
Install
pip install fundly # pip install "fundly[pandas]" for .to_pandas()
A quick tour
Search by name, in any language. Every word counts, in any order, accents optional:
for f in fundly.search("emaxis slim", limit=3):
print(f.id, f.name)
# JP90C000PZY9 MUAM eMAXIS Slim All US Equity
# JP90C000G7W3 MUAM eMAXIS Slim All World Eq 3 Reg Eql
# JP90C000H1T1 MUAM eMAXIS Slim All Wld Eq All Country
[f.id for f in fundly.search("superfondo acciones", limit=3)]
# ['ar-cafci:148', 'ar-cafci:304', 'ar-cafci:1373']
Any identifier lands on the same fund. Tickers and local codes are translated to the ISIN when one exists, so caching and cross-checking work across them:
fundly.quote("in-amfi:118989").id # 'INF179K01XQ0' (AMFI scheme code → ISIN)
fundly.quote("VOO").id, fundly.instrument("VOO").type # ('US9229083632', 'etf')
Daily history, straight into pandas:
fundly.history("N5508", start="2026-10-01").to_pandas().tail(3) # Spanish pension plan
# date
# 2026-10-21 134.58548
# 2026-10-22 133.59280
# 2026-10-23 133.50458
Cross-check every source. Independent feeds agreeing to the last decimal is how you know a price is right:
c = fundly.compare("ES0173311103") # Renta 4 Numantia Patrimonio Global
for q in c.quotes:
print(f"{q.source:<12} {q.price:>9} {q.currency} {q.date}")
# morningstar 29.3605 EUR 2026-10-23
# finect 29.00609 EUR 2026-10-21
# ft 29.3605 EUR 2026-10-23
# quefondos 29.41016 EUR 2026-10-22
# yahoo 29.4102 EUR 2026-10-22
c.nav_spread_pct # 0.0 (spread between sources that share the latest date)
Know what kind of price you got. Every quote says whether it is an official NAV, an exchange close, or an index rebuilt from published returns:
fundly.quote("IE00B4L5Y983").price_type # 'nav' iShares Core MSCI World: issuer NAV
fundly.quote("IE00B4L5Y983", source="morningstar").price_type # 'market' exchange close
fundly.quote("il-gemel:880").price_type # 'index' Israeli fund: monthly returns only
Spot bad data instead of trusting it blindly. A price older than expected is flagged stale; one far from what other sources said in the last month is checked against the next source and replaced or flagged suspicious. Histories note isolated spikes and ×100 jumps:
q = fundly.quote("ar-cafci:3906") # Argentine agro fund that stopped reporting
q.stale, q.age_days, q.warnings
# (True, 90, ('stale: last price is 90 days old (2026-07-31)',))
q.to_dict() # every result is JSON-ready
# {'id': 'ar-cafci:3906', 'name': 'ADBlick Granos Plus FCIC', 'price': 0.488829, 'date': '2026-07-31', ...}
Value everything in one currency. Prices come in each fund's own currency; ask for another and fundly converts at the ECB reference rate of the price's date, keeping the original figure:
q = fundly.quote("INF179K01XQ0", currency="EUR") # Indian fund, in euros
round(q.price, 4), q.original_price, q.original_currency, round(q.fx_rate, 6), q.fx_source
# (2.0377, 216.123, 'INR', 0.009428, 'ecb')
fundly.history("VTSAX", start="2025-01-01", currency="EUR") # each day at that day's rate
Coverage
Real quotes taken with fundly on 27 October 2026:
| Market | Example id | What it is | Latest | Source |
|---|---|---|---|---|
| 🌍 Worldwide funds | ZAE000025029 |
Allan Gray Balanced A | 201.67 ZAR | Morningstar |
| 🌍 Worldwide ETFs | VOO → US9229083632 |
Vanguard S&P 500 ETF | 703.41 USD (market) | Morningstar |
| 🇺🇸 US mutual funds | VTSAX |
Vanguard Total Stock Market Admiral | 182.82 USD | Morningstar |
| 🇪🇸 Spanish funds | ES0112611001 |
Azvalor Internacional FI | 367.82 EUR | Morningstar, Finect, FT, Quefondos |
| 🇪🇸 Spanish pension plans | N5508 |
Santander Autónomos RVM PPES | 133.50 EUR | Finect, comparadorfondos |
| 🇬🇧 UK pension & life funds | ft:0P00009VB8 |
Aviva Pension Invesco Emerging Markets | 2.53 GBP | FT |
| 🇵🇱 Poland (funds, PPK, OFE) | pl-analizy:ARK52 |
Erste PPK 2050 | 2,439.80 PLN | analizy.pl |
| 🇮🇳 India mutual funds | in-amfi:118989 |
HDFC Mid Cap Direct Growth | 216.12 INR | AMFI (official) |
| 🇮🇳 India NPS pensions | in-nps:SM001001 |
SBI Pension Fund, Central Govt | 49.36 INR | npsnav.in |
| 🇨🇳 China | cn:110022 |
易方达消费行业股票 | 2.79 CNY | Eastmoney |
| 🇯🇵 Japan | JP90C000H1T1 |
eMAXIS Slim All Country | 37,441 JPY | Morningstar |
| 🇻🇳 Vietnam | vn-fmarket:VFF |
VinaCapital Enhanced Bond | 27,154.70 VND | fmarket |
| 🇮🇩 Indonesia | IDN000007002 |
Simpan Balanced | 944.27 IDR | Morningstar, Pasardana, fund managers |
| 🇨🇱 Chile pension funds | cl-afp:HABITAT-A |
AFP Habitat, Fund A | 100,365.02 CLP | Superintendencia de Pensiones |
| 🇨🇴 Colombia pensions & funds | co-pension:10-6000 |
Colfondos, higher-risk fund | 97,116.41 COP | datos.gov.co |
| 🇧🇷 Brazil funds | br-cvm:00017024000153 |
Renda fixa class | 45.26 BRL | CVM (official open data) |
| 🇦🇷 Argentina funds | ar-cafci:148 |
Superfondo Acciones, Clase A | 486.53 ARS | CAFCI, argentinadatos |
| 🇮🇱 Israel provident & pension | il-gemel:880 |
Meitav Hishtalmut General | index | Gemel-net (gov) |
Tested at random: in 326 funds, ETFs and pension plans drawn at random from 15 universes (worldwide Morningstar pages, AMFI, CAFCI, CVM, Chilean AFPs, Spanish plans…), 96% returned a price and none raised an unexpected error. The misses were mostly funds that have since closed but are still listed.
Morningstar alone reaches funds and ETFs in most countries (US, Canada, Europe, Japan, Korea, Taiwan, Hong Kong, Singapore, Australia, South Africa, the Gulf…). The national sources add official data and products Morningstar doesn't carry. Not covered yet: Turkey, Peru, Mexico, Hong Kong MPF and Australian superannuation. Their public data sits behind bot protection or isn't published.
History depth. Argentine funds have daily history from January 2020 for every class, from the argentinadatos.com community mirror of the regulator's (CNV) daily sheets. Indonesian funds get full history since launch from Morningstar (about a third of them), or from the manager's own site for Batavia, Trimegah, Avrist and Syailendra (about 140 more funds, some back to 1996). Others have Pasardana's last 12 months: older data is a paid product everywhere we looked. With the cache on, fundly keeps every Indonesian and Argentine price it downloads, so those histories grow on your machine instead of sliding along.
Identifiers
| You type | Means | Example |
|---|---|---|
| ISIN | any fund or ETF | IE00B4L5Y983 |
| ticker | listed ETF or US/CA mutual fund | VTSAX, ticker:VOO |
N#### · S#### |
Spanish pension plan · employment sub-plan (DGS code) | N5508, S0156 |
ms: |
Morningstar id, for funds without ISIN (Korea, China…) | ms:F00001H9R0 |
ft: |
FT symbol, for UK pension/life funds | ft:0P00009VB8 |
in-amfi: · in-nps: |
India scheme code · NPS scheme | in-amfi:118989 |
cn: |
Chinese fund code | cn:110022 |
cl-afp: |
Chilean AFP + fund letter | cl-afp:HABITAT-A |
co-pension: · co-fic: |
Colombia entity–fund · collective fund | co-pension:10-6000 |
br-cvm: |
Brazilian CNPJ (digits) | br-cvm:00017024000153 |
ar-cafci: |
CAFCI class code | ar-cafci:148 |
pl-analizy: |
analizy.pl code | pl-analizy:PZU50 |
il-gemel: · il-pensia: |
Israeli fund id | il-gemel:880 |
vn-fmarket: · id-pasardana: |
Vietnam fund code · Pasardana id | vn-fmarket:VFF |
Results always carry a canonical id: the ISIN when there is one, otherwise scheme:code.
How it works
flowchart LR
Q["fundly.quote(id)"] --> I["Translate the id<br/>(ticker → ISIN…)"]
I --> C{"Fresh in the<br/>local cache?"}
C -- yes --> R(["Quote"])
C -- no --> T["Work out the type<br/>fund · ETF · plan"]
T --> S1["1st source that<br/>knows this id"]
S1 -- answers --> R
S1 -- "fails or 429" --> S2["next source"]
S2 -- answers --> R
- Each source only gets the ids it understands. National sources answer for their own codes; Morningstar, FT and Yahoo for ISINs and tickers.
- Priority depends on the product. ETFs go to the official NAV first, Indian funds to AMFI first, and pension plans to the portals that carry them.
- If a source fails, the next one answers. Rate-limited sources are paused, not hammered.
- Search only asks who can answer. An ISIN or a local code is looked up directly. Text goes to the worldwide sources, plus national ones whose words appear in it ("afp" → Chile, "hdfc" → India…); Chinese, Hebrew and Vietnamese text go straight to the sources that publish names in that script. Other national catalogues are only tried when nothing matches every word. Results are ranked by how well the name matches, then by fund size.
- Bad data is flagged, not hidden. A price far from the last month's prices from other sources (a ×100 unit error, a wrong share class) makes fundly ask the next source; whichever two agree wins, and the quote says what was replaced. Old prices are marked
stale(10 days; 45 for monthly series). - Local cache in your platform's cache folder (
~/.cache/fundlyon Linux,~/Library/Caches/fundlyon macOS,%LOCALAPPDATA%\fundly\Cacheon Windows; or$FUNDLY_CACHE_DIR): quotes are reused for 6 h, history and searches for 24 h. The catalogue starts empty and only grows with what you look up. Bulk files (Brazil's monthly CVM archives, Argentine history files) are kept there too and revalidated with the server, so a later session downloads only what changed.
API
| Call | Returns |
|---|---|
fundly.search(q, type=None, category=None, live=True, limit=20) |
list[Instrument] |
fundly.instrument(id) |
Instrument (name, type, currency, domicile, provider, category, TER, size, other ids) |
fundly.quote(id, source=None, currency=None) |
Quote (price, date, currency, price_type, source, warnings, stale, suspicious, age_days; plus the original price and FX rate if converted) |
fundly.history(id, start=None, end=None, source=None, currency=None) |
History, with .points, .warnings and .to_pandas() |
fundly.compare(id) |
Comparison, with every source's quote (the odd one out flagged suspicious) and nav_spread_pct |
Every result has .to_dict(), with dates as ISO strings, ready for json.dumps.
For custom settings, create your own client:
from fundly import Client
with Client(cache="~/data/fundly", min_interval=1.0, max_wait=60) as fl:
fl.history("IE00B4L5Y983", start="2015-01-01")
min_interval: seconds between two requests to the same site (default 0.5).max_wait: total seconds one call may take across every source it tries (default 120;Nonefor no limit, e.g. for many years of Brazilian history, whose first download takes a while; if a call times out, the download carries on in the background and the next call finds it on disk). A hanging site can't hold your program beyond it.exclude: sources to leave out.
Errors: InvalidId, NotFound, UnknownSource, FXUnavailable and FundlyTimeout, all subclasses of FundlyError. Source fallbacks are logged on the fundly logger.
Currencies
- Prices are always in the share class's own currency, never silently converted. Prices quoted in pence, cents or agorot (GBp/GBX, ZAc, ILA) are turned into pounds, rand and shekels.
- With
currency="EUR"(or any ISO code) the price is converted through the euro at the rate in force on the price's date; weekends and holidays use the last published rate. History converts each day with its own rate. - Rates are ECB euro reference rates (29 currencies, source: ECB). Currencies the ECB doesn't publish (ARS, CLP, COP, VND, TWD…) come from Yahoo Finance. Converted quotes keep
original_price,original_currency,fx_rate,fx_dateandfx_source, so a converted price is never mistaken for a native one.
Sources
| Source | Covers | Data |
|---|---|---|
| Morningstar | Funds & ETFs worldwide, search | NAV / exchange close |
| Finect | Spanish & EU funds, ETF NAVs, Spanish plans | NAV |
| Financial Times | Funds & ETFs, UK pension funds | NAV / exchange close |
| Quefondos | Spanish funds & plans | latest NAV |
| comparadorfondos | Spanish pension plans | NAV |
| Yahoo Finance | Funds & ETFs (fallback) | NAV / exchange close |
| AMFI (+ mfapi.in history) | India mutual funds | NAV, official |
| npsnav.in | India NPS pensions | NAV |
| Eastmoney | China funds | NAV |
| Superintendencia de Pensiones | Chile AFP funds A–E | NAV, official |
| datos.gov.co | Colombia pensions & collective funds | NAV, official |
| CVM open data | Brazil funds | NAV, official (ODbL) |
| CAFCI (+ argentinadatos.com history) | Argentina funds | NAV, official |
| analizy.pl | Poland funds, PPK, OFE | NAV |
| Gemel-net / Pensia-net | Israel provident & pension funds | index from monthly returns, official |
| fmarket | Vietnam funds | NAV |
| Pasardana | Indonesia funds | NAV, last 12 months of history |
| Batavia, Trimegah, Avrist, Syailendra | Their Indonesian funds | full NAV history, from each manager's site |
Responsible use
fundly is an independent, source-available project, not affiliated with any of the sites above. All data belongs to its owners.
- No data ships with fundly. Every request goes from your machine to the public website, as if you visited it, and you are responsible for following each site's terms of use.
- Personal, non-commercial use. Most of these sites allow personal use and forbid redistributing or reselling their data. Don't use fundly to build a data feed, a paid API or any service that republishes it.
- robots.txt. Morningstar, Finect, Yahoo, npsnav.in, analizy.pl and Gemel-net ask automated clients to stay away in their robots.txt. Like yfinance, fundly uses them by default. If you prefer to respect robots.txt strictly, leave them out:
Client(exclude=["morningstar", "finect", "yahoo", "npsnav", "analizy", "gemelnet"])
- Gentle by default. At most one request every 0.5 s per site, cached results, and a pause whenever a site answers 429 Too Many Requests.
- Honest. fundly identifies itself in its
User-Agentand never bypasses anti-bot protection. Sites that block automated clients are not supported. - No advice. Prices can be late, missing or wrong. Nothing here is investment advice, and the software comes with no warranty.
If you run one of these sites and want it out of fundly, open an issue.
License
fundly is released under the PolyForm Noncommercial License 1.0.0.
- ✅ Free for personal use, research, education, hobby projects, and non-profit, educational and government organisations.
- ❌ No commercial use. You can't sell it, include it in a paid product or service, or use it inside a business.
Because it forbids commercial use, fundly is source-available, not "open source" in the OSI sense.
Contributing
uv sync
uv run pytest # 527 offline tests: parsers, client, currencies, broken sites, properties, concurrency
uv run pytest -m live # 75 tests against the real sites
Adding a country is one class with get_quote, get_history and, optionally, search, plus an id scheme registered in fundly.ids. See fundly/sources/.
🌍 En español: fundly consulta el valor liquidativo de fondos de inversión, ETFs y planes de pensiones de todo el mundo por ISIN, ticker o código local, cruzando varias fuentes. Licencia PolyForm Noncommercial: uso personal y no comercial; no redistribuye datos.
Metadata
Release files for fundly 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| fundly-0.1.0.tar.gz | 99.2 kB | With provenance | Details for fundly-0.1.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| fundly-0.1.0-py3-none-any.whl | Python 3 | none | any | Details for fundly-0.1.0-py3-none-any.whl |
Total release size: 174.8 kB
Release files / fundly-0.1.0.tar.gz
| Download URL | fundly-0.1.0.tar.gz |
|---|---|
| Size | 99.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
83d72f9d5710acf8a3efd67fe8c45f781c94b15c63817d86d65197e72c1a1585
|
|
BLAKE2b-256 checksum How to use checksums |
8f0fdae7e93b8beb7feb59ceb6d3a4f38a8280714c1c8dfa18a7887a61a98377
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 3, 2026.
Transparency logRelease files / fundly-0.1.0-py3-none-any.whl
| Download URL | fundly-0.1.0-py3-none-any.whl |
|---|---|
| Size | 75.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
1f4a6ec825b86eed3cb8a44b28c0ff7e1faee852c1ac2000eaf8e0e6488182fb
|
|
BLAKE2b-256 checksum How to use checksums |
2b7b974223eb034aaec4d45f45b5faca9a0a6fc15da79885703e4d9c47f142ea
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 3, 2026.
Transparency logSecurity for fundly 0.1.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for fundly-0.1.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 3, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.