Related Topics
George (3)
It's often desirable to get live financial data and everyone knows. XML is the thing to use but actually writing programs that work takes a bit of trouble. Plus, once you've got the data you need to display it.
The Treasury reports yields on its constant-maturity bonds daily and produces an XML feed to retrieve them. This is an Excel function that returns a string with the most-recent yield curve data for a specified maturity.
Function TreasuryRates(Optional Maturity As String = "BC_10YEAR") As String
' This Excel VBA function returns a string with
' the most-recent constant-maturity Treasury bond yield specified
' The default is the 10-year rate
' Before you start, read this:
' https://stackoverflow.com/questions/11245733/declaring-early-bound-msxml-object-throws-an-error-in-vba
' The Maturity input argument is any one of the elements
' following the colon in the <d: ... nodes are shown in a sample of the XML produced by the Treasury
' On December 4, 2012
' =TreasuryRates() returned 1.62
' =TreasuryRates("BC_30YEAR") returned 2.78
' <entry>
' <content type="application/xml">
' <m:properties>
' <d:Id m:type="Edm.Int32">5738</d:Id>
' <d:NEW_DATE m:type="Edm.DateTime">2012-12-04T00:00:00</d:NEW_DATE>
' <d:BC_1MONTH m:type="Edm.Double">0.07</d:BC_1MONTH>
' <d:BC_3MONTH m:type="Edm.Double">0.1</d:BC_3MONTH>
' <d:BC_6MONTH m:type="Edm.Double">0.15</d:BC_6MONTH>
' <d:BC_1YEAR m:type="Edm.Double">0.18</d:BC_1YEAR>
' <d:BC_2YEAR m:type="Edm.Double">0.25</d:BC_2YEAR>
' <d:BC_3YEAR m:type="Edm.Double">0.34</d:BC_3YEAR>
' <d:BC_5YEAR m:type="Edm.Double">0.63</d:BC_5YEAR>
' <d:BC_7YEAR m:type="Edm.Double">1.04</d:BC_7YEAR>
' <d:BC_10YEAR m:type="Edm.Double">1.62</d:BC_10YEAR>
' <d:BC_20YEAR m:type="Edm.Double">2.36</d:BC_20YEAR>
' <d:BC_30YEAR m:type="Edm.Double">2.78</d:BC_30YEAR>
' <d:BC_30YEARDISPLAY m:type="Edm.Double">2.78</d:BC_30YEARDISPLAY>
' </m:properties>
' </content>
' </entry>
' This function returns a string; the String_to_Number function
' defined with my GetQuote function will convert to a string number to double
Dim TreasuryXMLstream As MSXML2.DOMDocument
Dim DNodes As MSXML2.IXMLDOMNodeList
Dim DNode As MSXML2.IXMLDOMNode
Dim success As Boolean
Dim URL As String, _
url_part1 As String, _
url_this_month As String, _
url_part2 As String, _
url_this_year As String
Dim point As Integer
On Error GoTo HandleErr
' create the XML request URL for today's month and year
' -----------------------------------------------------
' this one returns more than 5,700 entries (25+ years?)
' URL = "https://data.treasury.gov/feed.svc/DailyTreasuryYieldCurveRateData"
url_part1 = "https://data.treasury.gov/feed.svc/DailyTreasuryYieldCurveRateData?$filter=month(NEW_DATE)%20eq%20"
url_part2 = "%20and%20year(NEW_DATE)%20eq%20"
iInt = Month(Now)
url_this_month = LTrim(Str(iInt))
iInt = Year(Now)
url_this_year = LTrim(Str(iInt))
' this is used to test whether the month we requested had no data
' ---------------------------------------------------------------
TreasuryRates = "empty"
' set up to pull in the XML stream
' --------------------------------
Set TreasuryXMLstream = New MSXML2.DOMDocument
TreasuryXMLstream.async = False ' wait for completion
TreasuryXMLstream.validateOnParse = False ' do not validate the XML stream
TryAgain:
URL = url_part1 & url_this_month & url_part2 & url_this_year
' pull in the XML
' ---------------
fSuccess = TreasuryXMLstream.Load(URL) ' load the XML stream
If Not success Then ' quit on failure
MsgBox "error loading Treasury XML stream"
Exit Function
End If
' Iterate through the <d: nodes looking for the <d:Maturity
' ---------------------------------------------------------
' this assumes
' 1. the last node in the XML stream returned to us is the <entry> node we want
' 2. the last node in the <entry> node is a <content node
' 3. the last node in the <content node is an <m:properties> node ...
' 4. ... which contains the <d:BC_10YEAR (or whatever) nodes
Set DNodes = TreasuryXMLstream.DocumentElement.LastChild.LastChild.LastChild.ChildNodes
' entry content m d's
For Each DNode In DNodes
If DNode.BaseName = Maturity Then
TreasuryRates = DNode.Text
Exit Function
End If
Next DNode
' test for no entries (first day of the month on a Saturday, for example, has no entries for this month)
' go to a prior month in that case
If TreasuryRates = "empty" Then
' go through twice, and we assume the input parameter is wrong
TreasuryRates = Maturity & " is not a valid parameter for TreasuryRates function"
url_this_month = Format(DateSerial(Year(Date), Month(Date) - 1, 1), "mm")
url_this_year = Format(DateSerial(Year(Date), Month(Date) - 1, 1), "yyyy")
GoTo TryAgain
End If
' error handlers
' --------------
ExitHere:
Exit Function
HandleErr:
MsgBox "Error " & Err.Number & ": " & Err.Description
Resume ExitHere
Resume
End Function
Thanks to declaring early bound msxml object throws an error in vba for both the clue and the picture
My thanks to Encode / Decode HTML Entities
Originally published: Tuesday, December 04, 2012; most-recently modified: Friday, June 07, 2019