Backtester per fondi comuni ed ETF: cerca gli strumenti, definisci i pesi del portafoglio, scegli il periodo e vedi quanto sarebbe diventato il tuo capitale — con l'impatto dei costi (TER) evidenziato. Include anche il confronto con i fondi pensione italiani (negoziali, aperti, PIP).
Ci sono due modi, e conviene sceglierli così:
| A · Scarica la release | B · Clona il repository | |
|---|---|---|
| Per chi | Voglio usare l'app | Voglio modificarla, o voglio l'ultima versione |
| Serve | Niente: nessun Python da installare | Python 3.13+ e uv |
| Ottieni | Un'applicazione da avviare con doppio clic | Il codice sorgente, aggiornato all'ultimo commit |
| Pesa | ~105 MB da scaricare | ~500 MB fra ambiente virtuale e dipendenze |
| Sistemi | macOS (Apple Silicon) e Windows | macOS, Windows, Linux |
1. Scarica l'archivio dalla pagina delle release:
👉 https://github.com/giulios123/ComparatoreFondi/releases/latest
In fondo alla pagina, sotto Assets, scegli il file per il tuo sistema:
| Sistema | File | Dimensione |
|---|---|---|
| macOS (Apple Silicon) | ComparatoreFondi-macOS.zip |
~105 MB |
| Windows | ComparatoreFondi-Windows.zip |
~107 MB |
macOS Intel: gli archivi pubblicati sono compilati per Apple Silicon (arm64). Su un Mac Intel serve la strada B, oppure adattare il workflow di build (vedi § Pacchetto standalone).
2. Estrai l'archivio. Doppio clic sul file .zip.
- macOS → ottieni
ComparatoreFondi.app. Trascinala in Applicazioni. - Windows → ottieni la cartella
ComparatoreFondi, che contieneComparatoreFondi.exe. Spostala dove preferisci, ma tienila intera: l'eseguibile ha bisogno dei file che gli stanno accanto.
3. Al primo avvio, sblocca l'app. Le applicazioni non sono firmate digitalmente (il perché è spiegato in § Firma del codice), quindi il sistema avvisa. Succede solo la prima volta:
- macOS — un doppio clic mostra "sviluppatore non identificato". Chiudi l'avviso, poi clic destro sull'app → Apri, e conferma Apri nella finestra che compare.
- Windows — SmartScreen mostra "Windows ha protetto il PC". Clicca Ulteriori informazioni → Esegui comunque.
4. L'app parte. Si apre da sola nel browser predefinito, su http://localhost:8765. La finestra del browser è l'applicazione: chiuderla non spegne il programma, che si chiude dalla sua icona nel Dock (macOS) o dalla finestra del terminale che resta aperta (Windows).
I tuoi dati — cache, chiavi API, preferenze — stanno fuori dall'app, così un aggiornamento non li porta via:
| Sistema | Cartella |
|---|---|
| macOS | ~/Library/Application Support/ComparatoreFondi |
| Windows | %APPDATA%\ComparatoreFondi |
Se l'app non parte, nella stessa cartella trovi comparatore.log con il
motivo dell'ultimo avvio fallito.
Per aggiornare: scarica il nuovo archivio dalla stessa pagina e sostituisci l'applicazione. I dati nella cartella qui sopra restano dove sono.
1. Installa uv, se non ce l'hai già. È il gestore di progetto: si occupa
anche di scaricare Python 3.13 se manca, quindi non serve installarlo a parte.
# macOS e Linux
curl -LsSf https://astral.sh/uv/install.sh | sh# Windows (PowerShell)
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"In alternativa: brew install uv su macOS, pipx install uv ovunque, o gli
altri metodi elencati nella documentazione di uv.
2. Clona il repository ed entra nella cartella:
git clone https://github.com/giulios123/ComparatoreFondi.git
cd ComparatoreFondi3. Installa le dipendenze:
uv syncCrea l'ambiente virtuale in .venv/ e installa tutto quello che serve
(Streamlit, pandas, yfinance, openpyxl, ecc.) leggendo pyproject.toml. La
prima volta scarica qualche centinaio di MB; le volte successive è quasi
istantaneo.
uv sync installa anche gli strumenti di sviluppo (PyInstaller,
pip-licenses, ruff): per uv, quel gruppo è incluso di default. Per il solo
runtime, come su una macchina che deve solo eseguire l'app: uv sync --no-dev.
4. Avvia l'app:
uv run streamlit run app.pySi apre automaticamente il browser su http://localhost:8501. Per fermarla,
Ctrl+C nel terminale.
Per aggiornare:
git pull
uv sync # riallinea le dipendenze se sono cambiatePer eseguire i test:
uv run python -m unittest discover -s tests -p "test_*.py"| Sintomo | Cosa fare |
|---|---|
uv: command not found dopo l'installazione |
Riapri il terminale: uv finisce in ~/.local/bin, che serve al PATH della nuova sessione |
Port 8501 is already in use |
Un'altra istanza è già attiva. Chiudila, oppure usa un'altra porta: uv run streamlit run app.py --server.port 8502 |
| Il browser non si apre da solo | Vai a mano su http://localhost:8501 (da sorgente) o http://localhost:8765 (app scaricata) |
| L'app scaricata non parte con doppio clic | Leggi comparatore.log nella cartella dati utente indicata sopra |
| Un fondo non produce dati | Apri 📚 Fonti usate sotto la tabella: l'app dichiara quali fonti ha provato e come è andata |
L'interfaccia è disponibile in italiano, inglese, francese e tedesco: alla prima apertura viene scelta in base alla lingua del browser (o del sistema operativo nell'app desktop), ed è sempre cambiabile dal selettore in cima alla barra laterale. La scelta viene ricordata fra un avvio e l'altro.
- Apri il pannello 🔎 Cerca fondi ed ETF in cima alla pagina.
- Digita un nome (
Vanguard S&P 500), un ticker (VUSA.AS) o un ISIN (IE00B3XXRP09) — l'ISIN è il modo più affidabile, soprattutto per i fondi europei. - Nei risultati, premi Aggiungi sulla riga giusta.
- Ripeti per ogni fondo del portafoglio.
Il fondo compare nella tabella Composizione del portafoglio, dove puoi modificare:
- Peso % — quota del capitale assegnata. I pesi sommano sempre a 100%: modificandone uno, gli altri si adeguano da soli in proporzione fra loro (il pulsante ⚖️ Pesi uguali azzera invece tutto a una ripartizione paritaria);
- Importo — lo stesso peso espresso in euro (o nella valuta di riferimento scelta in barra laterale). Modificarlo aggiorna sia i pesi sia il valore iniziale del portafoglio: ad esempio, con due fondi al 50% su 10.000€, portare il primo importo a 2.000€ dà pesi 22%/78% e un capitale totale di 7.000€, con pesi 28,57%/71,43% — il secondo fondo resta a 5.000€ investiti;
- TER % — precompilato quando la fonte lo espone, ma verifica sempre sul KID del fondo e correggilo se serve;
- Costi extra % — per costi non già inclusi nel NAV (custodia, consulenza);
- ISIN — compilalo se manca: permette di usare justETF dopo l'opt-in nelle fonti dati o selezionandolo esplicitamente sul singolo fondo;
- Fonte — normalmente su "Automatica"; forzala solo se vuoi diagnosticare da dove arrivano i dati di un fondo specifico;
- Proxy storico — vedi Storico esteso.
Ogni riga della tabella ha un pulsante 🗑️ nella prima colonna: un clic toglie il fondo, nessuna conferma. Il capitale resta investito — i pesi dei fondi rimasti si ridistribuiscono mantenendo le loro proporzioni reciproche, mentre il valore iniziale del portafoglio non cambia. 🗑️ Svuota, sotto la tabella, azzera invece tutto il portafoglio.
Tutto nella barra laterale a sinistra:
- Periodo: pulsanti rapidi
1a · 5a · 10a · 20a · Max, oppure le due date a mano. - Valore iniziale del portafoglio e Valuta di riferimento: cambiare il capitale qui riscala tutti gli importi per fondo mantenendo i pesi invariati (è l'operazione inversa a quella descritta al punto 1).
- Ribilanciamento: nessuno (buy & hold), mensile, trimestrale, annuale — vedi il tooltip ⓘ accanto al menu per la spiegazione completa. In breve: senza ribilanciamento i pesi impostati sono solo il punto di partenza e derivano nel tempo con i rendimenti relativi dei fondi (chi cresce di più finisce per pesare di più); con un ribilanciamento periodico, i pesi tornano a quelli impostati a ogni inizio periodo. Il backtest non applica commissioni di negoziazione né tassazione sulle plusvalenze, quindi ribilanciare spesso qui risulta più conveniente di quanto sarebbe nella realtà. Nella scheda 📊 Portafoglio, sotto Composizione nel tempo, una riga di testo mostra l'effetto concreto: quanto sono derivati i pesi (buy & hold) oppure quanti ribilanciamenti sono scattati nel periodo.
Il grafico e le metriche si aggiornano da soli. Se i pesi non sommano a 100% l'app li normalizza e te lo segnala.
La barra laterale si può restringere trascinandone il bordo, per lasciare più spazio ai grafici. Le etichette lunghe vanno a capo, ma i pulsanti dei periodi no: restano leggibili su una riga anche alla larghezza minima.
Nella barra laterale, sotto Ribilanciamento, l'espansore 📅 Versamenti periodici (PAC) è chiuso e disattivato di default: senza aprirlo l'app si comporta esattamente come senza questa sezione.
Attivandolo si configurano:
- Importo per versamento e Frequenza (mensile, trimestrale, annuale);
- Rivalutazione annua della rata (%), per farla crescere di una percentuale
fissa ogni anno (ad esempio per seguire l'inflazione o lo stipendio). Si
scrive in percentuale, come il tasso risk-free e i costi della tabella di
composizione:
3significa +3% all'anno; - Limita i versamenti a un periodo, per versare solo fra due date invece che per tutto l'orizzonte del backtest.
Ogni rata entra ai pesi impostati il primo giorno di borsa del periodo successivo al capitale iniziale: è di fatto un ribilanciamento morbido, quindi anche con "Nessuno" il portafoglio deriva un po' meno di quanto farebbe senza PAC.
Con il PAC attivo compaiono, accanto ai cinque KPI abituali, quattro metriche in più:
- Saldo finale — quanto vale il portafoglio a fine periodo, versamenti inclusi;
- Versato — capitale iniziale più tutti i versamenti fatti;
- Guadagno — saldo finale meno il versato;
- XIRR — il rendimento annuo del tuo denaro, che tiene conto di quando è entrato ogni versamento (a differenza del CAGR, che assume un capitale unico investito il primo giorno).
Nel grafico del portafoglio compaiono anche la curva del versato cumulato e la linea PIC: lo stesso denaro totale versato tutto in un'unica soluzione il primo giorno. È il termine di paragone naturale del PAC — quanto è costato, o ha risparmiato, diluire l'ingresso nel tempo — ed è un confronto ipotetico, perché presuppone di avere avuto subito tutta la somma.
CAGR, volatilità, Sharpe, Sortino e drawdown restano invece calcolati sul rendimento dello strumento al netto dei versamenti: un PAC non falsa queste metriche facendo apparire ogni versamento come un guadagno di mercato. Vale in ogni scheda: nel Confronto fondi ogni riga riceve lo stesso capitale e lo stesso piano di versamenti, il valore finale è il saldo vero e le metriche di rischio/rendimento sono al netto delle rate (con l'XIRR come colonna in più); nel Drawdown valgono le stesse curve depurate, così un versamento non risale un drawdown come farebbe un rimbalzo di mercato.
Nella scheda 🏦 Fondi pensione il PAC cambia tre cose, e una didascalia lo ricorda: le curve sintetiche dei comparti ricevono lo stesso piano di versamenti, il confronto con i rendimenti COVIP usa il rendimento al netto dei versamenti (è così che COVIP calcola i propri) e la tabella dei costi ISC ragiona sulla tua rata per dieci anni — l'erosione conta ogni rata solo per il tempo in cui è davvero investita, e una colonna in più proietta il montante a 10 anni versando lo stesso PAC. Quella proiezione tiene la rata costante: la rivalutazione annua non vi entra.
L'expander 🎯 Benchmark e analisi comparative e' facoltativo. Si puo'
scegliere nessun riferimento, uno dei preset total-return VT e VFINX,
cercare uno strumento oppure aprire il sottomenu Portafogli famosi. Il
popover contiene 25 strategie, una ricerca e un tooltip nativo con composizione,
proxy e avvertenze; la scheda del selezionato resta visibile anche senza hover.
I portafogli compositi usano proxy quotati in EUR, capitale e PAC uguali al
portafoglio e ribilanciamento annuale al primo giorno di mercato. ALLW, RPAR e
TRTY restano strumenti singoli gestiti internamente. Il benchmark resta fuori
da holdings, pesi, TER, costi e ribilanciamento dell'utente; un componente
mancante rende indisponibile soltanto il benchmark. Il confronto usa soltanto
il periodo comune realmente coperto, senza backfill o rinormalizzazione.
Sono disponibili CAGR, rendimento attivo, tracking error, information ratio,
correlazioni dei rendimenti mensili e rendimenti rolling a 1, 3, 5 e 10 anni.
La scelta viene salvata nell'export JSON; i file precedenti restano validi.
L'expander 📉 Rendimento reale e inflazione e' spento di default e usa il HICP mensile ufficiale Eurostat per Italia o area euro. Mostra fonte, area, copertura e ultimo mese disponibile, oltre a curva, rendimento totale e CAGR reali. Con un PAC deflaziona separatamente il saldo e ogni versamento; nessun valore futuro viene stimato. Un errore o un ritardo della fonte lascia disponibile il backtest nominale.
Sopra le schede trovi la composizione del portafoglio e le metriche di sintesi del periodo:
Le schermate di questa guida usano due serie di esempio caricate da CSV, non fondi reali: servono a mostrare l'interfaccia, non a suggerire un investimento.
Otto schede sotto il grafico principale:
| Scheda | Cosa mostra |
|---|---|
| 📊 Portafoglio | curva del capitale, netta e lorda (senza TER), composizione nel tempo |
| ⚖️ Bilanciamento | ripartizione per classe di attivo, area, settore, valuta e paesi (stima) |
| 🆚 Confronto fondi | ogni fondo preso da solo, a parità di capitale investito |
| 📊 Analisi | heatmap dei rendimenti, finestre rolling e frontiera storica dei pesi |
| 📉 Drawdown | perdita dal massimo storico, e rendimenti per anno solare |
| 📋 Dati | tabella numerica scaricabile in CSV |
| 🏦 Fondi pensione | confronto con le finestre ufficiali COVIP |
| 🧭 Diagnosi | rilievi locali rispetto al profilo facoltativo |
Ogni metrica in alto (Valore finale, CAGR, Volatilità, Max drawdown, Sharpe) ha un tooltip ⓘ con la spiegazione; l'expander ❓ Come si leggono queste metriche, subito sotto, elenca anche Sortino e Calmar. Nella scheda 🆚 Confronto fondi, la tabella confronta ogni fondo preso da solo con il portafoglio: una didascalia sopra ricorda che tutte le righe partono dallo stesso capitale, quindi i valori finali sono confrontabili direttamente riga per riga.
Il riquadro 💸 Impatto del TER quantifica in euro quanto i costi correnti sono costati rispetto al fondo ipotetico senza commissioni.
La scheda 📊 Analisi ricostruisce lo storico indipendentemente dalle date
del backtest per non perdere il pregresso necessario alle finestre lunghe. La
Return heatmap mostra i mesi e il rendimento annuo composto, lasciando
— dove mancano dati e marcando i periodi parziali e l'anno corrente (YTD).
Rolling returns offre le modalità Continuous, Annual e Distribution per
finestre di 1, 3, 5, 10, 15 e 20 anni e per CAGR, volatilità, Sharpe, Sortino,
Calmar e Ulcer Index; le finestre sovrapposte della distribuzione non sono
osservazioni indipendenti. Le serie mantengono coperture proprie e il PAC
influisce sulla ricostruzione, mentre i rendimenti sono depurati dai
versamenti. La scheda mostra anche la fonte effettivamente usata per ogni
serie: provider diversi possono restituire rendimenti diversi; per un confronto
numerico omogeneo va selezionata la stessa fonte nella composizione.
La Frontiera storica valuta mix non negativi dei soli fondi già presenti, con gli stessi prezzi netti, PAC e ribilanciamento del backtest. Il campionamento è riproducibile (seed fisso), i limiti min/max sono editabili e i risultati sono presentati come migliori mix trovati sullo storico, non come previsioni. Un mix può essere esportato come variante JSON e applicato solo dopo anteprima e conferma; la scheda mostra fonte e copertura effettive usate dalla ricerca; il benchmark resta sempre esterno alle holdings. Il grafico evidenzia con stelle i casi migliori e con X i peggiori per CAGR, volatilità, Sharpe e drawdown; ogni marcatore mostra nel tooltip pesi e metriche del mix.
Nella scheda 📊 Portafoglio, la curva continua è il capitale netto e quella tratteggiata il lordo: la distanza fra le due è il costo del TER. Sotto, la composizione nel tempo mostra come i pesi si sono mossi.
Nessuna fonte, da sola, copre tutti i casi. In modalità automatica l'app le prova in ordine e si ferma alla prima che risponde, dicendo sempre quale ha usato.
| Ordine | Fonte | Copre | Attivazione |
|---|---|---|---|
| 1 | CSV caricato | qualsiasi cosa, incluso ciò che nessuno espone | caricamento locale |
| 2 | Yahoo Finance | fonte generalista, unica con ricerca testuale | automatica |
| 3 | EODHD | fondi comuni ed ETF europei, TER affidabile | chiave personale |
| 4 | Twelve Data | 50+ mercati | chiave personale |
justETF non fa parte dell'ordine automatico predefinito: usa un endpoint
interno e non documentato. È disponibile solo attivando il relativo opt-in
nella barra laterale oppure scegliendo esplicitamente justETF come fonte del
singolo fondo. Prima del consenso, l'interfaccia indica esattamente cosa viene
inviato: ISIN, intervallo, valuta, indirizzo IP e normali metadati HTTP; non
vengono trasmessi capitale, pesi, CSV o chiavi API. Il consenso automatico è
ricordato su questo computer fra i riavvii ed è revocabile in qualsiasi momento
deselezionando la casella. Yahoo funziona
senza configurazione; EODHD e Twelve Data si attivano quando configuri una
chiave personale.
Quando una serie non arriva, l'app mostra cosa ha tentato e come è andata, invece di lasciare un grafico vuoto senza spiegazione.
La licenza Apache-2.0 di questo repository copre il codice del progetto, non concede diritti aggiuntivi sui dati ottenuti dai servizi esterni. Ogni utente è responsabile di usare la propria chiave e un piano compatibile con il proprio caso d'uso:
- yfinance è Apache-2.0, ma ricorda che i dati Yahoo Finance sono destinati all'uso personale; valgono anche i termini Yahoo API;
- justETF non espone un'API pubblica per questa funzione: l'integrazione è sperimentale, opt-in e soggetta alle condizioni justETF e ai diritti dei fornitori dei dati;
- i piani ordinari EODHD sono per uso personale e vietano redistribuzione o display a terzi senza approvazione: consulta i termini EODHD;
- il free tier Twelve Data non consente uso commerciale e redistribuzione o display esterno richiedono diritti specifici: consulta i termini Twelve Data;
- gli identificatori OpenFIGI sono dedicati al pubblico dominio secondo i termini OpenFIGI;
- i dataset COVIP sono CC BY 4.0 e i cambi BCE richiedono attribuzione della fonte; i dettagli delle elaborazioni sono indicati nelle sezioni dedicate.
Pubblicare, ospitare o monetizzare un'istanza multiutente può quindi richiedere piani commerciali o autorizzazioni separate, anche se il codice resta open source.
L'expander ℹ️ Informazioni e licenze in barra laterale mostra la licenza
del progetto, una tabella di tutte le librerie di terze parti con la loro
licenza, e il link per scaricare il testo completo (THIRD_PARTY_NOTICES.txt,
generato da scripts/generate_third_party_notices.py).
L'expander 💼 Portafoglio: salva e carica in barra laterale permette sia di
importare sia di scaricare un file .json con fondi, pesi, costi, fonte e
proxy, oltre ai parametri usati (periodo, valuta, capitale iniziale,
ribilanciamento, storico esteso, tasso risk-free). Il download resta
disponibile anche quando il backtest non può essere eseguito: riaprendo il
file si ottiene lo stesso portafoglio, indipendentemente dalla lingua
dell'interfaccia in cui è stato esportato o viene importato. Il CSV nella
scheda Dati esporta invece soltanto le serie dei risultati del backtest.
Servono solo se vuoi coprire fondi che Yahoo e justETF non hanno — tipicamente fondi collocati dalle reti italiane (Mediolanum, Fineco, banche). Yahoo ne copre solo una parte, con storico fermo al 2018.
-
Registrati e ottieni una chiave gratuita da:
- eodhd.com per EODHD;
- twelvedata.com per Twelve Data.
-
Nella barra laterale, sotto Fonti dati, apri 🔑 Chiavi API (EODHD, Twelve Data), incolla la chiave e premi Salva. Non serve riavviare: il pallino accanto alla fonte passa da ⚪ a 🟢 subito. Basta compilare le chiavi che hai — se ne manca una, quella fonte resta semplicemente spenta. Sotto il form compare un riepilogo con il provider e solo gli ultimi quattro caratteri di ogni chiave salvata.
La chiave viene scritta in
.streamlit/api_keys.json, con permessi riservati al tuo utente (chmod 600), e resta lì fra un avvio e l'altro dell'app — Svuota cache non la tocca. È pensato per un uso in locale, a utente singolo: se l'app viene deployata ed è raggiungibile da più persone, quel file sarebbe condiviso da tutti i visitatori, quindi in quel caso conviene la via alternativa qui sotto. Il file è già in.gitignore: non finisce mai nel repository. Il pulsante Dimentica le chiavi salvate, nello stesso pannello, rimuove le credenziali e cancella immediatamente anche le cache EODHD e Twelve Data, senza toccare le altre fonti.
In alternativa (o se preferisci non salvare nulla su disco), le chiavi si possono impostare anche fuori dall'interfaccia — e in tal caso hanno la precedenza più bassa, cioè valgono solo finché non ne inserisci una dall'interfaccia:
-
.streamlit/secrets.tomlnella cartella del progetto (la cartella.streamlit/va creata se non esiste già):EODHD_API_KEY = "la-tua-chiave-eodhd" TWELVEDATA_API_KEY = "la-tua-chiave-twelvedata"
Anche questo file è già in
.gitignore. -
Variabili d'ambiente, prima di avviare:
export EODHD_API_KEY="la-tua-chiave-eodhd" export TWELVEDATA_API_KEY="la-tua-chiave-twelvedata" uv run streamlit run app.py
Ordine di precedenza: interfaccia → secrets.toml → variabile d'ambiente.
Le serie e i metadati EODHD/Twelve Data vengono eliminati automaticamente dopo
al massimo 30 giorni. La retention può solo essere ridotta, impostando
COMPARATORE_RESTRICTED_CACHE_DAYS a un valore fra 1 e 30. Alla cessazione di
un abbonamento resta responsabilità dell'utente rispettare gli eventuali
obblighi di cancellazione previsti dal provider.
Per i fondi comuni non quotati che nessuna fonte gratuita copre (tipico caso: un fondo interno di una banca, senza ISIN pubblico su Yahoo/justETF).
-
Nella barra laterale, apri 📄 Carica una serie da CSV.
-
Indica il simbolo o ISIN a cui associarla (deve corrispondere a quello che userai per aggiungere il fondo dalla ricerca, o puoi crearlo tu come codice interno).
-
Scegli la valuta della serie.
-
Carica il file CSV: due colonne, data e valore della quota. Non serve preoccuparsi del formato esatto — separatore (
;o,), decimale (virgola o punto) e formato data vengono riconosciuti da soli, compresi i formati italiani (GG/MM/AAAA, virgola decimale). Esempio valido:Data;NAV 02/01/2020;12,3456 03/01/2020;12,4010 06/01/2020;12,3900
Una volta caricata, la serie ha priorità massima: se aggiungi un fondo con quello stesso simbolo o ISIN, l'app userà i tuoi dati invece di cercarli altrove.
La scheda 🏦 Fondi pensione, in fondo alle schede dei risultati, confronta il tuo portafoglio con la previdenza complementare italiana: 471 comparti fra 33 fondi negoziali, 38 aperti e 71 PIP, dati COVIP (CC BY 4.0), con rendimenti e Indicatore Sintetico dei Costi (ISC). Il progetto modifica la rappresentazione originale: normalizza nomi e categorie, unisce albo, rendimenti e ISC e calcola confronti, impatto dei costi e curve sintetiche.
- Costruisci prima il tuo portafoglio come al solito (fondi, pesi, periodo).
- Apri la scheda 🏦 Fondi pensione.
- Filtra per tipo (negoziale / aperto / PIP), categoria (azionario,
bilanciato, obbligazionario, garantito) o cerca per nome — es.
mediolanum,cometa,previgest. - Seleziona uno o più comparti nel menu Comparti da confrontare.
Compaiono una tabella con i rendimenti a 1/3/5/10/20 anni affiancati a quelli del tuo portafoglio, un grafico a barre, e una tabella separata sull'impatto dell'ISC.
COVIP pubblica rendimenti medi annui su orizzonti fissi, non le serie storiche giorno per giorno. Per questo, per i fondi pensione non sono calcolabili curva del capitale, drawdown, volatilità, Sharpe o Calmar: non è una scelta dell'app, è che il dato non esiste pubblicamente. Chi lo vuole può scaricare il valore quota dal sito del proprio fondo e caricarlo con l'uploader CSV descritto sopra.
Il confronto usa le stesse finestre pubblicate da COVIP (es. 2016-2025,
non "ultimi dieci anni da oggi"): le date sono scritte nell'intestazione di
ogni colonna, perché sono finestre chiuse e indipendenti, non periodi
cumulativi. Un rendimento a 10 anni più basso di quello a 5 significa quindi
che la prima metà del decennio ha reso meno, non che il fondo sia peggiorato
di recente.
Le finestre sono anni solari interi, dal 1° gennaio al 31 dicembre: un
backtest agosto 2021 → luglio 2025 non copre la finestra 5 anni = 2021-2025,
anche se gli anni di calendario sembrano gli stessi. Se il portafoglio non copre
l'intera finestra, quella cella mostra n/d invece di un numero calcolato su un
periodo più corto e non realmente confrontabile.
In quel caso, sotto la tabella, l'app mostra comunque il rendimento medio annuo
del portafoglio sul suo periodo — dichiarato non confrontabile, serve ad
avere un ordine di grandezza — e offre un pulsante che porta le date del
backtest esattamente sulle finestre COVIP. Il backtest parte comunque dalla
prima data in cui tutti i fondi selezionati hanno dati, quindi con un fondo
recente le finestre più lunghe restano n/d.
Puoi anche sovrapporre al grafico principale una curva sintetica per ogni comparto scelto (interruttore in fondo alla scheda, spento di default): è una crescita costante ricavata dal rendimento medio, utile per un colpo d'occhio, ma non un andamento reale — il percorso vero ha oscillato, e per questo non entra nel calcolo delle metriche di rischio.
Il confronto non considera la fiscalità: deducibilità dei versamenti, tassazione agevolata dei rendimenti e dell'imposta finale sono vantaggi reali dei fondi pensione che qui non vengono modellati, quindi i numeri mostrati li sottostimano rispetto alla realtà.
La scheda ⚖️ Bilanciamento risponde a "come è ripartito quello che ho", non a "quanto avrei guadagnato": cinque ciambelle con la ripartizione per classe di attivo, area geografica, settore, valuta di quotazione e paesi (stima), calcolate sui pesi impostati nella tabella di composizione.
Nessuna fonte di prezzo dice che cosa sia uno strumento, quindi il dato viene ricostruito da tre sorgenti, in quest'ordine:
| Sorgente | Quando interviene | Che qualità ha |
|---|---|---|
| EODHD | se hai configurato la chiave (serve un piano che includa /fundamentals) |
percentuali vere e granulari: un ETF mondiale risulta ripartito su più aree e più settori |
| Yahoo Finance | sempre, su ETF e fondi comuni riconosciuti come tali, senza bisogno di chiave | classe di attivo e settori reali, più le prime 10 posizioni — ma mai l'area geografica, che Yahoo non espone |
| nome del fondo | sempre, per le dimensioni che le due sopra non coprono | un'etichetta sola per dimensione, dedotta da parole chiave ("Eurozone Government Bond" → obbligazionario, Europa) |
Le tre si sommano invece di escludersi: EODHD vince quando copre una dimensione, Yahoo colma quelle che EODHD non ha (tipicamente l'area), il nome completa quel che resta — un obbligazionario non ha settori da nessuna delle prime due, e su quella dimensione la deduzione dal nome resta meglio di un buco. La provenienza è dichiarata sopra i grafici.
L'expander 📌 Principali posizioni elenca, per ogni fondo che Yahoo riconosce come ETF o fondo comune, le sue prime 10 posizioni con il peso nel fondo — utile anche per vedere le sovrapposizioni fra fondi diversi (VWCE e un ETF tecnologico condividono spesso gli stessi titoli in testa).
La ciambella Paesi nasce da quelle stesse posizioni: il suffisso di borsa
del simbolo (.TW → Taiwan, .HK → Hong Kong, nessun suffisso alfabetico →
Stati Uniti…) stima il paese di ciascuna. È dichiaratamente parziale — le
prime 10 coprono di solito un quinto o un quarto del fondo — e la quota non
coperta resta esplicita in "Resto del fondo", in grigio come "Non
classificato", invece di essere spalmata sulle altre voci o ignorata. Una
ripartizione geografica completa richiede l'area di EODHD, cioè un piano a
pagamento.
La tabella Classificazione sotto i grafici ha una tendina per dimensione
(classe, area, settore — non il paese, che resta solo una stima e non è
correggibile a mano). Il valore (automatica) conserva la classificazione
dedotta, che può ripartirsi su più voci; scegliendo una voce esplicita le si
attribuisce l'intero strumento. L'expander 🔍 Dettaglio per strumento
mostra la ripartizione effettiva riga per riga, comprese quelle su più voci.
- La classificazione automatica è indicativa: va verificata sul KID. Senza EODHD (a chiave) e senza dati di composizione da Yahoo si basa solo sul nome, che spesso non basta — uno strumento non riconosciuto finisce in "Non classificato", visibile in grigio nel grafico invece di sparire da un totale che non chiuderebbe.
- La valuta è quella di quotazione, non l'esposizione valutaria: un ETF sul mercato mondiale quotato in euro resta esposto al dollaro.
- La ripartizione per paese è una stima sulle sole prime posizioni, non una ripartizione geografica vera: non confonderla con quella per area, che quando arriva da EODHD copre l'intero fondo.
- Il perimetro sono i fondi e gli ETF della tabella di composizione. I comparti COVIP della scheda 🏦 restano un confronto e non entrano nella ripartizione.
- I pesi usati sono quelli impostati, normalizzati a 100% come nel backtest, non quelli derivati a fine periodo.
I NAV pubblicati sono già al netto del TER. La commissione di gestione viene addebitata giorno per giorno dentro il NAV: se un fondo dichiara +10% di rendimento, quel +10% è già al netto delle spese correnti. Sottrarre di nuovo il TER dalla performance storica significa contarlo due volte.
L'app quindi lavora con due curve:
| Curva | Significato |
|---|---|
| Netta | La serie così com'è pubblicata: quello che l'investitore ha realmente ottenuto. |
| Lorda | Il TER ri-aggiunto sopra, cioè il fondo ipotetico senza commissioni. |
La distanza fra le due curve è esattamente il costo del TER, ed è quello che il riquadro "Impatto del TER" quantifica in euro e in percentuale.
C'è poi la colonna Costi extra % per i costi che il NAV non contiene già — commissioni di custodia, consulenza, oppure il TER di una classe diversa da quella quotata. Questi vengono sottratti dalla performance.
La formula applicata è la capitalizzazione della commissione nel tempo:
fattore(t) = (1 - tasso_annuo) ^ (giorni_trascorsi / 365.25)
Il TER precompilato arriva dalla fonte quando disponibile, ma la copertura
sui fondi europei è scarsa e i valori sono arrotondati (Yahoo riporta 0.00
per un TER reale dello 0,07%). Verifica sempre il TER sul KID e correggilo a
mano: il campo è editabile.
I cambi sono quelli ufficiali BCE, disponibili dal 4 gennaio 1999 e ottenuti tramite l'API open source Frankfurter, con ripiego su Yahoo per le valute fuori dal paniere BCE. Le serie vengono riallineate ai giorni del portafoglio e riportate in avanti nei giorni senza nuova rilevazione; la BCE resta la fonte dei tassi e richiede che venga citata quando i dati sono riprodotti.
Prima della prima data disponibile non si inventa nulla: il periodo viene accorciato e l'app lo segnala esplicitamente, invece di usare un cambio retro-riempito su anni in cui non è mai stato quotato.
Gli ETF UCITS sono giovani: VWCE quota dal 2019, VUSA dal 2012. Attivando Storico esteso, nella barra laterale, il periodo precedente viene ricostruito con uno strumento più anziano (il proxy), agganciato con continuità al primo dato reale del fondo.
I proxy predefiniti sono vecchie classi di fondi, non indici, perché con i dividendi reinvestiti sono serie total return — un indice di solo prezzo sottostimerebbe il rendimento ricostruito di circa 2 punti l'anno. L'app propone il proxy in base al nome del fondo (colonna Proxy storico nella tabella), e lo lascia sempre correggere o disattivare per singolo fondo.
Il tratto ricostruito è una stima, non un dato reale: compare tratteggiato nei grafici, la tabella delle metriche lo segnala nella colonna Ricostruito, e l'estensione è spenta di default.
Due limiti da conoscere:
- I proxy sono quotati in dollari, quindi con valuta di riferimento diversa da USD la ricostruzione non può scendere sotto il 1999 (prima data dei cambi BCE), per quanto profondo sia il proxy. In USD si arriva al 1980.
- Un proxy che ha smesso di quotare prima della nascita del fondo viene rifiutato: l'ancoraggio userebbe un valore vecchio di mesi.
Le serie scaricate finiscono in .cache/ in formato parquet. Per Yahoo,
justETF, cambi e CSV la cache è accumulativa: ogni file contiene tutto lo
storico mai scaricato per quella combinazione di fonte, simbolo e valuta, non
la singola finestra richiesta. EODHD e Twelve Data seguono invece una policy
ristretta: serie e metadati vengono eliminati dopo al massimo 30 giorni e un
dato scaduto non viene usato neppure come ripiego offline.
Si svuota con il pulsante Svuota cache nella barra laterale. La posizione
è sovrascrivibile con la variabile d'ambiente COMPARATORE_CACHE_DIR. Le
chiavi API salvate dall'interfaccia vivono altrove
(.streamlit/api_keys.json, vedi sopra) e non vengono toccate da questo
pulsante.
Questa sezione riguarda chi costruisce il pacchetto. Per scaricarlo e usarlo basta la § A · Installazione da release.
Il progetto puo' essere impacchettato in un eseguibile che non richiede Python
installato, tramite PyInstaller. I file coinvolti
sono in desktop/:
desktop/launcher.py— entry point del bundle: avvia il server Streamlit e apre il browser, come farebbestreamlit run app.py. Reindirizza anche cache e chiavi API dentro la cartella dati dell'utente (~/Library/Application Support/ComparatoreFondisu macOS,%APPDATA%su Windows), perche' dentro un bundle installato la cartella del codice e' di sola lettura.desktop/comparatore.spec— configurazione del build. Un solo file serve entrambe le piattaforme; rigenera e includeLICENSEeTHIRD_PARTY_NOTICES.txtper le dipendenze effettive della piattaforma.
uv sync --group dev
uv run pyinstaller desktop/comparatore.spec --noconfirm --cleanRisultato in dist/: ComparatoreFondi.app su macOS, la cartella
ComparatoreFondi/ (con ComparatoreFondi.exe) su Windows. La build CI su
macos-latest produce un .app arm64 (Apple Silicon); per Intel/universal
serve adattare il workflow.
Se l'app non parte da Finder/Esplora risorse, il log dell'ultimo avvio e' in
comparatore.log nella stessa cartella dati utente citata sopra.
Il workflow .github/workflows/desktop-build.yml
builda entrambe le piattaforme su GitHub Actions:
- manuale — tab Actions del repo -> Build desktop (macOS + Windows) -> Run workflow; gli archivi si scaricano come artefatti della run;
- su tag —
git tag v0.3.0 && git push origin v0.3.0builda entrambe le piattaforme e pubblica una GitHub Release con i due.zipallegati.
Il tag deve avere tre componenti. Il trigger è
v*.*.*:v0.3.0lo soddisfa,v0.2no. Un tag a due componenti non fa partire nulla e la release va poi completata a mano con una run manuale del workflow.
Il workflow License audit esegue inoltre la scansione a ogni push su main e
su ogni pull request, su Linux, macOS e Windows. Ogni licenza non inclusa
nell'allowlist verificata viene bloccata e richiede revisione; PyInstaller è
ammesso per la specifica Bootloader Exception, che non impone GPL al programma
impacchettato.
Le app prodotte oggi non sono firmate: al primo avvio macOS e Windows mostrano un avviso, e vanno sbloccate una volta sola con i passi descritti in § A · Installazione da release. Per uso personale o con pochi utenti fidati e' un fastidio, non un blocco reale.
Per togliere questi avvisi servono due iscrizioni distinte e a pagamento, indipendenti fra loro:
- macOS: Apple Developer Program, 99 $/anno. Serve sia per firmare che per notarizzare (Apple scansiona il binario e rilascia un ticket che Gatekeeper controlla); senza notarizzazione l'avviso resta anche con un certificato valido.
- Windows: un certificato di code signing (OV o EV) da una CA riconosciuta (DigiCert, SSL.com, ecc.), tipicamente 70-250 $/anno. Con un certificato OV normale, SmartScreen continua comunque a mostrare l'avviso finche' l'eseguibile non accumula una "reputazione" (download e utilizzo nel tempo); un certificato EV aggira questo periodo di attesa ma costa di piu'.
Nessuno dei due e' legato all'altro: puoi firmare solo macOS, solo Windows, o nessuno dei due, senza cambiare nulla nel workflow di build oltre ad aggiungere le credenziali come segreti del repository quando/se deciderai di procedere.
app.py interfaccia Streamlit
AGENTS.md istruzioni per chi (o cosa) lavora sul codice
CLAUDE.md rimando ad AGENTS.md, più le note specifiche di Claude Code
docs/
images/ screenshot usati da questo README
memory-bank/ perché le cose sono come sono: decisioni, architettura, stato
spec-driven/ il processo: spec → piano → attività → codice
.streamlit/
config.toml barra Streamlit senza Deploy/Rerun (committato)
secrets.toml chiavi API, alternativa al pannello (gitignored)
api_keys.json chiavi API salvate dal pannello (gitignored)
prefs.json preferenze di interfaccia, es. lingua e opt-in justETF (gitignored)
comparatore/
sources/
base.py interfaccia comune alle fonti
yahoo.py ricerca, metadati, prezzi
justetf.py ETF europei per ISIN
eodhd.py EOD Historical Data (a chiave)
twelvedata.py Twelve Data (a chiave)
csv_source.py serie caricate dall'utente
openfigi.py risoluzione ISIN -> ticker
registry.py priorità, ripiego, diagnostica
locales/
it.py, en.py, fr.py, de.py cataloghi di traduzione (it è il riferimento)
i18n.py rilevamento lingua, traduzione, etichette di dominio
prefs.py preferenze salvate dall'interfaccia (lingua e opt-in justETF)
licenses.py accesso a LICENSE / THIRD_PARTY_NOTICES.txt
portfolio_io.py export/import di un portafoglio in JSON
fx.py cambi BCE con ripiego Yahoo
allocazione.py classe di attivo, area, settore e stima paesi per il bilanciamento
cache.py cache parquet accumulativa
keys.py chiavi API salvate dall'interfaccia
proxies.py estensione dello storico
covip.py fondi pensione: catalogo, rendimenti, ISC
horizons.py rendimenti sulle finestre COVIP
engine.py logica commissioni, simulazione, ribilanciamento
metrics.py metriche di performance
data.py facciata sui nomi storici
I moduli in comparatore/ non importano Streamlit e sono usabili da script:
import datetime as dt
from comparatore.sources import Registry
reg = Registry()
res = reg.resolve("IE00B3XXRP09", dt.date(2010, 1, 1), dt.date.today(),
"EUR", isin="IE00B3XXRP09")
print(res.series.source, len(res.series.prices))AGENTS.md— comandi, confini architetturali e regole da rispettare. È il primo file da leggere, e vale sia per le persone sia per gli assistenti di codice.docs/memory-bank/— il perché delle scelte fatte finora, con il registro delle decisioni. Prima di rimettere in discussione un vincolo, quasi sempre la risposta è già lì.docs/spec-driven/— il processo per le funzionalità nuove: prima la spec, poi il piano, poi il codice.
- Prezzi total return: i dividendi sono reinvestiti, quindi fondi ad accumulazione e a distribuzione sono confrontabili.
- Il backtest parte dalla prima data in cui tutti i fondi hanno dati; se un fondo è più giovane del periodo richiesto l'app lo segnala. Lo storico esteso attenua il problema ma non lo elimina.
- I NAV mancanti vengono riportati in avanti (
ffill), come è corretto per i fondi che non quotano tutti i giorni. - Non sono considerati: costi di ingresso/uscita, spread denaro-lettera, fiscalità, inflazione.
- Un fondo la cui valuta non è risolvibile viene escluso anziché mescolato a valute diverse.
Le performance passate non sono indicative di quelle future. Questo strumento è di analisi, non una consulenza finanziaria.
Copyright 2026 Giulio Sciarappa.
Il codice di Comparatore Fondi è distribuito sotto Apache License 2.0. Le licenze, gli avvisi e i collegamenti al codice sorgente delle dipendenze distribuite nel bundle sono raccolti in THIRD_PARTY_NOTICES.txt. I dati recuperati dai provider restano soggetti ai rispettivi termini e non sono relicenziati da Apache-2.0.



