web-dev-qa-db-fra.com

Les données Bloomberg ne sont pas renseignées avant la fin de la macro VBA Excel

J'exécute une macro dans un classeur Excel 2007 vierge sur un PC doté d'une licence Bloomberg. La macro insère des fonctions de Bloomberg dans le folio 1 qui extrait les données de la courbe de rendement. Les résultats de certaines fonctions supplémentaires dépendent de la finalisation et de l'affichage correct des données Bberg par les premières fonctions. Lorsque je parcours le programme, il n’affiche que «# N/A Requesting Data». . ' au lieu des résultats de la requête, peu importe la lenteur avec laquelle je vais. Étant donné que certaines fonctions dépendent des résultats de chaîne et de champ numérique, le programme génère une erreur d'exécution avec ce code. Lorsque j'arrête le débogage (arrêt complet du programme), toutes les valeurs Bberg qui auraient dû être renseignées apparaissent. Je veux que ces valeurs apparaissent pendant que le programme est toujours en cours d'exécution.

J'ai essayé d'utiliser une combinaison de DoEvents et Application.OnTime () pour restituer le contrôle au système d'exploitation et pour que le programme attende la mise à jour des données pendant une longue période, mais cela n'a pas fonctionné. Toutes les idées seraient utiles. Mon code est ci-dessous. wb est un classeur de niveau global et ws1 est une feuille de calcul de niveau global.

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

Un moyen de résoudre ce problème consiste à placer tous les sous-produits, etc. que vous souhaitez exécuter après avoir extrait les données bloomberg dans un autre sous-répertoire. Vous devez le faire chaque fois que vous appelez des informations Bloomberg. Si vous appelez un autre sous-maître dans le sous-maître "maître" après Application.OnTime Now + TimeValue ("00:00:15"), la tentative échouera - vous devez placer tous les sous-suivants dans un nouveau sous-maître.

Par exemple: au lieu de

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

CA devrait etre

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

Sub Master2()
OtherSub1
OtherSub2
OtherSub3
End Sub

J'espère que cela pourra aider

6
CoreyB

J'ai cherché Google pour BloombergUI.RefreshAllStaticData et j'ai été immédiatement dirigé vers cette page de M. Excel: http://www.mrexcel.com/forum/showthread.php?t=414626

Nous ne sommes pas supposés poster des réponses qui ne sont que des liens au cas où ce lien disparaîtrait et prend la réponse avec elle. Cependant, je ne suis pas sûr de bien comprendre la question ou la réponse pour la résumer.

Le lien Google existera probablement dans un avenir prévisible.

Au sein de M. Excel, la chaîne est la suivante: MrExcel Message Board> Forum aux questions> Questions Excel> Liens Bloomberg et macros.

Les informations clés semblent être:

Sur votre terminal Bloomberg, si vous tapez WAPI <GO>, vous trouverez une liste des API Bloomberg et des exemples téléchargeables.

En utilisant les informations du fichier d'aide dans cette zone, nous pouvons créer une solution plus robuste à l'aide de la bibliothèque de types de données Bloomberg. Aller aux outils | Références et ajouter une référence à cette bibliothèque. Ce code peut ensuite être utilisé pour renseigner les cellules:

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

Une fois que vous aurez testé la solution de M. Excel, vous pourrez peut-être mettre à jour cette réponse pour le bénéfice des futurs visiteurs.

4
Tony Dallimore

J'ai rassemblé des informations sur le Web et écrit ce qui est imho est une version améliorée par rapport à tout ce que j'ai trouvé jusqu'à présent:

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

Cela devrait être une tâche arbitraire en appelant un sous-marin comme DoSomething ()

Public Sub DoSomething() 
    DoSomethingCallback
End Function

Cela appelle une fonction de "rappel" qui s'appellera jusqu'à ce que les données soient actualisées ou que le délai imparti soit atteint

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

Tout commentaire est apprécié. Une amélioration possible pourrait être de permettre au classeur et/ou à la feuille de calcul d’être une entrée de la fonction, mais je n’en ai pas vraiment vu la nécessité.

À votre santé

1
Dave

Bonjour, je pense avoir trouvé une solution à ce problème et je souhaite vraiment la partager avec vous.

Avant de commencer avec la vraie réponse Je veux m'assurer que tout le monde comprend comment Application.OnTime fonctionne réellement . Et si vous le savez déjà, vous pouvez passer en toute sécurité à LA SOLUTION ci-dessous.

Faisons un TOY EXAMLPE example avec deux sous-routines Sub First () et Sub Second () et une variable x déclarée à l'extérieur, de sorte qu'elle ait une portée à l'intérieur du module entier

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

