Zurück zum Blog

Live-Wechselkurse in Power BI: Power Query, DAX und die Aktualisierungsfalle

V
Vlado Grigirov
September 01, 2026
Currency API Exchange Rates Power BI Power Query DAX Tutorial Finexly

Live-Wechselkurse in Power BI zu holen gehört zu den Aufgaben, die lange fertig aussehen, bevor sie es sind. Sie fügen eine API-URL in Daten abrufen → Web ein, eine Kurstabelle erscheint, Ihr umgerechnetes Umsatzmaß leuchtet auf, und Sie veröffentlichen. Zwei Tage später scheitert die Aktualisierung des Datasets im Power BI-Dienst mit einer Meldung über eine dynamische Datenquelle — oder sie läuft durch und rechnet stillschweigend jede historische Transaktion zum heutigen Kurs um.

Dieser Leitfaden deckt den gesamten Weg ab: eine Power Query-M-Abfrage, die eine saubere Kurstabelle liefert, das RelativePath-Muster, das sie im Dienst aktualisierbar hält, eine Funktion für historische Kurse zur Umrechnung am Transaktionsdatum, ein DAX-Measure für eine dynamische Berichtswährung sowie die Rechnung zur Anfragezahl, die entscheidet, ob Ihr Aktualisierungsplan in einen API-Tarif passt.

Alle Abfragen unten sind gegen die dokumentierten Antwortstrukturen der Finexly-API geschrieben. Wenn Sie unseren Leitfaden zu Live-Wechselkursen in Excel bereits kennen, wird Ihnen das M hier vertraut vorkommen — Power BI ergänzt jedoch eine dienstseitige Aktualisierungsschicht, die Excel nicht hat, und genau dort brechen die meisten dieser Projekte.

Die drei Wege, Kurse nach Power BI zu bringen

AnsatzAktualisiert im Dienst?API-Schlüssel sicher?Historische KurseAm besten für
Web-Connector, URL in den Dialog eingefügtOft nicht — die URL wird meist zur dynamischen Datenquelle❌ Schlüssel steht in der URLNeinEin Fünf-Minuten-Proof-of-Concept
Leere Abfrage mit Web.Contents + RelativePath✅ Ja✅ Über Header✅ JaNahezu jedes echte Modell
Dataflow (oder Fabric-Pipeline), der eine Kurstabelle speist✅ Ja, und entkoppelt von der Berichtsaktualisierung✅ Über Header✅ JaMehrere Berichte, hohe Zeilenzahlen
Die zweite Zeile ist die Standardantwort. Auf die dritte steigt man um, sobald mehr als ein Bericht dieselben Kurse braucht. Die erste ist die, die jedes Screenshot-Tutorial lehrt — und der Grund, warum so viele Währungsmodelle bei der ersten geplanten Aktualisierung scheitern.

Methode 1: Eine Live-Kurstabelle mit Power Query

Öffnen Sie Daten transformieren → Neue Quelle → Leere Abfrage → Erweiterter Editor und fügen Sie das hier ein. Es entsteht eine Zeile pro Währungspaar mit UTC-Abrufzeitstempel.

