tags: fintech, python, api, opensource
When Morningstar paywalled their Portfolio X-Ray tool in 2025 ($249/year), European investors got hit the hardest. Most alternatives are US-ticker-only. If you hold iShares, Vanguard, Xtrackers, or Synchrony funds with ISINs, your options were basically zero.
So I built a free replacement: nwc-advisory.com/xray
What it does
Enter your fund ISINs and amounts (no login, no account). It fetches public factsheet data, decomposes each fund into underlying holdings, and shows 6 analysis views:
- Asset Allocation -- before and after look-through
- Geographic Exposure -- economic exposure, not fund domicile (your IE-domiciled S&P 500 ETF shows as US, not Ireland)
- Sector Breakdown -- GICS sectors across your entire portfolio
- Stock Overlap -- stocks appearing in 2+ funds, with fund similarity percentages
- Fee Analysis -- weighted TER vs cheapest passive alternative, with annual savings in your currency
- Top Holdings -- your 30 largest underlying positions
Tech stack
- Backend: Python/FastAPI
- Data: 13 async factsheet fetchers (iShares CSV exports, JustETF, FT.com, Gerifonds PDF parsing, and 9 more)
- Cache: 24h disk-backed JSON + in-memory LRU (500 entries). Popular funds return in under 100ms, cold starts take 15-30s
- PDF: ReportLab for 6-page PDF reports (email-gated)
- Frontend: Vanilla HTML/CSS/JS, no framework
- Hosting: Single Ubuntu server, systemd service, nginx reverse proxy
The interesting technical bits
Name normalization was harder than expected. The same company appears as "Nestle SA", "Nestle AG", "NESTLE S.A.", and "Nestlé" across different data sources. I strip accents, remove corporate suffixes (AG, SA, Ltd, Inc, Corp, PLC, Group, Holdings), and normalize whitespace before deduplicating.
Fund-pair overlap uses a Jaccard-like calculation on the intersection of underlying holdings, weighted by position size. This tells you "your MSCI World and S&P 500 ETFs are 78% identical" -- meaning you're paying two sets of fees for nearly the same exposure.
ISIN-based routing determines which fetchers to try first. CH-prefix ISINs go to Swiss sources (Gerifonds, SwissFundData), IE/LU go to JustETF and iShares, and everything falls back through 9 legacy fetchers.
What I couldn't replicate
- Morningstar's style box (3x3 value/growth/blend grid) -- proprietary classification
- P/E and P/B ratios -- would need a real-time data feed
- Performance tracking -- out of scope for a free tool
Also: Property Comps API
Separately, I built an API serving 4.2M+ government-recorded property transactions across 11 markets (UK, France, Dubai, Singapore, NYC, and 6 more). If you're building anything in proptech:
- Swagger docs: api.nwc-advisory.com/docs
- Free tier available
Happy to answer questions about the architecture or data sources.
Top comments (1)
If you want to try it, here are some ISINs to get started:
Paste them at nwc-advisory.com/xray with any amounts. Takes about 15 seconds for the first analysis (cached after that).
Happy to answer any questions about the tech or the data sources.