首页 文章

在Excel VBA宏完成之前,Bloomberg数据不会填充

提问于
浏览
9

我在具有Bloomberg许可证的PC上的空白Excel 2007工作簿中运行宏 . 宏将Bloomberg函数插入到sheet1中,以获取收益率曲线数据 . 一些附加功能的结果取决于完成和正确显示Bberg数据的第一个功能 . 当我单步执行程序时,它只显示'#N / A请求数据 . . “ . 而不是查询的结果,无论我走得多慢 . 由于某些函数依赖于填充的字符串和数字字段结果,因此程序会在该代码处遇到运行时错误 . 当我停止调试 - 完全结束运行程序 - 然后出现应该填充的所有Bberg值 . 我希望在程序仍在运行时显示这些值 .

我尝试使用DoEvents和Application.OnTime()的组合将控制权返回给操作系统,并使程序等待很长时间进行数据更新,但都没有工作 . 任何想法都会有所帮助 . 我的代码如下 . wb是一个全局级工作簿,ws1是一个全局级工作表 .

Public Sub Run_Me()

'Application.DisplayAlerts = False
'Application.ScreenUpdating = False

Call Populate_Me
Call Format_Me

'Application.DisplayAlerts = True
'Application.ScreenUpdating = True

结束子

Private Sub Populate_Me()

Dim lRow_PM As Integer
Dim xlCalc As XlCalculation

Set wb = ThisWorkbook
Set ws1 = wb.Sheets(1)

'clear out any values from previous day
If wb.Sheets(ws1.Name).Range("A1").Value <> "" Then
    wb.Sheets(ws1.Name).Select
    Selection.ClearContents
End If


xlCalc = Application.Calculation
Application.Calculation = xlCalculationAutomatic

Range("A1").Value = "F5"
Range("B1").Value = "Term"
Range("C1").Value = "PX LAST"

Range("A2").Select
ActiveCell.FormulaR1C1 = "=BDS(""YCCF0005 Index"",""CURVE_MEMBERS"",""cols=1;rows=15"")"
BloombergUI.RefreshAllStaticData

Range("B2").Select
ActiveCell.FormulaR1C1 = "=BDS(""YCCF0005 Index"",""CURVE_TERMS"",""cols=1;rows=15"")"
BloombergUI.RefreshAllStaticData

Application.OnTime Now + TimeValue("00:00:10"), "HardCode"

'******more code*******'
End Sub

Sub HardCode()

Range("C2").Select
ActiveCell.FormulaR1C1 = "=BDP($A2,C$1)"
BloombergUI.RefreshAllStaticData

结束子