Je pensais que les commandes étaient exécutées dans l'ordre suivant:

  1. x = 3
  2. Application.OnTime Now + TimeSerial (0, 0, 2), "Sub2"
  3. Puis, après 2 secondes d’attente, en sous-seconde () x = x + 1, d’où 4
  4. Enfin, nous revenons à Sub First () où x = 2 * x, de sorte que x est égal à 8 à la fin.

Il s'avère que ce n'est pas ainsi que fonctionne VBA; ce qui se passe à la place est:

  1. x = 3
  2. Application.OnTime Now + TimeSerial (0, 0, 2), "Sub2"
  3. Ici, le code restant dans Sub First () est exécuté jusqu'à THE END, avant de passer à Sub Second ().
  4. Donc x = 2 * x est exécuté immédiatement avec chaque ligne de code qui apparaît jusqu'à la fin de Sub First (). Maintenant, x est égal à 6.
  5. Enfin, après 2 secondes d’attente, il exécute l’instruction en Sub Second (), x = x + 1, de sorte qu’à la fin x est égal à 7

Cela se produit indépendamment du temps d'attente de l'application. Donc, par exemple si dans mon exemple, après

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

VBA a pris 10 secondes pour exécuter la ligne

x = 2*x

il devra toujours terminer l'exécution de cette commande avant de passer à Sub Second ().

POURQUOI IS CECI IMPORTANT?

Parce que, à la lumière de ce que je viens d’expliquer, je peux maintenant vous montrer ma solution à la question OP. Ensuite, vous pourrez l'adapter à vos besoins.

Et oui!!! Cela fonctionne aussi avec For Loops!

LA SOLUTION

J'ai deux sous-routines:

  1. BLPDownload () un où je rafraîchit un classeur et je dois attendre que les valeurs soient téléchargées pour pouvoir exécuter un autre code ...

  2. BLPCheckForRefresh () où je vérifie si toutes les données ont été téléchargées

Donc, comme avant, je déclare deux variables avec une étendue de niveau module

Dim firstRefreshDone As Boolean, Refreshing As Boolean

Sub BLPDownload()

CHECK:

Ce que je fais juste en dessous est de:

  • vérifiez si j'ai déjà dit à VBA d'actualiser le classeur. Bien sûr, la première fois que vous exécutez la macro, ce n'est pas le cas. Par conséquent, firstRefreshDone = False et il passe à ce bloc de l'instruction if.
  • ensuite, il appelle l'autre BLPCheckForRefresh () et quitte le sous-programme actuel.

Et c'est le truc. Pour quitter le sous-programme après avoir appelé Application.OnTime *

Dans BLPCheckForRefresh (), ce qui se passe est

  • que je mets la valeur de firstRefreshDone = True
  • vérifie si, dans la gamme UsedRange, j'ai des cellules avec # N/A Requesting Data. Si j'ai, la valeur de Refreshing = True.
  • enfin je rappelle le sous BLPDownload ()

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

Cette fois-ci cependant, firstRefreshDone = True, donc, si l'actualisation est également terminée, il passe à AFTER_REFRESH où vous pouvez mettre tout le code que vous voulez, sinon ...

    ElseIf Not Refreshing Then
        GoTo AFTER_REFRESH

si l'actualisation n'est pas terminée, c'est-à-dire si j'ai des cellules avec # N/A Requesting Data, elle appelle l'autre BLPCheckForRefresh Sub) et quitte à nouveau le sous-programme actuel.

Ce jeu amusant continue encore et encore jusqu'à ce que nous n'ayons plus de # N/A Demande de données dans notre UsedRange

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

AFTER:
    some code ...
End Sub

C'est le sous-dossier où je vérifie si l'actualisation est terminée.

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

Comme expliqué ci-dessus, j'ai défini la valeur de firstRefreshDone = True

    firstRefreshDone = True

Et c’est la boucle où je passe par chaque cellule de la gamme used à la recherche de # N/A Requesting Data

    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

Enfin, je rappelle le sous-téléchargement BLP ()

    Call BLPDownload
End Sub

C'est donc ma solution. Je travaille pour moi et avec un autre truc sale qui exploite toujours les instructions GoTo et une autre variable Scope au niveau du module qui tient compte du nombre d'itérations il est également possible d'utiliser cette structure dans les boucles For.

Cela étant dit, je tiens à souligner qu'à mon avis, la meilleure solution à ce problème consiste à utiliser l'API Bloomberg, comme l'a suggéré Tony Dallimore.

J'espère que cela t'aides!!

0
Hard Core