Ogni guida sulla conversione di valute in Power BI appartiene a uno di due schieramenti. Lo schieramento DAX ti mostra una misura elegante e dà per scontato, senza dirlo, che una tabella ExchangeRate esista già nel tuo modello. Lo schieramento API ti mostra uno snippet di Power Query che funziona benissimo in Power BI Desktop e si rompe nell'istante in cui pubblichi, perché l'aggiornamento pianificato lo rifiuta.
Questa guida copre entrambe le metà, nell'ordine: come portare tassi di cambio live in Power BI da un'API REST in modo che sopravviva alla pubblicazione sul servizio Power BI, come modellare quei tassi perché i tuoi numeri siano difendibili, e come convertire gli importi al momento dell'importazione oppure al momento della query, a seconda di ciò che il report richiede davvero.
Tutti gli esempi Power Query e DAX qui sotto sono stati scritti sulle strutture di risposta documentate dell'API Finexly.
Prima decidi quale problema di conversione hai
«Conversione di valute in Power BI» indica tre problemi di ingegneria diversi con lo stesso nome, e scegliere quello sbagliato è l'errore più costoso di tutto l'articolo.
- Molte valute di origine, una valuta di reporting. La tabella vendite ha righe in EUR, GBP e JPY e il CFO vuole un solo numero in USD. Converti all'importazione. Il tasso è una proprietà della transazione, non del report.
- Una valuta di origine, molte valute di reporting. Tutto è archiviato in USD e l'utente sceglie la valuta di visualizzazione da un filtro dei dati. Converti al momento della query, in DAX. Precalcolare ogni valuta non è praticabile.
- Molte valute di origine, molte di reporting. Normalizza a un'unica valuta pivot all'importazione, poi applica sopra il caso 2. Non provare a risolverlo in un colpo solo.
La regola che i modellatori esperti ripetono, e che vale la pena ripetere ancora: applica la conversione il più presto possibile. Ogni conversione spostata al momento della query ti presenta il conto a ogni oggetto visivo, a ogni cambio di filtro, a ogni clic sul filtro dei dati.
Portare i tassi live in Power Query nel modo giusto
Parti dalla tabella dei tassi. La chiamata più efficiente è una richiesta multi-coppia: ottieni tutte le valute che ti interessano in una sola richiesta invece di una richiesta per valuta.
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://api.finexly.com/v1/convert?q=USD_EUR,USD_GBP,USD_JPY"{
"USD_EUR": { "rate": 0.9215 },
"USD_GBP": { "rate": 0.7892 }
}Ecco l'equivalente come query M di Power Query. Crea una query vuota (Home → Nuova origine → Query vuota → Editor avanzato) e incolla:
let
ApiKey = "YOUR_API_KEY",
Pairs = "USD_EUR,USD_GBP,USD_JPY,USD_CAD,USD_AUD,USD_CHF",
Source = Json.Document(
Web.Contents(
"https://api.finexly.com",
[
RelativePath = "v1/convert",
Query = [ q = Pairs ],
Headers = [ #"Authorization" = "Bearer " & ApiKey ]
]
)
),
ToTable = Record.ToTable(Source),
Expanded = Table.ExpandRecordColumn(ToTable, "Value", {"rate"}, {"Rate"}),
Split = Table.SplitColumn(
Expanded, "Name",
Splitter.SplitTextByDelimiter("_", QuoteStyle.None),
{"BaseCurrency", "Currency"}
),
Typed = Table.TransformColumnTypes(
Split,
{{"BaseCurrency", type text}, {"Currency", type text}, {"Rate", type number}}
),
Stamped = Table.AddColumn(Typed, "RetrievedAt", each DateTimeZone.UtcNow(), type datetimezone)
in
StampedChiamala FxRates. Ottieni una tabella a quattro colonne — BaseCurrency, Currency, Rate, RetrievedAt — subito utilizzabile in relazioni e misure.
L'errore di Web.Contents che rompe l'aggiornamento pianificato
Nota ciò che la query sopra non fa: non concatena mai i parametri dentro la stringa dell'URL. È la ragione più comune per cui un report di conversione valute funziona sul desktop e muore nel cloud.
Se scrivi invece così:
// Do NOT do this
Source = Json.Document(
Web.Contents("https://api.finexly.com/v1/convert?q=" & Pairs)
)…Power BI Desktop lo aggiornerà senza fiatare, e il servizio Power BI lo rifiuterà con «Questo set di dati include un'origine dati dinamica. L'aggiornamento non è supportato.» Il servizio deve poter risolvere un URL di base statico in fase di analisi per associarvi le credenziali. Passare le parti variabili tramite RelativePath e Query gli dà esattamente questo: la base resta https://api.finexly.com e tutto ciò che è dinamico vive nelle opzioni.
Lo stesso vale per qualunque query che costruisca un URL da un parametro, una data o un valore di un'altra tabella. Se da questo articolo porti via una cosa sola, porta via RelativePath.
Gestire la chiave API senza scriverla nel codice
ApiKey = "YOUR_API_KEY" inline va bene per un test di cinque minuti ed è sbagliato per qualsiasi cosa condivisa. Il codice M di un modello semantico è visibile a chiunque abbia l'autorizzazione di compilazione.
Due opzioni praticabili:
- Un parametro di Power Query (Home → Gestisci parametri), richiamato come
ApiKey = KeyParam. Resta archiviato con il modello, ma è centralizzato, facile da ruotare e sovrascrivibile per ambiente con le pipeline di distribuzione. - Il tipo di credenziale API Web. Nel servizio Power BI vai su Impostazioni del modello semantico → Credenziali origine dati → Modifica credenziali e scegli API Web, inserendo lì la chiave. Il servizio inietta da solo l'intestazione
Authorizatione puoi eliminare del tutto l'opzioneHeadersdal tuo M. Così il segreto resta fuori dalla definizione del modello.
Qualunque strada scegli, usa una chiave limitata al reporting e ruotala quando qualcuno lascia il team. Se la chiave finisce nella query string dell'URL invece che in un'intestazione, può comparire nei log di accesso di proxy e server: la documentazione Finexly lo segnala, e vale per qualsiasi fornitore.
Costruisci una dimensione valuta, non solo un elenco di tassi
Una tabella dei tassi da sola ti dà numeri. Non ti dà etichette corrette, decimali corretti né un filtro dei dati che si ordini in modo sensato. Porta l'elenco delle valute come dimensione a sé:
let
ApiKey = "YOUR_API_KEY",
Source = Json.Document(
Web.Contents(
"https://api.finexly.com",
[
RelativePath = "v1/currencies",
Headers = [ #"Authorization" = "Bearer " & ApiKey ]
]
)
),
ToTable = Table.FromList(Source, Splitter.SplitByNothing(), {"Currency"}),
Typed = Table.TransformColumnTypes(ToTable, {{"Currency", type text}})
in
TypedPoi aggiungi le due colonne che Power BI non può dedurre al posto tuo:
MinorUnits— il numero di decimali che la valuta usa davvero. JPY ne ha 0, KWD 3, la maggior parte 2. Formattare un totale in yen con due decimali è un errore di correttezza visibile in un report finanziario, e arrotondare nel passaggio sbagliato lo amplifica. La guida all'arrotondamento delle valute mostra da dove entra l'errore.FormatString— ad esempio"\€#,0.00","\¥#,0". Ti servirà più avanti per le stringhe di formato dinamiche.
Entrambe seguono lo standard ISO 4217 e non qualcosa che Power BI conosca nativamente; il riferimento ISO 4217 contiene la tabella completa. Contrassegna questa tabella come dimensione, mettila in relazione uno-a-molti con FxRates[Currency] e usa lei — non la tabella dei tassi — come origine del filtro dei dati.
Percorso A: convertire all'importazione (veloce, noioso, corretto)
Per lo scenario 1 — tante valute in ingresso, una in uscita — fai il lavoro in Power Query e lascia che il modello memorizzi un solo numero pulito.
- Carica la query delle transazioni in Power Query.
- Home → Merge di query, unendo
Transactions[Currency]aFxRates[Currency](esterno sinistro). - Espandi la colonna unita e mantieni
Rate. - Aggiungi colonna → Colonna personalizzata:
= if [Currency] = "USD" then [Amount]
else if [Rate] = null then null
else [Amount] / [Rate]Nota il ramo null. Un join esterno sinistro su una tabella dei tassi a cui manca una valuta produce null, e null nell'aritmetica di Power Query produce silenziosamente null anziché un errore — che diventa un vuoto nell'oggetto visivo e un totale discretamente troppo basso. Rendi la lacuna esplicita per poterla filtrare e vedere.
Nota anche la divisione. USD_EUR = 0.9215 significa che un USD compra 0,9215 EUR, quindi convertire un importo in EUR verso USD si divide. Convertire un importo in USD verso EUR si moltiplica. Invertire i due è il secondo bug più comune nei report multivaluta e, con tassi vicini a 1,0, è quasi invisibile: un errore del 3% su un valore EUR/USD sembra una differenza di arrotondamento finché qualcuno non fa la riconciliazione.
Percorso B: convertire al momento della query con DAX
Per lo scenario 2 — una valuta archiviata e una valuta di visualizzazione scelta dall'utente — la conversione deve avvenire in una misura.
La versione ingenua fa un LOOKUPVALUE per riga e diventa lenta oltre qualche centinaio di migliaia di righe. Aggrega prima, converti una volta sola:
Sales (Reporting Currency) =
VAR SelectedCurrency = SELECTEDVALUE ( Currency[Currency], "USD" )
VAR Rate =
CALCULATE (
SELECTEDVALUE ( FxRates[Rate] ),
FxRates[Currency] = SelectedCurrency
)
VAR Result =
IF (
SelectedCurrency = "USD",
[Sales Amount],
[Sales Amount] * Rate
)
RETURN
IF ( ISBLANK ( Rate ) && SelectedCurrency <> "USD", BLANK (), Result )Due dettagli che contano più di quanto sembrino:
SELECTEDVALUEcon valore predefinito. Senza il fallback"USD", la misura restituisce vuoto ogni volta che nessuna valuta è selezionata — ossia lo stato in cui il report si apre.- La protezione esplicita sul vuoto. Se una valuta non ha tasso, restituisci vuoto di proposito invece di lasciare che
[Sales Amount] * BLANK()restituisca zero. Uno zero in una scheda di fatturato è una bugia; un vuoto è una lacuna visibile.
Quando il tasso varia nel tempo
La misura sopra usa un unico tasso corrente per l'intero set di dati. È corretto per «quanto varrebbe oggi il fatturato dell'anno scorso» ed è sbagliato per quasi tutto il resto. Se la tua tabella dei tassi ha una riga per valuta per giorno, raggruppa per data prima di convertire:
Sales (Historical Rates) =
SUMX (
VALUES ( 'Date'[Date] ),
VAR DayRate =
CALCULATE (
SELECTEDVALUE ( FxRates[Rate] ),
FxRates[Currency] = SELECTEDVALUE ( Currency[Currency], "USD" )
)
RETURN
[Sales Amount] * DayRate
)Iterare su VALUES('Date'[Date]) anziché sulla tabella dei fatti mantiene piccolo l'iteratore — giorni, non transazioni.
Stringhe di formato dinamiche
Un numero convertito con prefisso $ fisso è peggio di nessun simbolo. In Power BI imposta il Formato della misura su Dinamico e fornisci un'espressione:
SELECTEDVALUE ( Currency[FormatString], "#,0.00" )Ora la scheda che mostra ¥ mostra ¥, con zero decimali e senza una seconda misura. Un tempo servivano i gruppi di calcolo in Analysis Services; le stringhe di formato dinamiche per le misure lo hanno portato dentro Power BI stesso.
Quale tasso dovresti usare davvero?
È la domanda che separa una dashboard da un report che l'amministrazione firma, e nessuna API può risponderti al posto tuo.
- Tasso spot alla data della transazione — per registrare singole operazioni. Massima fedeltà, tabella dei tassi più grande.
- Media mensile o di periodo — lo standard per le voci di conto economico sia secondo IAS 21 sia secondo ASC 830. Attenua la volatilità infra-mensile ed è ciò che la maggior parte dei consolidamenti usa davvero.
- Tasso di chiusura del periodo — per le voci di stato patrimoniale: cassa, crediti, debiti.
- Tasso di budget o di piano — un tasso fisso mantenuto per tutto l'anno perché l'analisi degli scostamenti isoli la performance operativa dal movimento valutario.
Un modello serio spesso ne richiede due o tre affiancati, come colonne distinte della stessa tabella dei tassi (SpotRate, AverageRate, ClosingRate) e non come tabelle separate. Se il report alimenta qualcosa che finisce in una dichiarazione, la guida su tassi di cambio e reporting fiscale tratta quale fonte e quale timestamp devi poter difendere, mentre la guida ai tassi storici copre il recupero di tassi datati anziché live.
Il buco del fine settimana che rompe i totali in silenzio
I mercati valutari chiudono. Una tabella di tassi giornalieri costruita da un'API live non ha sabato, non ha domenica e non ha il 25 dicembre. Unisci una transazione datata sabato a quella tabella e ottieni null, null diventa vuoto, e il vuoto diventa un totale più basso esattamente delle vendite del fine settimana.
Risolvi nella tabella dei tassi, non nella misura. Genera un elenco di date completo e riempi verso il basso:
let
Dates = List.Dates(#date(2026,1,1), Duration.Days(Date.From(DateTime.LocalNow()) - #date(2026,1,1)) + 1, #duration(1,0,0,0)),
DateTable = Table.FromList(Dates, Splitter.SplitByNothing(), {"Date"}),
Typed = Table.TransformColumnTypes(DateTable, {{"Date", type date}}),
Joined = Table.NestedJoin(Typed, {"Date"}, RateHistory, {"Date"}, "r", JoinKind.LeftOuter),
Expanded = Table.ExpandTableColumn(Joined, "r", {"Currency", "Rate"}),
Filled = Table.FillDown(Expanded, {"Currency", "Rate"})
in
FilledTable.FillDown porta il tasso del venerdì attraverso il fine settimana: è il trattamento convenzionale e, soprattutto, un trattamento dichiarato invece che accidentale. Ordina per valuta e data prima di riempire, altrimenti trascinerai il tasso della valuta sbagliata attraverso il buco.
Se il tuo piano non include gli endpoint storici, puoi costruire lo storico in avanti: aggiungi i tassi di oggi a una tabella archiviata a ogni aggiornamento — un dataflow o una tabella Fabric Lakehouse vanno benissimo — e dopo un trimestre avrai una serie storica reale. Non è retroattivo, ma costa una chiamata API al giorno.
Pianificazione degli aggiornamenti e aritmetica della quota
Power BI Pro consente 8 aggiornamenti pianificati al giorno per modello semantico; le capacità Premium e Fabric ne consentono 48. È il numero che la tua quota API deve coprire, e i conti sono più clementi di quanto si creda.
La tabella dei tassi sopra sono due chiamate per aggiornamento: una a /v1/currencies, una a /v1/convert. Quindi:
| Cadenza di aggiornamento | Aggiornamenti/mese | Chiamate API/mese | Piano Finexly |
|---|---|---|---|
| 8/giorno (massimo Pro) | ~240 | ~480 | Gratuito (1.000/mese) |
| 48/giorno (Fabric, ogni 30 min) | ~1.440 | ~2.880 | Starter |
| 48/giorno + storico orario in dataflow | ~2.160 | ~4.320 | Growth |
Il tetto di 10 al minuto è quello da tenere d'occhio. Se costruisci una query che chiama /v1/rate una volta per valuta dentro un Table.AddColumn, venti valute significano venti chiamate in pochi secondi e una raffica di risposte 429 a metà aggiornamento. È esattamente per questo che esiste la chiamata multi-coppia /v1/convert. Raggruppa e metti in cache: la guida su cache e gestione degli errori descrive schemi di retry con backoff che valgono allo stesso modo per un aggiornamento pianificato.
Gateway, Excel e Fabric
Qualche nota d'ambiente che fa risparmiare un pomeriggio ciascuna:
- Nessun gateway necessario. Un'API REST cloud non è un'origine locale, quindi non serve un gateway dati locale. Se l'aggiornamento fallisce e qualcuno propone di installarne uno, quasi sempre è l'errore di origine dati dinamica travestito.
- Excel usa lo stesso motore. Power Query in Excel accetta esattamente il M qui sopra. Se il tuo pubblico vive nelle cartelle di lavoro e non nelle dashboard, la guida ai tassi live in Excel copre
WEBSERVICE,LAMBDAe la matrice delle versioni; esiste anche un equivalente per Google Sheets. - Fabric Dataflow Gen2 è la casa migliore per la tabella dei tassi non appena serve a più di un report. Atterra i tassi una volta, lascia che tutti i modelli semantici leggano la stessa tabella e il consumo di API smette di crescere con il numero di report.
- Verifica contro un numero noto prima di pubblicare. Prendi una coppia dal convertitore di valute e confrontala con quello che il modello mostra per la stessa coppia nello stesso istante. Se non coincidono, hai un problema di verso o di arrotondamento, ed è meglio trovarlo adesso che in consiglio di amministrazione.
Domande frequenti
Power BI può convertire valute senza un'API? Sì, se i tassi li fornisci tu: una tabella mantenuta a mano, un export dal sistema contabile o una vista di database. Power BI non ha una fonte di tassi integrata. L'API conta quando servono tassi che si aggiornano senza che qualcuno debba ricordarsene.
Perché il mio report di conversione si aggiorna in Power BI Desktop ma fallisce nel servizio?
Quasi sempre per l'errore di origine dati dinamica. La chiamata Web.Contents costruisce l'URL per concatenazione. Sposta le parti variabili nelle opzioni RelativePath e Query così che l'URL di base sia statico, ripubblica e reinserisci le credenziali.
Meglio convertire in Power Query o in DAX? Power Query quando il report ha una sola valuta di reporting: è più rapido e più semplice. DAX quando l'utente sceglie la valuta a runtime. Se servono entrambi, normalizza a una valuta pivot in Power Query e appoggia sopra la misura DAX.
Quante richieste API consuma un aggiornamento di Power BI?
Due per aggiornamento se raggruppi tutte le coppie in una sola chiamata /v1/convert. Al massimo di 8 aggiornamenti giornalieri di Power BI Pro sono circa 480 richieste al mese, dentro un piano gratuito. Diventa costoso solo se chiami l'API una volta per valuta o una volta per riga.
Come gestisco fine settimana e festivi in una tabella di tassi giornalieri? Genera una tabella date continua, unisci i tassi con join sinistro, ordina per valuta e data e riempi verso il basso. Il tasso del venerdì si estende al fine settimana. L'importante è che il trattamento sia deliberato e documentato, non che le righe spariscano in silenzio.
Quale tasso di cambio usare per il reporting finanziario? Tassi medi di periodo per le voci di conto economico e tassi di chiusura per le voci di stato patrimoniale, sia secondo IAS 21 sia secondo ASC 830. Conservali come colonne distinte di un'unica tabella dei tassi, così il report può passare dall'uno all'altro senza modificare il modello.
Pronto a mettere tassi live dietro le tue dashboard? Ottieni la tua chiave API Finexly gratuita — senza carta di credito. Parti con 1.000 richieste al mese, abbastanza per aggiornare un'area di lavoro Power BI Pro alla frequenza massima, e passa a un piano superiore quando ti servono dati storici o una cadenza più fitta. Se stai ancora confrontando i fornitori, la pagina di confronto mette le opzioni una accanto all'altra.
Explore More
Vlado Grigirov
Senior Currency Markets Analyst & Financial Strategist
Vlado Grigirov is a senior currency markets analyst and financial strategist with over 14 years of experience in foreign exchange markets, cross-border finance, and currency risk management. He has wo...
View full profile →