it-swarm.com.ru

Данные Bloomberg не заполняются до завершения макроса Excel VBA

Я запускаю макрос в пустой книге Excel 2007 на ПК с лицензией Bloomberg. Макрос вставляет функции Bloomberg в sheet1, которые извлекают данные кривой доходности. Результаты некоторых дополнительных функций зависят от завершения первых функций и правильного отображения данных Бберга. Когда я прохожу программу, отображается только «# N/A Requesting Data». , «. вместо результатов запроса, независимо от того, насколько медленно я иду. Поскольку некоторые функции зависят от заполнения строковых и числовых полей, программа обнаруживает ошибку во время выполнения в этом коде. Когда я прекращаю отладку - полностью заканчиваю запуск программы - появляются все значения Бберга, которые должны были заполниться. Я хочу, чтобы эти значения появлялись во время работы программы.

Я пытался использовать комбинацию 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

Частный 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

9
Diana Tortolini

Чтобы обойти эту проблему, нужно поместить все подпрограммы и т.д., Которые вы хотите запустить после загрузки данных Bloomberg, в другую подпрограмму. Вы должны делать это каждый раз, когда звоните в 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

Надеюсь, это поможет

6
CoreyB

Я погуглил BloombergUI.RefreshAllStaticData и был сразу же переведен на эту страницу Mr Excel: http://www.mrexcel.com/forum/showthread.php?t=414626

Мы не должны публиковать ответы, которые являются только ссылками в случае, если эта ссылка исчезнет и заберет ответ. Тем не менее, я не уверен, что понимаю вопрос или ответ достаточно хорошо, чтобы суммировать его.

Ссылка Google, вероятно, будет существовать в обозримом будущем.

В рамках г-на Excel цепочка состоит из: доски объявлений MrExcel> Форумы вопросов> Вопросы Excel> Ссылки и макросы Bloomberg.

Ключевая информация выглядит так:

На вашем терминале Bloomberg, если вы введете WAPI <GO>, вы найдете списки API Bloomberg и загружаемые примеры.

Используя информацию справочного файла в этой области, мы можем создать более надежное решение для этого с помощью библиотеки типов данных 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

После того, как вы опробовали решение Mr Excel, возможно, вы сможете обновить этот ответ для будущих посетителей. 

4
Tony Dallimore

Я собрал некоторую информацию со всего Интернета и написал, что 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

Любой комментарий приветствуется. Возможное улучшение может заключаться в том, чтобы позволить рабочей книге и/или рабочему листу быть вводом функции, но я действительно не видел необходимости в этом.

Ура

1
Dave

Здравствуйте, я думаю, что нашел решение этой проблемы, и я действительно хочу поделиться этим с вами, ребята.

Прежде чем начать с реального ответа я хочу убедиться, что все понимают, как на самом деле работает 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. х = 3
  2. Application.OnTime Now + TimeSerial (0, 0, 2), «Sub2»
  3. Затем через 2 секунды ожидания в Sub Second () x = x + 1, следовательно, 4
  4. Наконец, мы возвращаемся к Sub First (), где x = 2 * x, так что в конце x равен 8.

Оказывается, это не так, как работает VBA; вместо этого происходит следующее:

  1. х = 3
  2. Application.OnTime Now + TimeSerial (0, 0, 2), «Sub2»
  3. Здесь оставшийся код в Sub First () выполняется до КОНЦА, прежде чем переключиться на Sub Second ().
  4. Таким образом, x = 2 * x выполняется сразу же вместе с каждой строкой кода, которая появляется до конца Sub First (). Теперь х равен 6.
  5. Наконец, после 2 секунд ожидания он выполняет инструкцию в Sub Second (), x = x + 1, так что в конце x равен 7

Это происходит независимо от того, сколько времени вы заставляете приложение ждать. Так, например, если в моем примере, после 

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

VBA потребовалось 10 секунд, чтобы выполнить линию

x = 2*x

ему все равно придется завершить выполнение этой команды перед переключением на Sub Second ().

ПОЧЕМУ IS ЭТО ВАЖНО?

Потому что в свете того, что я только что объяснил, теперь я могу показать вам свое решение вопроса ОП. Тогда вы можете адаптировать его к вашим потребностям. 

И да!!! Это работает с For Loops тоже!

РЕШЕНИЕ

У меня есть две подпрограммы:

  1. BLPDownload (), где я обновляю рабочую книгу, и мне приходится ждать загрузки значений, чтобы выполнить какой-то другой код ...

  2. BLPCheckForRefresh (), где я проверяю, все ли данные были загружены

Так же, как и раньше, я объявляю две переменные с областью действия модуля

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 () и снова выходит из текущей подпрограммы. 

Эта забавная игра продолжается и продолжается до тех пор, пока у нас больше не будет # N/A Запрос данных в нашем 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

И это цикл, в котором я прохожу каждую ячейку в используемом диапазоне в поисках # 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 Loops.  

При этом я хочу отметить, что, по моему мнению, лучшее решение этой проблемы - это использование API Bloomberg, как это предложил Тони Даллимор.

Надеюсь это поможет!!

0
Hard Core