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

时间:2011-12-29 15:37:27

标签: excel-vba excel-2007 bloomberg vba excel

我正在使用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

End Sub

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

End Sub

4 个答案:

答案 0 :(得分:6)

解决此问题的一种方法是在将bloomberg数据拉入另一个子数据库之后放置要运行的所有子等。每次拨打彭博信息时都必须这样做。如果在Application.OnTime Now + TimeValue(“00:00:15”)之后调用“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 :(得分:4)

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

如果链接消失并接受答案,我们不应该发布只有链接的帖子答案。但是,我不确定我是否完全理解了这个问题或答案。

在可预见的未来,Google链接可能会存在。

在Excel先生中,该连锁店是:MrExcel留言板&gt;问题论坛&gt; Excel问题&gt;彭博链接和宏。

关键信息似乎是:

如果您输入WAPI&lt;在您的Bloomberg终端上GO&gt;你会找到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先生的解决方案,也许您可​​以更新此答案,以便将来访问者受益。

答案 2 :(得分:1)

我从网络上收集了一些信息,并写了一下与目前为止我发现的所有内容相比,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

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

干杯

答案 3 :(得分:0)

您好我认为我找到了解决此问题的方法,我真的想与您分享。

在开始真正的答案之前我想确保每个人都了解Application.OnTime的实际工作方式。如果您已经知道,那么您可以安全地跳到下面的解决方案

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

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

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

  1. x = 3
  2. Application.OnTime Now + TimeSerial(0,0,2),&#34; Sub2&#34;
  3. 然后在等待2秒后,在Sub Second()x = x + 1,因此4
  4. 最后我们回到Sub First(),其中x = 2 * x,因此最后x等于8。
  5. 事实证明,这不是VBA运作的方式;相反的是:

    1. x = 3
    2. Application.OnTime Now + TimeSerial(0,0,2),&#34; Sub2&#34;
    3. 这里Sub First()中的重映射代码执行到THE END,然后切换到Sub Second()。
    4. 因此,x = 2 * x会立即执行,直到Sub First()结束时出现的每一行代码。现在x等于6.
    5. 最后,等待2秒后,它执行Sub Second()中的指令,x = x + 1,这样最后x等于7
    6. 这与您使应用程序等待的时间无关。例如,如果在我的例子中,在

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

      VBA用了10秒钟来执行

      x = 2*x
      

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

      为什么这么重要?

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

      并且是的!这也适用于For Loops!

      解决方案

      我有两个子程序:

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

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

      3. 就像之前一样,我用Module-Level Scope

        声明了两个变量
        Dim firstRefreshDone As Boolean, Refreshing As Boolean
        
        Sub BLPDownload()
        
        CHECK:
        

        我在下面做的是:

        • 检查我是否已告诉VBA刷新工作簿。当然,第一次运行宏时你没有;因此firstRefreshDone = False,它进入if语句的这个块。
        • 接下来它调用另一个Sub BLPCheckForRefresh()并退出当前的子程序。

        这就是诀窍。在调用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(),它再次退出当前的子程序。

        这个有趣的游戏一直持续到我们的UsedRange不再有#N / A请求数据

            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 BLPDownload()

            Call BLPDownload
        End Sub
        

        所以这是我的解决方案。我为我工作并使用另一个肮脏的技巧,它总是利用GoTo语句和另一个模块级范围变量来计算迭代次数也可以在For循环中使用这个结构。 < / p>

        话虽如此,我想指出,在我看来,这个问题的最佳解决方案是使用Tony Dallimore建议的Bloomberg API。

        希望这会有所帮助!!