let
    ApiKey  = "YOUR_API_KEY",
    Base    = "USD",
    Symbols = "EUR,GBP,JPY,CHF,AUD,CAD,SEK,NZD",

    Source = Json.Document(
        Web.Contents(
            "https://api.finexly.com",
            [
                RelativePath = "v1/latest",
                Query        = [ base = Base, symbols = Symbols ],
                Headers      = [ #"Authorization" = "Bearer " & ApiKey ]
            ]
        )
    ),

    Rates    = Record.ToTable( Source[rates] ),
    Renamed  = Table.RenameColumns( Rates, {{"Name", "Quote"}, {"Value", "Rate"}} ),
    AddBase  = Table.AddColumn( Renamed, "Base", each Base, type text ),
    AddStamp = Table.AddColumn( AddBase, "RetrievedUTC", each DateTimeZone.UtcNow(), type datetimezone ),
    Typed    = Table.TransformColumnTypes(
                   AddStamp,
                   {{"Quote", type text}, {"Rate", type number}}
               )
in
    Typed

Der aufgerufene Endpunkt sieht auf der Kommandozeile so aus — es lohnt sich, ihn einmal auszuführen, um die Struktur zu sehen, die Sie parsen:

curl "https://api.finexly.com/v1/latest?base=USD&symbols=EUR,GBP,JPY" \
  -H "Authorization: Bearer YOUR_API_KEY"
{
  "success": true,
  "base": "USD",
  "date": "2026-09-01",
  "rates": { "EUR": "…", "GBP": "…", "JPY": "…" }
}

Warum RelativePath und Query nicht optional sind

Das ist die wichtigste Zeile des Artikels, deshalb bekommt sie eine eigene Überschrift.

Wenn Sie die URL als einen zusammengesetzten String bauen — "https://api.finexly.com/v1/latest?base=" & Base — kann Power Query das Ziel erst zur Laufzeit bestimmen. Microsoft stuft das als dynamische Datenquelle ein, und dynamische Datenquellen werden im Power BI-Dienst aus Sicherheits- und Datenschutzgründen nicht aktualisiert. Der Bericht aktualisiert auf Ihrem Laptop einwandfrei und scheitert in dem Moment, in dem er geplant wird.

Den Pfad in RelativePath und die Parameter in Query zu übergeben, ist die dokumentierte Ausnahme. Power BI kann dann eine einzige statische Basis-URL — https://api.finexly.com — für Anmelde- und Datenschutzprüfungen auflösen, während die variablen Teile variabel bleiben. Daraus folgen drei Regeln:

  1. Die Basis-URL muss ein Literal-String sein. Keine Parameter, keine Verkettung, nirgends ein &.
  2. RelativePath sollte der feste Endpunktpfad sein. "v1/latest", nicht "v1/latest?base=USD".
  3. Verketten Sie niemals innerhalb von Query. Übergeben Sie einen Record aus Name/Wert-Paaren und überlassen Sie Power Query die URL-Kodierung. Es maskiert zudem Zeichen, die die Anfrage sonst zerstören würden.

Anmeldeinformationen einrichten

Beim ersten Ausführen fragt Power BI, wie es sich bei https://api.finexly.com authentifizieren soll. Wählen Sie Anonym. Das fühlt sich falsch an, ist aber richtig: Der API-Schlüssel reist im Authorization-Header, den Sie im M-Code gesetzt haben, nicht über den Anmeldeinformationsspeicher von Power BI. Web-API oder Basic würde Power BI veranlassen, einen eigenen Header hinzuzufügen — die Anfrage wird dann abgelehnt.

Setzen Sie die Datenschutzstufe über alle Quellen hinweg konsistent auf Öffentlich oder Organisation. Nicht zusammenpassende Datenschutzstufen sind die zweithäufigste Ursache für eine Aktualisierung, die in Desktop funktioniert und im Dienst scheitert — Power BI blockiert die Abfrage lieber, als zu riskieren, Daten der einen Quelle in die Anfrage einer anderen zu geben.

Eine ehrliche Einschränkung: Der Schlüssel liegt jetzt als Klartext in der Abfrage. Wer die .pbix öffnet, kann ihn lesen. Für alles, was über Ihren eigenen Rechner hinaus geteilt wird, machen Sie den Schlüssel zu einem Power Query-Parameter und halten Sie die befüllte Fassung in einem Dataflow, der einem Dienstkonto gehört — so nutzen Berichtsautoren die Kurstabelle, ohne die Anmeldeinformation je zu sehen.

Methode 2: Historische Kurse für die Umrechnung zum Transaktionsdatum

Eine Live-Kurstabelle beantwortet „wie steht EUR/USD gerade". Sie beantwortet nicht „wie hoch war unser Januarumsatz in USD" — und sie dafür zu verwenden, ist der teuerste Fehler des ganzen Themas: Zahlen des Vorquartals neu auszuweisen, weil das Modell sie zu einem neuen Kurs umgerechnet hat, ist genau das, wonach Prüfer suchen. Wenn Ihr Bericht etwas speist, das Sie später verteidigen müssen, lesen Sie ergänzend unseren Leitfaden zu Wechselkursen und steuerlicher Berichterstattung.

Sie brauchen eine datumsindizierte Kurstabelle. Diese M-Funktion kapselt den Zeitreihen-Endpunkt und liefert eine Zeile pro Datum und Währung:

let
    FxHistory = (base as text, symbols as text, startDate as date, endDate as date) as table =>
        let
            ApiKey = "YOUR_API_KEY",

            Source = Json.Document(
                Web.Contents(
                    "https://api.finexly.com",
                    [
                        RelativePath = "v1/timeseries",
                        Query = [
                            base       = base,
                            symbols    = symbols,
                            start_date = Date.ToText( startDate, [Format = "yyyy-MM-dd", Culture = "en-US"] ),
                            end_date   = Date.ToText( endDate,   [Format = "yyyy-MM-dd", Culture = "en-US"] )
                        ],
                        Headers = [ #"Authorization" = "Bearer " & ApiKey ]
                    ]
                )
            ),

            Days      = Table.RenameColumns( Record.ToTable( Source[rates] ), {{"Name", "RateDate"}} ),
            Expanded  = Table.ExpandRecordColumn( Days, "Value", Record.FieldNames( Days{0}[Value] ) ),
            Unpivoted = Table.UnpivotOtherColumns( Expanded, {"RateDate"}, "Quote", "Rate" ),
            AsDate    = Table.TransformColumns(
                            Unpivoted,
                            {{"RateDate", each Date.FromText( _, [Format = "yyyy-MM-dd", Culture = "en-US"] ), type date}}
                        ),
            AddBase   = Table.AddColumn( AsDate, "Base", each base, type text ),
            Typed     = Table.TransformColumnTypes( AddBase, {{"Quote", type text}, {"Rate", type number}} )
        in
            Typed
in
    FxHistory

Zwei Details darin leisten echte Arbeit:

  • Culture = "en-US" sowohl bei Date.ToText als auch bei Date.FromText. Ohne das sendet ein auf Deutsch oder Französisch eingestellter Rechner 01.09.2026 als start_date, und die API lehnt ab — oder schlimmer: Die Aktualisierung einer Kollegin liefert eine anders geformte Tabelle als Ihre. Das Gebietsschema ist die unsichtbare Variable in jedem Power Query-Projekt, das mehr als ein Land umfasst.
  • Table.UnpivotOtherColumns. Die API gibt Datumswerte als Record-Schlüssel mit einem verschachtelten Währungs-Record zurück. Das Entpivotieren in die lange Form RateDate / Base / Quote / Rate ergibt eine Tabelle, die sich sauber mit einer Datumsdimension verbindet und nicht bei jeder neuen Währung umgebaut werden muss.

Einmal pro Ladevorgang aufrufen: FxHistory( "USD", "EUR,GBP,JPY", #date(2026,1,1), Date.From( DateTime.LocalNow() ) ).

Da sich Kurse vergangener Tage nie ändern, ist diese Tabelle der Lehrbuchfall für inkrementelle Aktualisierung: nach RateDate partitionieren, die letzten 7 Tage aktualisieren, alles Ältere archivieren. Ihre Aktualisierungsdauer wächst nicht mehr mit der Historie — und Ihre Anfragezahl auch nicht.

Rufen Sie die API nicht einmal pro Zeile auf

Das Muster, das diese Modelle umbringt, ist der Aufruf einer Kursfunktion als benutzerdefinierte Spalte auf der Faktentabelle. Zehntausend Transaktionen bedeuten zehntausend HTTP-Anfragen pro Aktualisierung, eine Aktualisierung von vierzig Minuten und eine Kontingentrechnung, die vor dem Mittagessen eintrifft.

Rechnen Sie vorher. Power BI Pro erlaubt 8 geplante Aktualisierungen pro Dataset und Tag; Premium Per User und Fabric-Kapazität erlauben 48. Ein einziger /v1/latest-Aufruf, der alle benötigten Währungen abdeckt und im Pro-Maximum aktualisiert wird, kostet 8 Anfragen pro Tag — rund 240 im Monat, bequem innerhalb eines Freikontingents von 1.000. Derselbe Plan mit einer Funktion pro Zeile ist unbegrenzt. Selbst beim PPU-Maximum von 48 Aktualisierungen landet ein konsolidierter Aufruf bei etwa 1.440 Anfragen im Monat — ein kleiner Bezahltarif statt einer Katastrophe je Zeile. Unsere Preispläne nennen die Schwellen, wenn Sie das genau dimensionieren müssen.

Sobald mehr als ein Bericht die Kurse braucht, verschieben Sie die Abfrage in einen Dataflow. Der Dataflow ruft die API nach eigenem Zeitplan auf und materialisiert das Ergebnis; jedes nachgelagerte Dataset liest aus dem Speicher, statt erneut die API zu treffen. Fünf Berichte auf demselben Dataflow erzeugen einen Satz Anfragen, nicht fünf.

Beträge umrechnen: Power Query-Zusammenführung oder DAX-Measure

Es gibt zwei legitime Orte für die Umrechnung, und sie beantworten unterschiedliche Fragen.

Variante A: In Power Query zusammenführen

Wenn Ihre Berichtswährung fest ist — alles wird in USD berichtet, Punkt — machen Sie den Join zur Ladezeit.

  1. Laden Sie die Faktentabelle in Power Query.
  2. Abfragen zusammenführen mit der Kurstabelle, abgeglichen über Währungscode und Datum. Strg halten und die Spalten in beiden Tabellen in derselben Reihenfolge wählen.
  3. Nur die Spalte Rate erweitern und auf Feste Dezimalzahl setzen.
  4. Amount und Rate markieren, dann Spalte hinzufügen → Standard → Multiplizieren.
  5. Das Laden der Kurstabelle deaktivieren, wenn nichts anderes sie referenziert.

Das ist schnell, materialisiert einmal und lässt sich von keinem Datenschnitt austricksen. Der letzte Punkt ist der Preis dafür.

Variante B: Ein DAX-Measure mit wählbarer Berichtswährung

Wenn Nutzer den gesamten Bericht zwischen USD, EUR und GBP umschalten sollen, muss die Umrechnung zur Abfragezeit passieren. Legen Sie eine unverknüpfte Tabelle Reporting Currency mit einer Spalte ISO-Codes an, setzen Sie sie in einen Datenschnitt und schreiben Sie:

Revenue (Reporting Currency) =
VAR ReportingCurrency = SELECTEDVALUE( 'Reporting Currency'[Code], "USD" )
RETURN
SUMX (
    'Sales',
    VAR TxCurrency = 'Sales'[CurrencyCode]
    VAR TxDate     = 'Sales'[OrderDate]
    VAR Rate =
        CALCULATE (
            MAX ( 'FX Rates'[Rate] ),
            REMOVEFILTERS ( 'FX Rates' ),
            'FX Rates'[Base]     = TxCurrency,
            'FX Rates'[Quote]    = ReportingCurrency,
            'FX Rates'[RateDate] = TxDate
        )
    RETURN 'Sales'[Amount] * Rate
)

Drei Dinge fallen auf:

  • Die VAR-Zeilen sind tragend. TxCurrency und TxDate vor CALCULATE in Variablen zu fangen, bindet sie an die aktuelle SUMX-Zeile. Die Spalten direkt in den Filterargumenten zu referenzieren, lädt einen Kontextübergangs-Fehler ein, der plausibel aussehende, aber falsche Summen erzeugt.
  • REMOVEFILTERS( 'FX Rates' ) verhindert, dass ein eingehender Filter auf der Kurstabelle die Suche einengt.
  • Ein fehlender Kurs liefert BLANK(), und Amount * BLANK() ist BLANK(). Genau das wollen Sie. Eine Zeile, die still auf den nicht umgerechneten Betrag zurückfällt, bläht Ihre Summe um den jeweiligen Wechselkurs auf.

Die Beziehungsfalle

Legen Sie keine physische Beziehung von der Faktentabelle zur Kurstabelle allein über den Währungscode an. In einer datumsindizierten Kurstabelle ist der Währungscode nicht eindeutig, also schlägt Power BI eine m:n-Beziehung vor — und m:n mit bidirektionaler Filterung fächert Ihre Zeilen fröhlich auf und vervielfacht Ihren Umsatz. Nutzen Sie entweder die zusammengesetzte Zusammenführung in Power Query oder halten Sie die Kurstabelle unverknüpft und schlagen Sie Kurse wie oben in DAX nach.

Fünf Fehler, die ohne Fehlermeldung falsche Zahlen erzeugen

  1. Verkettete URLs. Aktualisiert in Desktop, scheitert im Dienst mit „Dieses Dataset enthält eine dynamische Datenquelle." Behoben durch RelativePath und Query.
  2. Vertauschte Paare. base=USD&symbols=EUR liefert USD→EUR. Wenn Ihre Faktentabelle EUR-Beträge speichert, brauchen Sie den Kehrwert. Prüfen Sie ein bekanntes Paar von Hand, bevor Sie irgendeiner Summe trauen. Unsere ISO-4217-Referenz hilft, wenn unklar ist, welcher Code auf welche Seite gehört.
  3. Heutiger Kurs auf historischen Zeilen. Die Zahl ändert sich bei jeder Aktualisierung, und niemand merkt es, bis jemand zwei Exporte desselben Berichts vergleicht.
  4. Regional formatierte Daten und Dezimalzeichen. Ein Dezimalkomma macht aus 1,0842 Text, Table.TransformColumnTypes liefert einen Fehler, den das Modell als leer behandelt, und die betroffenen Zeilen verschwinden aus Ihren Summen.
  5. Runden am falschen Schritt. Runden Sie einmal, bei der Darstellung, nach der Multiplikation. Den Kurs vor der Multiplikation eines siebenstelligen Betrags auf vier Nachkommastellen zu runden, erzeugt eine sichtbare Abweichung gegenüber dem Buchhaltungssystem.

Häufige Fragen

Kann Power BI Wechselkurse automatisch aktualisieren?

Ja. Ein veröffentlichtes Dataset lässt sich für bis zu 8 Aktualisierungen pro Tag in Power BI Pro und 48 pro Tag in Premium Per User oder Fabric-Kapazität planen. Der XMLA-Endpunkt von Premium erlaubt externen Werkzeugen, Aktualisierungen außerhalb dieser Grenzen auszulösen. Die Kursabfrage selbst braucht nichts Besonderes, außer mit Web.Contents + RelativePath gebaut zu sein, damit der Dienst sie akzeptiert.

Wie übergebe ich einen API-Schlüssel sicher in Power BI?

Setzen Sie ihn in den Headers-Record von Web.Contents als Authorization = "Bearer " & ApiKey und wählen Sie Anonym, wenn Power BI fragt. Damit bleibt der Schlüssel aus der URL, aus Proxy-Logs und aus dem Browserverlauf heraus. Verschlüsselt wird er in der .pbix dadurch nicht — für geteilte Modelle halten Sie den Schlüssel in einem Dataflow eines Dienstkontos und lassen Berichte die materialisierte Tabelle lesen.

Warum meldet mein Dataset „Dieses Dataset enthält eine dynamische Datenquelle"?

Weil die URL im Code zusammengesetzt wird: Power BI kann das Ziel vor dem Lauf der Abfrage nicht prüfen und verweigert die Aktualisierung im Dienst. Bauen Sie den Aufruf mit statischer Basis-URL plus RelativePath und Query neu, veröffentlichen Sie erneut und geben Sie die Anmeldeinformation für die Basis-URL neu ein.

Wie rechne ich Beträge zum Kurs des Transaktionsdatums um?

Laden Sie eine datumsindizierte Kurstabelle aus einem Zeitreihen-Endpunkt und gleichen Sie über Währung und Datum ab — entweder per zusammengesetzter Zusammenführung in Power Query oder mit einem CALCULATE-Lookup innerhalb von SUMX wie oben gezeigt. Verknüpfen Sie nie nur über die Währung; Sie greifen sonst still die Kurszeile ab, die in der Sortierung zufällig zuerst steht.

Gibt es eine kostenlose Währungs-API, die mit Power BI funktioniert?

Ja. Der kostenlose Tarif der kostenlosen Währungs-API von Finexly umfasst 1.000 Anfragen pro Monat ohne Kreditkarte — mit deutlichem Puffer genug für ein Pro-lizenziertes Dataset, das achtmal täglich aktualisiert. Wenn Sie Anbieter nach Aktualisierungsgrenzen, Historientiefe oder Währungsabdeckung abwägen: Währungs-APIs vergleichen, bevor Sie eine in ein Modell verdrahten, das Sie jahrelang pflegen werden.


Loslegen mit Finexly

Bereit, Live-Wechselkurse in Ihre Power BI-Berichte zu bringen? Holen Sie sich Ihren kostenlosen Finexly-API-Schlüssel — ohne Kreditkarte. Starten Sie mit 1.000 kostenlosen Anfragen pro Monat und wachsen Sie in Ruhe hinein. Echtzeit- und historische Kurse für über 170 Währungen aus einer REST-API, die sich gleich verhält, ob Sie sie aus Power Query, Python oder einem Zahlungsdienst aufrufen.

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 →

Diesen Artikel teilen