Skip to main content
cancel
Showing results for 
Search instead for 
Did you mean: 

Register now to learn Fabric in free live sessions led by the best Microsoft experts. From Apr 16 to May 9, in English and Spanish.

Reply
Anonymous
Not applicable

Historical exchange rate API

Hi,

 

I am looking for a way to get historical exchange rates into my report - also daily updated rates - and I have been looking at ecb.europa.eu and their rest API, but find it difficult; 

does anyone know a fairly easy way to fetch these figures? 

Disclaimer; I have no developer skills - solely a business analyst, obviously... 

1 ACCEPTED SOLUTION
Anonymous
Not applicable

@Anonymous I would suggest first creating a table with sequential dates on each row. Then by invoking the function, it will send the dates to the function one by one thus returning the exchange rate info for each day. You can use this example which first generates a list of dates of the past 365 days (this is updated with every refresh) and invokes the function:

 

let
    Source = {Number.From(Date.AddDays(DateTime.Date(DateTime.LocalNow()),-365))..Number.From(DateTime.Date(DateTime.LocalNow()))},
    #"Converted to Table" = Table.FromList(Source, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
    #"Changed Type" = Table.TransformColumnTypes(#"Converted to Table",{{"Column1", type date}}),
    #"Renamed Columns" = Table.RenameColumns(#"Changed Type",{{"Column1", "Date"}}),
    #"Invoked Custom Function" = Table.AddColumn(#"Renamed Columns", "ExchangeRates", each Fn_GetHistoricExchangeRates(Date.ToText([Date],"yyyy-MM-dd"))),
    #"Expanded ExchangeRates" = Table.ExpandTableColumn(#"Invoked Custom Function", "ExchangeRates", {"Currency", "Rate"}, {"Currency", "Rate"}),
    #"Changed Type1" = Table.TransformColumnTypes(#"Expanded ExchangeRates",{{"Rate", type number}, {"Currency", type text}})
in
    #"Changed Type1"

In order for it to work you should create a function named Fn_GetHistoricExchangeRates, by using the code in my previous post.

 

Hope that helps!


Jan

View solution in original post

15 REPLIES 15
GarlonYau
Helper I
Helper I

Hi Folks,

 

I'm trying to use the code that @janvanwerkhoven provided but I seem to be running into issues.

 

So here's what I've done, I've created the mentioned.

let
    Source = {Number.From(Date.AddDays(DateTime.Date(DateTime.LocalNow()),-365))..Number.From(DateTime.Date(DateTime.LocalNow()))},
    #"Converted to Table" = Table.FromList(Source, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
    #"Changed Type" = Table.TransformColumnTypes(#"Converted to Table",{{"Column1", type date}}),
    #"Renamed Columns" = Table.RenameColumns(#"Changed Type",{{"Column1", "Date"}}),
    #"Invoked Custom Function" = Table.AddColumn(#"Renamed Columns", "ExchangeRates", each Fn_GetHistoricExchangeRates(Date.ToText([Date],"YYYY-MM-DD"))),
    #"Expanded ExchangeRates" = Table.ExpandTableColumn(#"Invoked Custom Function", "ExchangeRates", {"Currency", "Rate"}, {"Currency", "Rate"}),
    #"Changed Type1" = Table.TransformColumnTypes(#"Expanded ExchangeRates",{{"Rate", type number}, {"Currency", type text}})
in
    #"Changed Type1"

 