4 回答

  • 6

    解决这个问题的一种方法是在将bloomberg数据拉入另一个子数据库之后放置您想要运行的所有子类 . 每次拨打彭博信息时都必须这样做 . 如果在Application.OnTime Now TimeValue(“00:00:15”)之后调用“master”子中的另一个sub,它将失败 - 您必须将所有子跟随放入新的master子 .

    例如:而不是

    Sub Master1()
    Application.Run "RefreshAllStaticData"
    Application.OnTime Now + TimeValue("00:00:15"), "OtherSub1"
    'This will cause the Bloomberg Data to not refresh until OtherSub2 and 3 have run
    OtherSub2
    OtherSub3
    End Sub
    

    它应该是

    Sub Master1()
    Application.Run "RefreshAllStaticData"
    Application.OnTime Now + TimeValue("00:00:15"), "Master2"
    End Sub
    
    Sub Master2()
    OtherSub1
    OtherSub2
    OtherSub3
    End Sub
    

    希望有所帮助

  • 1

    我用Google搜索了BloombergUI.RefreshAllStaticData并立即被带到了Excel先生页面:http://www.mrexcel.com/forum/showthread.php?t=414626

    我们不应该发布只有链接消失并且用它来回答的链接的帖子 . 但是,我不确定我是否理解这个问题或答案,以便总结它 .

    谷歌链接可能会存在于可预见的未来 .

    在Excel之前,链接是:MrExcel留言板>问题论坛> Excel问题> Bloomberg链接和宏 .

    关键信息似乎是:

    在您的Bloomberg终端上,如果您输入WAPI <GO>,您将找到Bloomberg API的列表和可下载的示例 .

    使用该区域中的帮助文件信息,我们可以使用Bloomberg数据类型库为此构建更强大的解决方案 . 转到工具|引用并添加对此库的引用 . 然后可以使用此代码填充单元格:

    Sub Test2()
        Dim vResults, vSecurities, vFields
        Dim objBloomberg As BLP_DATA_CTRLLib.BlpData
    
        'fill our arrays - must be 1 dimension so we transpose from the worksheet
        With Application.WorksheetFunction
            vSecurities = .Transpose(Sheet1.Range("B2:B4").Value)
            vFields = .Transpose(.Transpose(Range("C1:H1").Value))
        End With
    
        Set objBloomberg = New BLP_DATA_CTRLLib.BlpData
        objBloomberg.AutoRelease = False
    
        objBloomberg.Subscribe _
                Security:=vSecurities, _
                cookie:=1, _
                Fields:=vFields, _
                Results:=vResults
    
        Sheet1.Range("C2:H4").Value = vResults
    End Sub
    

    一旦您尝试了Excel先生的解决方案,也许您可以更新此答案,以便将来访问者受益 .

  • 0

    我收集了一些来自网络的信息并写了一下imho是一个改进版本,与我迄今为止发现的所有内容相比:

    Private WaitStartedAt As Double
    Private Const TimeOut As String = "00:02:00"
    
    Public Function BloomCalc(Callback As String) As Boolean
        Dim rngStillToReceive As Range
        Dim StillToReceive As Boolean
        Dim ws As Worksheet
        StillToReceive = False
        If WaitStartedAt = 0 Then
            WaitStartedAt = TimeValue(Now())
        End If
        If TimeValue(Now()) >= WaitStartedAt + TimeValue(TimeOut) Then
            GoTo errTimeOut
        End If
        For Each ws In ActiveWorkbook.Worksheets
            Set rngStillToReceive = ws.UsedRange.Find("*Requesting Data*", LookIn:=xlValues)
            StillToReceive = StillToReceive Or (Not rngStillToReceive Is Nothing)
        Next ws
        If StillToReceive Then
            BloomCalc = False
            Application.OnTime Now + (TimeSerial(0, 0, 1)), Callback
        Else
            WaitStartedAt = 0
            BloomCalc = True
        End If
        Exit Function
    errTimeOut:
        Err.Raise -1, , "BloomCalc: Timed Out. Callback = " & Callback
    End Function
    

    它应该是一个任意的任务,通过调用像DoSomething()这样的子

    Public Sub DoSomething() 
        DoSomethingCallback
    End Function
    

    这称为“回调”函数,它将调用自身,直到数据刷新或达到时间限制

    Public Sub AutoRunLcbCallback()
        If BloomCalc("AutoRunLcbCallback") Then
            MsgBox "Here I can do what I need with the refreshed data"
            ' for instance I can close and save the workbook
            ActiveWorkbook.Close True
        End If
    End Sub
    

    任何评论表示赞赏 . 可能的改进可能是允许工作簿和/或工作表作为函数的输入,但我真的没有看到它的需要 .

    干杯

  • 4

    你好,我想我找到了解决这个问题的方法,我真的想和你们分享一下 .

    在开始真正的答案之前 I want to make sure everyone understands how Application.OnTime actually works . 如果您已经知道,那么您可以安全地跳到下面的 THE SOLUTION .

    让我们创建一个 TOY EXAMLPE 示例,其中包含两个子例程Sub First()和Sub Second()以及一个在外部声明的变量x,因此它在整个Module中具有范围

    Dim x as integer
    Sub First()
        x = 3
        Application.OnTime Now + TimeSerial(0, 0, 2), "Sub2"
        x = 2*x
    End Sub
    
    Sub Second() 
        x = x + 1
    End Sub
    

    我认为命令按以下顺序执行:

    • x = 3

    • Application.OnTime Now TimeSerial(0,0,2),"Sub2"

    • 然后等待2秒后,在Sub Second()x = x 1中,因此4

    • 最后我们回到Sub First(),其中x = 2 * x,因此最后x等于8 .

    It turns out that this is not the way VBA operates; what happens instead is:

    • x = 3

    • Application.OnTime Now TimeSerial(0,0,2),"Sub2"

    • Here the remaing code in Sub First() is executed until THE END, before switching to Sub Second().

    • 所以x = 2 * x立即执行,直到Sub First()结束时出现的每一行代码 . 现在x等于6 .

    • 最后,在等待2秒后,它执行Sub Second()中的指令,x = x 1,这样最后x等于7

    这与您创建应用程序的时间无关等待 . 因此,例如,如果在我的例子中,之后

    Application.OnTime Now + TimeSerial(0, 0, 2), "Sub2"
    

    VBA花了10秒钟执行该线

    x = 2*x
    

    在切换到Sub Second()之前,它仍然必须完成该命令的执行 .

    WHY IS THIS IMPORTANT?

    因为根据我刚才解释的内容,我现在可以向您展示我对OP问题的解决方案 . 然后,您可以根据自己的需求进行调整 .

    And YES!!! This works with For Loops too!

    THE SOLUTION

    我有两个子程序:

    • BLPDownload()我刷新工作簿的地方,我必须等待值被下载才能执行其他代码......

    • BLPCheckForRefresh(),我检查是否已下载所有数据

    就像以前一样,我用Module-Level Scope声明了两个变量

    Dim firstRefreshDone As Boolean, Refreshing As Boolean
    
    Sub BLPDownload()
    
    CHECK:
    

    我在下面做的是:

    • 检查我是否已告诉VBA刷新工作簿 . 当然,第一次运行宏时你没有;因此firstRefreshDone = False,它进入if语句的这个块 .

    • 接下来它调用另一个Sub BLPCheckForRefresh()并退出当前的子程序 .

    And this is the trick. To Exit the Subroutine after calling Application.OnTime*

    在BLPCheckForRefresh()里面发生了什么

    • 我设置firstRefreshDone = True的值

    • 检查在UsedRange中,我是否有#N / A请求数据的单元格 . 如果我有,则Refreshing = True的值 .

    • 最后我回调Sub BLPDownload()

    If Not firstRefreshDone Then
        Application.Run "RefreshEntireWorkbook"
        Application.Run "RefreshAllStaticData"
        Application.OnTime Now + TimeSerial(0, 0, 4), "BLPCheckForRefresh"
        Exit Sub
    

    这一次,firstRefreshDone = True所以,如果刷新完成,它会转到AFTER_REFRESH,您可以在其中放置您想要的所有代码,否则......

    ElseIf Not Refreshing Then
            GoTo AFTER_REFRESH
    

    如果刷新没有完成,即如果我有#N / A请求数据的单元,它调用另一个Sub BLPCheckForRefresh(),它再次退出当前的子程序 .

    This funny game goes on and on until we have no more #N/A Requesting Data in our UsedRange

    Else
            Refreshing = False
            Application.OnTime Now + TimeSerial(0, 0, 4), "BLPCheckForRefresh"
            Exit Sub
        End If
    
    AFTER:
        some code ...
    End Sub
    

    这是我检查刷新是否完成的子 .

    Sub BLPCheckForRefresh()
        Dim rng As Range, cl As Range
        Set rng = Foglio1.UsedRange
    

    如上所述,我设置firstRefreshDone = True的值

    firstRefreshDone = True
    

    这是循环,我遍历usedrange中的每个单元格,寻找#N / A请求数据

    On Error Resume Next
        For Each cl In rng
            If InStr(cl.Value2, "#N/A Request") > 0 Then
                Refreshing = True
                Exit For
            End If
        Next cl
        On Error GoTo 0
    

    最后我回电Sub Sub BLPDownload()

    Call BLPDownload
    End Sub
    

    所以这是我的解决方案 . 我为我和另一个肮脏的技巧工作,它总是利用GoTo语句和另一个模块级范围变量来保持迭代次数的计数 it is possible to use this structure in For Loops too.

    That being said I want to point out that in my opinion the best solution to this problem is to use Bloomberg API as suggested by Tony Dallimore.

    希望这可以帮助!!

相关问题