wake-up-neo.com

Bloomberg-Daten werden erst ausgefüllt, wenn das Excel VBA-Makro beendet ist

Ich führe ein Makro in einer leeren Excel 2007-Arbeitsmappe auf einem PC mit einer Bloomberg-Lizenz aus. Das Makro fügt Bloomberg-Funktionen in Sheet1 ein, die Zinskurvendaten abrufen. Die Ergebnisse einiger Zusatzfunktionen hängen davon ab, ob die ersten Funktionen abgeschlossen sind und die Bberg-Daten korrekt angezeigt werden. Wenn ich durch das Programm gehe, wird nur "# N/A Requesting Data" angezeigt. . . ' Anstelle der Ergebnisse der Abfrage, egal wie langsam ich gehe. Da einige der Funktionen davon abhängen, dass Zeichenfolgen- und numerische Feldergebnisse ausgefüllt werden, stößt das Programm bei diesem Code auf einen Laufzeitfehler. Wenn ich das Debuggen beende - und das Programm vollständig beende -, werden alle Bberg-Werte angezeigt, die ausgefüllt sein sollten. Ich möchte, dass diese Werte angezeigt werden, während das Programm noch ausgeführt wird.

Ich habe versucht, eine Kombination aus DoEvents und Application.OnTime () zu verwenden, um die Steuerung an das Betriebssystem zurückzugeben und das Programm lange auf die Datenaktualisierung warten zu lassen, aber keines hat funktioniert. Irgendwelche Ideen wären hilfreich. Mein Code ist unten. wb ist eine Arbeitsmappe auf globaler Ebene und ws1 ist ein Arbeitsblatt auf globaler Ebene.

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

9
Diana Tortolini

Eine Möglichkeit, dieses Problem zu umgehen, besteht darin, alle Subs usw., die Sie ausführen möchten, nachdem Sie die Bloomberg-Daten in ein anderes Sub gezogen haben, zu platzieren. Sie müssen dies jedes Mal tun, wenn Sie Bloomberg-Informationen anrufen. Wenn Sie nach Application.OnTime Now + TimeValue ("00:00:15") ein anderes Sub im "Master" -Unter aufrufen, schlägt dies fehl. Sie müssen alle folgenden Subwoofer in einen neuen Master-Subwoofer einfügen.

Zum Beispiel: Anstelle von

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

Es sollte sein

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

Sub Master2()
OtherSub1
OtherSub2
OtherSub3
End Sub

Hoffentlich hilft das

6
CoreyB

Ich googelte nach BloombergUI.RefreshAllStaticData und wurde sofort zu dieser Mr Excel-Seite weitergeleitet: http://www.mrexcel.com/forum/showthread.php?t=414626

Wir dürfen keine Antworten posten, die nur Links sind, falls dieser Link verschwindet und die Antwort mit sich nimmt. Ich bin mir jedoch nicht sicher, ob ich die Frage oder die Antwort gut genug verstehe, um sie zusammenzufassen.

Der Google-Link wird wahrscheinlich in absehbarer Zeit existieren.

Innerhalb von Mr Excel lautet die Kette: MrExcel Message Board> Fragenforen> Excel-Fragen> Bloomberg-Links und -Makros.

Die wichtigsten Informationen scheinen zu sein:

Wenn Sie auf Ihrem Bloomberg-Terminal WAPI <GO> eingeben, finden Sie eine Auflistung der Bloomberg-API und Beispiele zum Herunterladen.

Mit Hilfe der Hilfedateien in diesem Bereich können wir mithilfe der Bloomberg-Datentypbibliothek eine robustere Lösung dafür erstellen. Gehen Sie zu Extras | Verweise und fügen Sie einen Verweis auf diese Bibliothek hinzu. Dieser Code kann dann zum Auffüllen der Zellen verwendet werden:

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

Wenn Sie die Lösung von Herrn Excel ausprobiert haben, können Sie diese Antwort möglicherweise zum Nutzen der zukünftigen Besucher aktualisieren.

4
Tony Dallimore

Ich habe einige Informationen aus dem Internet gesammelt und geschrieben, was im Vergleich zu allem, was ich bisher gefunden habe, eine verbesserte Version ist:

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

Es sollte eine beliebige Aufgabe sein, indem ein Sub wie DoSomething () aufgerufen wird

Public Sub DoSomething() 
    DoSomethingCallback
End Function

Das ruft eine "Rückruffunktion" auf, die sich selbst aufruft, bis entweder die Daten aktualisiert wurden oder das Zeitlimit erreicht ist

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

Jeder Kommentar ist willkommen. Eine mögliche Verbesserung könnte darin bestehen, die Arbeitsmappe und/oder das Arbeitsblatt als Eingabe für die Funktion zuzulassen, aber ich habe die Notwendigkeit wirklich nicht erkannt.

Prost

1
Dave

Hallo, ich glaube, ich habe eine Lösung für dieses Problem gefunden und möchte diese wirklich mit euch teilen.

Bevor ich mit der eigentlichen Antwort beginne möchte ich sicherstellen, dass jeder versteht, wie Application.OnTime tatsächlich funktioniert . Und wenn Sie es bereits wissen, können Sie sicher zu DIE LÖSUNG weiter unten springen.