I created a function as well after signing up for the free api from exchangeratesapi.io. The access key has been shared (I know I'm normally shouldn't share this, but I can easily reset it after - I wanted to share it incase the problem is not in the query but in the API key:

= (Date as text) => let
        Source = Json.Document(Web.Contents("https://api.exchangeratesapi.io/v1/" & Date & "?access_key=103e0b5e0bd42045530ea385cc28422b" & "?base=USD" )),
        rates = Source[rates],
        #"Converted to Table" = Record.ToTable(rates),
        #"Renamed Columns" = Table.RenameColumns(#"Converted to Table",{{"Name", "Currency"}, {"Value", "Rate"}})
    in
        #"Renamed Columns"

 

Now, when I try to invoke the function, it tells me that my credentials are incorrect. 

GarlonYau_0-1708480658208.png

GarlonYau_1-1708480681923.png

 

I'm a bit lost in terms of what I am doing wrong.

 

Any help would be much appreciated!

ddecoene
Frequent Visitor

How did you get that date into PowerBI? I had trouble with the navigation to find the dataset within the XML file.

In my example, I needed only 3 currencies EUR, GBP and PLN, and grouped average by month.

 

See the M code below. 

 

/*

let
Source = Xml.Tables(Web.Contents("http://www.ecb.europa.eu/stats/eurofxref/eurofxref-hist.xml")),
#"Changed Type" = Table.TransformColumnTypes(Source,{{"subject", type text}}),
#"Expanded Sender" = Table.ExpandTableColumn(#"Changed Type", "Sender", {"name"}, {"Sender.name"}),
#"Expanded http://www.ecb.int/vocabulary/2002-08-01/eurofxref" = Table.ExpandTableColumn(#"Expanded Sender", "http://www.ecb.int/vocabulary/2002-08-01/eurofxref", {"Cube"}, {"Cube"}),
#"Expanded Cube" = Table.ExpandTableColumn(#"Expanded http://www.ecb.int/vocabulary/2002-08-01/eurofxref", "Cube", {"Cube"}, {"Cube.1"}),
#"Expanded Cube.1" = Table.ExpandTableColumn(#"Expanded Cube", "Cube.1", {"Cube", "Attribute:time"}, {"Cube", "Attribute:time"}),
#"Expanded Cube1" = Table.ExpandTableColumn(#"Expanded Cube.1", "Cube", {"Attribute:currency", "Attribute:rate"}, {"Attribute:currency", "Attribute:rate"}),
#"Filtered Rows" = Table.SelectRows(#"Expanded Cube1", each ([#"Attribute:currency"] = "GBP" or [#"Attribute:currency"] = "PLN")),
#"Replaced Value" = Table.ReplaceValue(#"Filtered Rows",".",",",Replacer.ReplaceText,{"Attribute:rate"}),
#"Changed Type1" = Table.TransformColumnTypes(#"Replaced Value",{{"Attribute:rate", type number}, {"Attribute:time", type date}, {"Attribute:currency", type text}}),
#"Removed Columns" = Table.RemoveColumns(#"Changed Type1",{"subject", "Sender.name"}),
#"Renamed Columns" = Table.RenameColumns(#"Removed Columns",{{"Attribute:time", "Date"}}),
#"Pivoted Column" = Table.Pivot(#"Renamed Columns", List.Distinct(#"Renamed Columns"[#"Attribute:currency"]), "Attribute:currency", "Attribute:rate", List.Sum),
#"Added Custom" = Table.AddColumn(#"Pivoted Column", "EUR", each 1),
#"Changed Type2" = Table.TransformColumnTypes(#"Added Custom",{{"EUR", type number}}),
#"Unpivoted Other Columns" = Table.UnpivotOtherColumns(#"Changed Type2", {"Date"}, "Attribute", "Value"),
#"Sorted Rows" = Table.Sort(#"Unpivoted Other Columns",{{"Date", Order.Descending}}),
#"Inserted Year" = Table.AddColumn(#"Sorted Rows", "Year", each Date.Year([Date]), Int64.Type),
#"Inserted Month" = Table.AddColumn(#"Inserted Year", "Month", each Date.Month([Date]), Int64.Type),
#"Inserted Merged Column" = Table.AddColumn(#"Inserted Month", "CURR_ID", each Text.Combine({[Attribute], Text.From([Year], "nl-BE"), Text.From([Month], "nl-BE")}, "-"), type text),
#"Removed Other Columns1" = Table.SelectColumns(#"Inserted Merged Column",{"CURR_ID", "Value"}),
#"Grouped Rows" = Table.Group(#"Removed Other Columns1", {"CURR_ID"}, {{"FX", each List.Average([Value]), type number}})
in
#"Grouped Rows"

*/

Hi,
Thanks a million! That was exactly what I needed but for other currencies (which I easily can adjust).
I have made the first tests and this looks brilliant.
You made my week!
// Philip

Anonymous
Not applicable

It can be done in ChristianSteven's PBRS

TeigeGao
Solution Sage
Solution Sage

Hi @Anonymous ,

I will use data from this website: https://www.x-rates.com/historical/?from=USD&amount=1&date=2019-07-17, we can change the url to specified date to get historical exchange rates. Then we can use the web connector in PowerBI to get the data from them:
PBIDesktop_cEiyWMRHcJ.png

Best Regards,

Teige

Anonymous
Not applicable

So you update the URL everytime you want new data? 

Should be possible to get the latest data added to your previous queries and cached responses. 

Anonymous
Not applicable

Hi @TeigeGao,

 

Thx for your reply.

I should've been more specific:

 

What I am trying to achieve is to have a line chart with historical rates that refreshes with new datapoints every day. 

ECB has a syntax to do that, but I can't seem to get it to work.

https://sdw-wsrest.ecb.europa.eu/help/ 

 

Anonymous
Not applicable

@Anonymous I have recently created a simple function that extracts exchange rate information from the site https://exchangeratesapi.io/ which gets its data from the ECB site:

let
    Source = (Date as text) => let
        Source = Json.Document(Web.Contents("https://api.exchangeratesapi.io/" & Date & "?base=USD")),
        rates = Source[rates],
        #"Converted to Table" = Record.ToTable(rates),
        #"Renamed Columns" = Table.RenameColumns(#"Converted to Table",{{"Name", "Currency"}, {"Value", "Rate"}})
    in
        #"Renamed Columns"
in
    Source

Using a datetable or generated range of dates, you can then invoke the custom function like this:

= Table.AddColumn(#"Removed Other Columns", "Rates", each Fn_GetHistoricCurrencyRates(DateTime.ToText([Date],"yyyy-MM-dd")))

Hope that helps!

 

Jan

Hi, I am new to Power BI, I have followed all the steps you have mentioned in the thread, but I am stuck, how do I add api key to the code so I can get the data? 

Also, I am kind of confused about the Fn_GetHistoricExchangeRates part, how do I create this function so I can get it to work with the date table?

I would really appreciate your help 

Anonymous
Not applicable

@Anonymous this looks promising, I stumbled upon that site as well.

I am totally inexperienced with this; "invoke function" lets me enter parameter as date - should I fill in a range of dates and then use the second function you mention? 

Anonymous
Not applicable

@Anonymous I would suggest first creating a table with sequential dates on each row. Then by invoking the function, it will send the dates to the function one by one thus returning the exchange rate info for each day. You can use this example which first generates a list of dates of the past 365 days (this is updated with every refresh) and invokes the function:

 

let
    Source = {Number.From(Date.AddDays(DateTime.Date(DateTime.LocalNow()),-365))..Number.From(DateTime.Date(DateTime.LocalNow()))},
    #"Converted to Table" = Table.FromList(Source, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
    #"Changed Type" = Table.TransformColumnTypes(#"Converted to Table",{{"Column1", type date}}),
    #"Renamed Columns" = Table.RenameColumns(#"Changed Type",{{"Column1", "Date"}}),
    #"Invoked Custom Function" = Table.AddColumn(#"Renamed Columns", "ExchangeRates", each Fn_GetHistoricExchangeRates(Date.ToText([Date],"yyyy-MM-dd"))),
    #"Expanded ExchangeRates" = Table.ExpandTableColumn(#"Invoked Custom Function", "ExchangeRates", {"Currency", "Rate"}, {"Currency", "Rate"}),
    #"Changed Type1" = Table.TransformColumnTypes(#"Expanded ExchangeRates",{{"Rate", type number}, {"Currency", type text}})
in
    #"Changed Type1"

In order for it to work you should create a function named Fn_GetHistoricExchangeRates, by using the code in my previous post.

 

Hope that helps!


Jan

Just note that this cannot be used in Power BI Service, it falls under a dynamic dataset and cannot be refreshed:

https://docs.microsoft.com/en-us/power-bi/connect-data/refresh-data#refresh-and-dynamic-data-sources

You can rephrase the query like this using RelativePath (see Chris Webb's excellent blog about this workaround for dynamic datasources):

 

 

let
    Source = (Date as text) => let
        Source = Json.Document(
            Web.Contents("https://api.exchangeratesapi.io/",
             [RelativePath = "Date",
             Query = 
                [base="USD"]])),
        rates = Source[rates],
        #"Converted to Table" = Record.ToTable(rates),
        #"Renamed Columns" = Table.RenameColumns(#"Converted to Table",{{"Name", "Currency"}, {"Value", "Rate"}})
    in
        #"Renamed Columns"
in
    Source

 

 

Helpful resources

Announcements
Microsoft Fabric Learn Together

Microsoft Fabric Learn Together

Covering the world! 9:00-10:30 AM Sydney, 4:00-5:30 PM CET (Paris/Berlin), 7:00-8:30 PM Mexico City

PBI_APRIL_CAROUSEL1

Power BI Monthly Update - April 2024

Check out the April 2024 Power BI update to learn about new features.

April Fabric Community Update

Fabric Community Update - April 2024

Find out what's new and trending in the Fabric Community.

Top Solution Authors
Top Kudoed Authors