通过Excel中的VBA从彭博社刷新BDH公式
我目前正在运行一个宏,它在一个单元格中选择一个标记,粘贴到另一个单元格中,该标记链接到BDH公式。然后,它复制彭博带来的一个值,然后复制并粘贴到另一个单元格中。宏重复了20个代码,所以我把它放在for语句中,但当我运行宏时,它不会给彭博社“时间”刷新。你知道我怎么修吗?我已经尝试了application.wait、application.run等 这是我目前的代码:通过Excel中的VBA从彭博社刷新BDH公式,vba,outlook-addin,bloomberg,Vba,Outlook Addin,Bloomberg,我目前正在运行一个宏,它在一个单元格中选择一个标记,粘贴到另一个单元格中,该标记链接到BDH公式。然后,它复制彭博带来的一个值,然后复制并粘贴到另一个单元格中。宏重复了20个代码,所以我把它放在for语句中,但当我运行宏时,它不会给彭博社“时间”刷新。你知道我怎么修吗?我已经尝试了application.wait、application.run等 这是我目前的代码: Sub Atualizar_Relatorio() Dim Cont As Integer 'Dim Ticker As Str
Sub Atualizar_Relatorio()
Dim Cont As Integer
'Dim Ticker As String
Cont = 0
For Cont = 0 To 20
' Copy and paste the ticker in the cell where bloomber formula is linked
ThisWorkbook.Sheets("Report").Cells(4 + Cont, 4).Copy
ThisWorkbook.Sheets("Historical").Cells(17, 2).PasteSpecial Paste:=xlPasteValues
' Copy the values from BDH and paste in the other worksheet
ThisWorkbook.Sheets("Historical").Cells(19, 4).Copy
ThisWorkbook.Sheets("Report").Cells(4 + Cont, 5).PasteSpecial Paste:=xlPasteValues
ThisWorkbook.Sheets("Report").Cells(4 + Cont, 20).Copy
ThisWorkbook.Sheets("Report").Cells(4 + Cont, 7).PasteSpecial Paste:=xlPasteValues
ThisWorkbook.Sheets("Historical").Cells(16, 8).Copy
ThisWorkbook.Sheets("Report").Cells(4 + Cont, 9).PasteSpecial Paste:=xlPasteValues
ThisWorkbook.Sheets("Historical").Cells(19, 8).Copy
ThisWorkbook.Sheets("Report").Cells(4 + Cont, 13).PasteSpecial Paste:=xlPasteValues
Next
End Sub
这个问题经常出现(事实上我自己也问过),所以这里是我在代码中使用的解决方案,以防它对其他人有用。问题在于BDH()电子表格函数是异步的,即它立即返回,在后台获取数据,然后在完成时告诉Excel。由于Excel只有一个执行线程,因此它仅在完成VBA子程序的处理后对该回调作出反应 递归调用VBA函数(参见类似问题的其他答案)以等待BDH数据返回的另一种方法是编写同步VBA电子表格函数。根据您对VBA的信心程度,您可能希望尝试这种方法。我还有等效的BDP/BDS函数调用,但在这里省略了它 此函数直接调用彭博数据API,在请求完成之前不会返回。它不提供BDH调用的所有选项(但如果需要,可以将这些选项添加到代码中),只返回每日数据,以最新可用数据结尾。另外一个优点是,数据以数组的形式返回,因此可以用作其他Excel函数的数组参数 用法: =getBloomiHistory(股票代码、字段、起始日期、包含日期) 参数:
- 股票代码:任何Bbg股票代码(如“EUSA2 Curncy”) 字段:任何Bbg历史字段或字段数组(例如“PX_MID”) startDate:作为Excel日期的特定开始日期(例如 “2021年5月21日”),或字符串(例如“20210521”或“-1CY”) includeDates:默认为True。如果为False,则返回序列不存在 具有日期,并且是值的单个向量。由于这是一个数组函数,因此返回的数据可以直接用作其他函数的参数
CreateObject(“blpapicom2.Session”)
来代替New()调用,并将所有对象定义为Object,但随后还需要使用VBA IDE中的对象浏览器(点击F2)查找所有BlpApi常量定义
VBA代码:
Option Explicit
Dim g_Session As blpapicomLib2.Session
Dim g_Service As blpapicomLib2.Service
'Function to set up the Bloomberg session once
Private Function CheckSession() As Boolean
If g_Session Is Nothing Then
Set g_Session = New blpapicomLib2.Session
g_Session.Start
g_Session.OpenService "//blp/refdata"
Set g_Service = g_Session.GetService("//blp/refdata")
End If
CheckSession = True
End Function
Public Function getBloomiHistory(strSecurity As String, rngFields As Variant, vStart As Variant, Optional bIncludeDates As Boolean = True) As Variant
Dim vRet As Variant
CheckSession
Dim req As blpapicomLib2.REQUEST
Set req = g_Service.CreateRequest("HistoricalDataRequest")
req.GetElement("securities").AppendValue strSecurity
Dim vFields As Variant
vFields = rngFields
Dim strFields() As String
Dim lFields As Long
If IsArray(vFields) Then
Dim lr, lc, lRows, lCols As Long
lRows = UBound(vFields, 1)
lCols = UBound(vFields, 2)
lFields = lRows * lCols
ReDim strFields(1 To lFields) As String
Dim lstr As Long
lstr = 1
For lr = 1 To lRows
For lc = 1 To lCols
strFields(lstr) = vFields(lr, lc)
req.GetElement("fields").AppendValue vFields(lr, lc)
lstr = lstr + 1
Next lc
Next lr
Else
ReDim strFields(1) As String
lFields = 1
strFields(1) = vFields
req.GetElement("fields").AppendValue vFields
End If
req.Set "nonTradingDayFillOption", "NON_TRADING_WEEKDAYS"
req.Set "periodicityAdjustment", "ACTUAL"
req.Set "periodicitySelection", "DAILY"
Dim strStart As String
If IsDate(vStart) Then
strStart = Format(vStart, "yyyymmdd")
Else
strStart = vStart
End If
'endDate defaults to Today
req.Set "startDate", strStart
g_Session.SendRequest req
Dim evt As blpapicomLib2.Event
Dim msgIt As blpapicomLib2.MessageIterator
Dim msg As blpapicomLib2.Message
Dim eltRef As blpapicomLib2.Element
Dim eltSecurities As blpapicomLib2.Element
Dim eltSecurity As blpapicomLib2.Element
Dim eltData As blpapicomLib2.Element
Dim eltFieldDataArray As blpapicomLib2.Element
Dim eltDate As blpapicomLib2.Element
Dim eltValue As blpapicomLib2.Element
Dim dt As Date
Dim vt As Variant
Dim bExit As Boolean
bExit = False
Do While Not bExit
Set evt = g_Session.NextEvent
If (evt.EventType = PARTIAL_RESPONSE Or evt.EventType = RESPONSE) Then
Set msgIt = evt.CreateMessageIterator
Do While (msgIt.Next)
Set msg = msgIt.Message
Set eltSecurities = msg.GetElement("securityData")
Set eltFieldDataArray = eltSecurities.GetElement("fieldData")
Dim nItems As Integer
nItems = eltFieldDataArray.NumValues
If bIncludeDates Then
ReDim vRet(1 To nItems, 1 To lFields + 1) As Variant
Else
ReDim vRet(1 To nItems, 1 To lFields) As Variant
End If
Dim nItem As Integer
Dim nValues As Integer
Dim d As Double
For nItem = 0 To nItems - 1
Set eltData = eltFieldDataArray.GetValueAsElement(nItem)
nValues = eltData.NumElements
Dim lOffset As Long
lOffset = 0
If bIncludeDates Then
Set eltDate = eltData.GetElement(0)
dt = eltDate.Value
vRet(nItem + 1, 1) = dt
lOffset = 1
End If
Dim lField As Long
For lField = 1 To lFields
If eltData.HasElement(strFields(lField)) Then
Set eltValue = eltData.GetElement(strFields(lField))
vt = eltValue.Value
vRet(nItem + 1, lField + lOffset) = vt
Else
vRet(nItem + 1, lField + lOffset) = CVErr(xlErrNA)
End If
Next lField
Next nItem
Loop
If (evt.EventType = RESPONSE) Then bExit = True
End If
Loop
getBloomiHistory = vRet
End Function
我说“已经使用”,因为我现在使用编译的C++ Excel。XLL,它基本上做同样的事情,但有点快。
< P>这个问题经常出现(实际上我已经问过了),所以这里是我用代码的解决方案,以防它对任何人有用。问题在于BDH()电子表格函数是异步的,即它立即返回,在后台获取数据,然后在完成时告诉Excel。由于Excel只有一个执行线程,因此它仅在完成VBA子程序的处理后对该回调作出反应 递归调用VBA函数(参见类似问题的其他答案)以等待BDH数据返回的另一种方法是编写同步VBA电子表格函数。根据您对VBA的信心程度,您可能希望尝试这种方法。我还有等效的BDP/BDS函数调用,但在这里省略了它 此函数直接调用彭博数据API,在请求完成之前不会返回。它不提供BDH调用的所有选项(但如果需要,可以将这些选项添加到代码中),只返回每日数据,以最新可用数据结尾。另外一个优点是,数据以数组的形式返回,因此可以用作其他Excel函数的数组参数 用法: =getBloomiHistory(股票代码、字段、起始日期、包含日期) 参数:- 股票代码:任何Bbg股票代码(如“EUSA2 Curncy”) 字段:任何Bbg历史字段或字段数组(例如“PX_MID”) startDate:作为Excel日期的特定开始日期(例如 “2021年5月21日”),或字符串(例如“20210521”或“-1CY”) includeDates:默认为True。如果为False,则返回序列不存在 具有日期,并且是值的单个向量。由于这是一个数组函数,因此返回的数据可以直接用作其他函数的参数
CreateObject(“blpapicom2.Session”)
来代替New()调用,并将所有对象定义为Object,但随后还需要使用VBA IDE中的对象浏览器(点击F2)查找所有BlpApi常量定义
VBA代码:
Option Explicit
Dim g_Session As blpapicomLib2.Session
Dim g_Service As blpapicomLib2.Service
'Function to set up the Bloomberg session once
Private Function CheckSession() As Boolean
If g_Session Is Nothing Then
Set g_Session = New blpapicomLib2.Session
g_Session.Start
g_Session.OpenService "//blp/refdata"
Set g_Service = g_Session.GetService("//blp/refdata")
End If
CheckSession = True
End Function
Public Function getBloomiHistory(strSecurity As String, rngFields As Variant, vStart As Variant, Optional bIncludeDates As Boolean = True) As Variant
Dim vRet As Variant
CheckSession
Dim req As blpapicomLib2.REQUEST
Set req = g_Service.CreateRequest("HistoricalDataRequest")
req.GetElement("securities").AppendValue strSecurity
Dim vFields As Variant
vFields = rngFields
Dim strFields() As String
Dim lFields As Long
If IsArray(vFields) Then
Dim lr, lc, lRows, lCols As Long
lRows = UBound(vFields, 1)
lCols = UBound(vFields, 2)
lFields = lRows * lCols
ReDim strFields(1 To lFields) As String
Dim lstr As Long
lstr = 1
For lr = 1 To lRows
For lc = 1 To lCols
strFields(lstr) = vFields(lr, lc)
req.GetElement("fields").AppendValue vFields(lr, lc)
lstr = lstr + 1
Next lc
Next lr
Else
ReDim strFields(1) As String
lFields = 1
strFields(1) = vFields
req.GetElement("fields").AppendValue vFields
End If
req.Set "nonTradingDayFillOption", "NON_TRADING_WEEKDAYS"
req.Set "periodicityAdjustment", "ACTUAL"
req.Set "periodicitySelection", "DAILY"
Dim strStart As String
If IsDate(vStart) Then
strStart = Format(vStart, "yyyymmdd")
Else
strStart = vStart
End If
'endDate defaults to Today
req.Set "startDate", strStart
g_Session.SendRequest req
Dim evt As blpapicomLib2.Event
Dim msgIt As blpapicomLib2.MessageIterator
Dim msg As blpapicomLib2.Message
Dim eltRef As blpapicomLib2.Element
Dim eltSecurities As blpapicomLib2.Element
Dim eltSecurity As blpapicomLib2.Element
Dim eltData As blpapicomLib2.Element
Dim eltFieldDataArray As blpapicomLib2.Element
Dim eltDate As blpapicomLib2.Element
Dim eltValue As blpapicomLib2.Element
Dim dt As Date
Dim vt As Variant
Dim bExit As Boolean
bExit = False
Do While Not bExit
Set evt = g_Session.NextEvent
If (evt.EventType = PARTIAL_RESPONSE Or evt.EventType = RESPONSE) Then
Set msgIt = evt.CreateMessageIterator
Do While (msgIt.Next)
Set msg = msgIt.Message
Set eltSecurities = msg.GetElement("securityData")
Set eltFieldDataArray = eltSecurities.GetElement("fieldData")
Dim nItems As Integer
nItems = eltFieldDataArray.NumValues
If bIncludeDates Then
ReDim vRet(1 To nItems, 1 To lFields + 1) As Variant
Else
ReDim vRet(1 To nItems, 1 To lFields) As Variant
End If
Dim nItem As Integer
Dim nValues As Integer
Dim d As Double
For nItem = 0 To nItems - 1
Set eltData = eltFieldDataArray.GetValueAsElement(nItem)
nValues = eltData.NumElements
Dim lOffset As Long
lOffset = 0
If bIncludeDates Then
Set eltDate = eltData.GetElement(0)
dt = eltDate.Value
vRet(nItem + 1, 1) = dt
lOffset = 1
End If
Dim lField As Long
For lField = 1 To lFields
If eltData.HasElement(strFields(lField)) Then
Set eltValue = eltData.GetElement(strFields(lField))
vt = eltValue.Value
vRet(nItem + 1, lField + lOffset) = vt
Else
vRet(nItem + 1, lField + lOffset) = CVErr(xlErrNA)
End If
Next lField
Next nItem
Loop
If (evt.EventType = RESPONSE) Then bExit = True
End If
Loop
getBloomiHistory = vRet
End Function
我说“使用”,因为我现在使用编译的C++ Excel。XLL,它基本上做同样的事情,但速度稍快。
类似的问题:答案DS@伦敦提供的最好的方法是:转换代码使用BLAPPICOLIb2。一开始可能看起来很吓人,但如果你打算做这类事情,花时间是值得的。更同步的方式是