Lassen Sie uns ein TOY EXAMLPE - Beispiel mit zwei Subroutinen Sub First () und Sub Second () und einer Variablen x erstellen, die außerhalb deklariert ist, so dass sie innerhalb des gesamten Moduls Gültigkeitsbereich hat

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

Ich dachte, dass die Befehle in der folgenden Reihenfolge ausgeführt wurden:

  1. x = 3
  2. Application.OnTime Now + TimeSerial (0, 0, 2), "Sub2"
  3. Dann, nach 2 Sekunden Wartezeit, in Subsekunde () x = x + 1, also 4
  4. Schließlich kehren wir zu Sub First () zurück, wo x = 2 * x ist, so dass x am Ende gleich 8 ist.

Es stellt sich heraus, dass dies nicht die Art ist, wie VBA funktioniert; was stattdessen passiert ist:

  1. x = 3
  2. Application.OnTime Now + TimeSerial (0, 0, 2), "Sub2"
  3. Hier wird der verbleibende Code in Sub First () bis THE END ausgeführt, bevor zu Sub Second () gewechselt wird.
  4. Also wird x = 2 * x sofort mit jeder Codezeile ausgeführt, die bis zum Ende von Sub First () erscheint. Jetzt ist x gleich 6.
  5. Schließlich führt es nach 2 Sekunden des Wartens den Befehl in Sub Second () aus, x = x + 1, so dass am Ende x gleich 7 ist

Dies geschieht unabhängig davon, wie lange Sie die Anwendung warten lassen. So zum Beispiel, wenn in meinem Beispiel nach

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

VBA brauchte 10 Sekunden, um die Zeile auszuführen

x = 2*x

es müsste immer noch die Ausführung dieses Befehls beenden, bevor zu Sub Second () gewechselt wird.

WARUM IS DIESE WICHTIGE?

Denn im Lichte dessen, was ich gerade erklärt habe, kann ich Ihnen jetzt meine Lösung für die OP-Frage zeigen. Dann können Sie es an Ihre Bedürfnisse anpassen.

Und ja!!! Dies funktioniert auch mit For Loops!

DIE LÖSUNG

Ich habe zwei Unterprogramme:

  1. BLPDownload (), bei dem ich eine Arbeitsmappe aktualisiere und warten muss, bis die Werte heruntergeladen wurden, um einen anderen Code auszuführen ...

  2. BLPCheckForRefresh (), wo ich überprüfe, ob alle Daten heruntergeladen wurden

Wie zuvor deklariere ich also zwei Variablen mit dem Modul-Level-Scope

Dim firstRefreshDone As Boolean, Refreshing As Boolean

Sub BLPDownload()

CHECK:

Was ich gleich unten mache, ist:

  • Überprüfen Sie, ob ich VBA bereits angewiesen habe, die Arbeitsmappe zu aktualisieren. Wenn Sie das Makro zum ersten Mal ausführen, ist dies natürlich nicht der Fall. also firstRefreshDone = False und es tritt in diesen Block der if-Anweisung ein.
  • als nächstes wird das andere Sub BLPCheckForRefresh () aufgerufen und die aktuelle Subroutine verlassen.

Und das ist der Trick. So beenden Sie die Subroutine nach dem Aufruf von Application.OnTime *

In BLPCheckForRefresh () passiert Folgendes:

  • dass ich den Wert von firstRefreshDone = True gesetzt habe
  • Überprüfen Sie, ob ich in der UsedRange Zellen mit der Nummer N/A habe, die Daten anfordert. Wenn ja, ist der Wert von Refreshing = True.
  • endlich rufe ich das Sub BLPDownload () zurück

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

Dieses Mal ist firstRefreshDone = True. Wenn also auch die Aktualisierung abgeschlossen ist, wird AFTER_REFRESH aufgerufen, in dem Sie den gewünschten Code einfügen können, ansonsten ...

    ElseIf Not Refreshing Then
        GoTo AFTER_REFRESH

wenn die Aktualisierung nicht abgeschlossen ist, d. h. wenn ich Zellen mit # N/A Requesting Data habe, ruft es das andere Sub BLPCheckForRefresh () auf und verlässt das aktuelle Subroutine erneut.

Dieses lustige Spiel geht weiter und weiter, bis wir keine # N/A mehr anfordernden Daten in unserer UsedRange haben

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

AFTER:
    some code ...
End Sub

Hier überprüfe ich, ob die Aktualisierung abgeschlossen ist.

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

Wie oben erklärt, setze ich den Wert von firstRefreshDone = True

    firstRefreshDone = True

Und dies ist die Schleife, in der ich durch jede Zelle im verwendeten Bereich gehe, um nach # N/A Requesting Data zu suchen

    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

Zum Schluss rufe ich das Sub BLPDownload () zurück

    Call BLPDownload
End Sub

Das ist also meine Lösung. Ich arbeite für mich und mit einem anderen schmutzigen Trick, der immer die GoTo-Anweisungen und eine andere Modul-Level-Scope-Variable ausnutzt, die die Anzahl der Iterationen zählt es ist auch möglich, diese Struktur in For Loops zu verwenden.

Vor diesem Hintergrund möchte ich darauf hinweisen, dass meiner Meinung nach die beste Lösung für dieses Problem ist, Bloomberg API zu verwenden, wie von Tony Dallimore vorgeschlagen.

Hoffe das hilft!!

0
Hard Core