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
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
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.
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
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:
Es stellt sich heraus, dass dies nicht die Art ist, wie VBA funktioniert; was stattdessen passiert 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:
BLPDownload (), bei dem ich eine Arbeitsmappe aktualisiere und warten muss, bis die Werte heruntergeladen wurden, um einen anderen Code auszuführen ...
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:
Und das ist der Trick. So beenden Sie die Subroutine nach dem Aufruf von Application.OnTime *
In BLPCheckForRefresh () passiert Folgendes:
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!!