【问题标题】:How to allow time to refresh BDH formula from Bloomberg via VBA in Excel?如何留出时间通过 Excel 中的 VBA 从 Bloomberg 刷新 BDH 公式?
【发布时间】:2021-08-11 01:29:41
【问题描述】:

我正在运行一个宏,它在其中选择一个单元格中的代码,将其粘贴到另一个链接到 BDH 公式的代码中。然后,它会复制 Bloomberg 带来的其中一个值,然后将其复制并粘贴到另一个单元格中。

宏重复 20 个代码,所以我将它放在 for 语句中。宏不会“给彭博时间”来刷新。

我试过application.waitapplication.run等。

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

【问题讨论】:

  • @DS_London 提供的答案是最好的方法:将您的代码转换为使用 blpapicomlib2。一开始可能看起来很吓人,但如果你要做这种事情,那么值得花时间。更同步的方法是从stackoverflow.com/a/35511699/4258124 添加类似Check_API 的内容,并在数据从BB 返回后开始循环的下一部分。

标签: excel vba outlook-addin bloomberg


【解决方案1】:

这个问题经常出现(事实上我自己也问过),所以这里是我在代码中使用的解决方案,以防它对其他人有用。问题是 BDH() 电子表格函数是异步的,即它立即返回,在后台获取数据,然后在完成时告诉 Excel。由于 Excel 只有一个执行线程,因此只有在处理完 VBA 子例程后才会响应此回调。

递归调用 VBA 函数(参见类似问题的其他答案)以等待 BDH 数据返回的替代方法是编写一个同步 VBA 电子表格函数。根据您对 VBA 的信心程度,您可能想尝试这种方法。我也有等效的 BDP/BDS 函数调用,但这里省略了。

此函数直接调用 Bloomberg 数据 API,直到请求完成才返回。 它不提供 BDH 调用的所有选项(但如果需要,可以将这些选项添加到代码中)并且只返回 每日数据,以最近可用的数据结尾。一个优点是数据以数组的形式返回,因此可以用作其他 Excel 函数的数组参数。

用法: =getBloomiHistory(ticker,fields,startDate,includeDates)

参数:

  • ticker:任何 Bbg Ticker(例如“EUSA2 Curncy”)

    字段:任何 Bbg 历史字段,或字段数组(例如“PX_MID”)

    startDate:作为 Excel 日期的特定开始日期(例如 '21-May-2021')或字符串(例如,'20210521' 或 '-1CY')

    includeDates:默认为 True。如果 False 则返回系列不 有日期,并且是单个值向量。由于这是一个数组函数,返回的数据可以直接作为其他函数的参数。

返回:包含从 startDate 到今天的历史日期的变体。

例子:

注意。为了运行代码,需要在工具/参考中勾选对 Bloomberg COM API 的引用。我更喜欢使用引用进行早期绑定,但您可以使用 VBA CreateObject("blpapicom2.Session") 代替 New() 调用切换到后期绑定,并将所有对象定义为 Object,尽管您需要找出所有 BlpApi 常量定义也可以使用 VBA IDE 中的对象浏览器(按 F2)。

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,它基本上可以做同样的事情,但速度要快一些。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-12-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多