I want to automatically download financial data by using Excel and save that data. The download of the data is done by an Excel add-in. ISINs are used as the data identifier. The process looks as follows:
Open Workbook
Replace the existing ISIN with a new one
Download data
Export data
Close file
The data download is done by a custom function which is defined inside the Excel Add-in (and which I cannot access as it is password protected): INFGETHIST(), one function parameter is an ISIN. Unfortunately, the function does not load the data until the VBA macro I am using to update the ISIN and close the workbook afterwards is fully executed - which means, the workbook gets closed before the data is updated.
I've tried the following
Application.CalculateFullRebuild
Calculate and
Sub WaitUntilFinished()
Application.Calculate
If Not Application.CalculationState = xlDone Then
DoEvents
End If
End Sub
but to no avail.
I'm searching for a way to trigger the download of the data before my code executes completely. Any ideas much appreciated.
Related
I am a VBA beginner trying to determine the "normal" behavior of excel during a timed call to a macro using Application.OnTime. In my code (below) I am calling ActiveWorkbook.RefreshAll but I think this question may be relevant to the timed call to any macro. As a newbie, I want to understand the behavior and limits of VBA so that I can determine if VBA is the right tool or if I should use another solution in certain cases (perhaps python / openpyxl).
My set up: I am using Microsoft Excel 365 (annual subscription) and the Account page says I am using Version 2006 (Build 13001.20384 Click-to-Run). I have a single workbook containing a single Sheet1 which contains the formulas to import stock data using the built in feature under the Excel Data tab. I have several rows (one stock per row) of columnar data corresponding to the stock fields such as ticker symbol, price, etc.
To automatically refresh the data, I borrowed & modified code to refresh the data every minute. The code works fine. The "issue" I have is that between refreshes, if I start editing any cell on the sheet and continue to do so during the time when the next automatic call to the refresh should occur, it indefinitely delays the execution of said call until the moment I complete (or cancel) the cell edit. When it does the refresh upon my edit completion that refresh does seem to work correctly.
If I start a cell edit and do not complete it for several minutes then only a single refresh occurs when I complete (or cancel) the edit, even though several intervals may have passed (it does not makeup/catchup the missed/delayed calls).
This behavior is OK with me in this application, but I would like to understand if this is considered "normal" behavior, and if I should expect it to always behave this way. Perhaps this question extends beyond a refresh call but also to any timed call to any macro that may be delayed as a result of a cell edit in progress.
Here is my code.
This is in a file called VBA-Test-02-StockData.xlsm under ThisWorkbook (Code):
Private Sub Workbook_Activate()
'ActiveWindow.WindowState = xlMaximized
Application.Speech.Speak ("Activating stock workbook")
Call AutoRefresh
End Sub
This is in the same xlsm file under Module1 (Code):
Sub RefreshStockData()
Application.Speech.Speak ("Refreshing stock data")
ActiveWorkbook.RefreshAll
End Sub
Sub AutoRefresh()
Call RefreshStockData
Application.OnTime Now + TimeValue("00:01:00"), "AutoRefresh"
End Sub
I have worksheet which gets data from RTD server through the following formula:
=RTD("tos.rtd", , "ASK", ".SPX150220C750")
I would like to save the worksheet with above formula every 1 minute or so. The challenge is to pause VBA code and also make sure that before we save, the value in the cell is updated. I have tried the following code.
Sub Archiving()
For i = 0 To 4
Worksheets("Test").Activate
Application.Sheets("Test").Copy
Application.DisplayAlerts = False
ActiveWorkbook.SaveAs Filename:="D:\Save " & i & ".csv", FileFormat:=xlCSV
ActiveWorkbook.Save
ActiveWindow.Close
Windows("Real time data.xlsm").Activate
Application.DisplayAlerts = True
Application.Wait (Now + TimeValue("0:00:05"))
ActiveWorkbook.RefreshAll
DoEvents
Next i
End Sub
The code does not work, simply because DoEvents waits until RTD is done with updates, which is never. I also have seen example where connection to DB is paused explicitly, but I don't know how to adapt it RTD server case. I tried to run RTD server from C#, but failed miserably. RTD in C# for dummies
Any suggestions?
The challenge is to pause VBA code and also make sure that before we save, the value in the cell is updated.
THE PROBLEM with your previous implementation is that by doing it inside a loop, since VBA doesn't support multi-threading, the application was "busy" and unable to receive new data from RTD server.
This is based mostly on what I've gathered from Microsoft's documentation/knowledge-base, emphasis added:
The RTD function retrieves data from an RTD server for use in the
workbook. The function result is updated whenever new data becomes
available from the server and the workbook can accept it. The server
waits until Excel is idle before updating. This relieves the developer
of having to determine whether Excel is available to accept updates.
The RTD function differs from other functions in this regard because
other functions are updated only when the worksheet is recalculated.
And further suggests that toggling the application's .CalculationState etc. will have no effect on the RTD server:
Because RTD updates data when Excel is idle, it continues to receive
information if Excel is in manual calculation mode. In that event, the
new data is cached and the current values are used when a manual
calculation is performed.
So the data will be updated when it becomes available from the server (presumably not a problem) but what is a problem in your implementation is that the workbook can't accept it because it's running the VBA thread and an RTD formula is not a "normal" external link.
Although the RTD function provides a link to data on a server, it is
not the same type of link as references to cells in other worksheets
or workbooks. For example, if you use the RTD function in a workbook,
you do not receive the Links startup message when you open the
workbook, nor can you manage the status of an RTD function through the
Edit Links dialog box.
I suspect that another dissimilarity is that the RefreshAll method has no effect on this function, you can't force it to get external data because it's already doing so when the workbook can accept it.
POTENTIAL SOLUTION
By using the Application.OnTime event to schedule the save interval, I think you should be able to avoid the problem of the workbook being unable to receive data.
if you want to save the data at a regular interval, this function will call itself recursively, subject to the limitations of the Appliction.OnTime method:
Private Sub CreateArchive()
'Saves a copy of sheet "Test" and sets OnTime to save again in 60 seconds
Dim saveTime as String
saveTime = Format(Now(), "YYYY-MM-DD-hh-nn")
Worksheets("Test").Copy
Application.DisplayAlerts = False
ActiveWorkbook.SaveAs Filename:="D:\Save " & saveTime & ".csv", FileFormat:=xlCSV
ActiveWorkbook.Close
Windows("Real time data.xlsm").Activate
Application.DisplayAlerts = True
'Call on this function again in 60 seconds:
Application.OnTime Now + TimeValue("00:00:60"), CreateArchive
End Sub
NOTE: I can't replicate on my end because I don't have your COM object /etc. that is being called from the RTD function. So, take this with a grain of salt and understand that I am very limited in how much further assistance I can offer you.
I had a similar issue. I added the following command in my VBA to trigger a RTD data refresh. I did this command before I used the data in my VBA macro. Hope this helps.
Excel.Application.RTD.RefreshData
I have an Access (2013) database that I use to store/process all of our data received from a Qualtrics online survey. The raw data downloaded from Qualtrics is in a csv file that's poorly formatted for importing to Access, so I've got a fairly complex Macro in Excel (2013) that I use to pre-process the data before importing to Access.
In Access, I use the following code to open the excel file that contains the macro, run the macro, save the workbook, and close it. This had been working well several for several months, but now when I run it, it stops near the end of the Excel Macro with the run time error: -2147417856 Automation error System call failed.
ActivateOrOpenWorkbook WbkName & ".xlsm", strWbkPath
appExcel.Run ProcName, ProcArg
appExcel.Workbooks(WbkName).Save
If appExcel.Workbooks.Count = 1 Then
appExcel.Quit
Else
appExcel.Workbooks(WbkName).Close True
End If
ActivateOrOpenWorkbook is just a custom function to do exactly what the name implies, appExcel is the Excel Application. The workbook always opens fine, and the macro begins to run, but it never actually reaches the point where control returns to the Access VBA and saves the workbook.
It does run fine if I open the Workbook before running the Access procedure, insert breakpoints at every major VBA step (in both Access and Excel), and step through the whole thing one Sub at a time. It just fails if I try to let VBA run it all from start to finish on it's own.
Based on that evidence plus stories of similar problems that I've seen online, I suspect that the error is occurring because the Excel macro is taking too long to run (we recently added some new variables to the Qualtrics survey), and Access is trying to take back control before Excel is finished. I just haven't found any viable way to solve that suspected problem or investigate it further.
I did try inserting this makeshift Wait routine into my ErrorHandling for the Access Sub, but it didn't work at all, because the error message still popped up in the same amount of time as before.
If Err = -2147417856 Then
TWait = Time
TWait = DateAdd("s", 15, TWait)
Do Until TNow >= TWait
TNow = Time
Loop
Resume Next
Any help will be appreciated!
Have you tried using DoEvents in the pre-processing macro?
If you have a loop where you're processing the CSV file line by line then use DoEvents every so often to give any pending events a chance to run. It would be overkill to call it on every line so maybe start with every 100 lines and adjust from there.
Given that the macro works when you step through the Subs, it would appear that it isn't the overall execution time that's the problem. If Access is throwing an error because Excel appears to be unresponsive then DoEvents might be enough to stop Access from giving up
I want to create an excel template that will includes formulas for dating the columns. However, since those formulas will be based on TODAY(), I need to convert them to static strings (so the dates don't change everytime someone opens it). Is there a way to add a macro that will run automatically when someone creates a new spreadsheet based on the template? (Similarly to Auto_Open(), only on Create, rather than Open). If so, I could just create a macro that will replace the formulas with their results upon document creation. Can this be done?
[Note: I'm not married to this solution; it just seemed like the simplest way to protect my spreadsheet. If someone can suggest an alternative approach, I'd be obliged.]
I have a couple thoughts...
If you run a copy/paste values macro every time it really won't matter, right?
You could check if the file exists yet (has been saved), and if not
then this must be the template opened as a new workbook, maybe?
Code:
Private Sub Workbook_Open()
If Dir(ActiveWorkbook.Name) = "" Then
'run the macro?
MsgBox "I'm gonna run this macro"
End If
End Sub
You could have a cell on one of the sheets, that will never be used,
or is hidden, that will store whether or not to run the macro, and
change that when the file is opened or when the macro is ran. Then
have a macro run on open that checks that cell. (Or custom/document property)
You could populate the cells that have the today() formula only on
open and if they are already populated then don't run the macro?
I realized that there is no need for a Workbook_Create() function, as that behavior can be emulated by simply deleting the macro after it has run once (which happens when it is first created). Deleting macros is done automatically when the file is saved with a .xlsx extension. In addition, you need to prevent the macro from running when you open the template itself (while editing the it). You can hold the SHIFT key when opening it to prevent auto-run macros, but since that method isn't foolproof, I added this code at the top:
Private Sub Workbook_Open()
'If we're opening the template, don't run the macro
If Application.ActiveWorkbook.FileFormat = xlOpenXMLTemplateMacroEnabled Then
Exit Sub
End If
...
'add code here to SaveAs .xlsx, thus removing the macros, so it won't run every time.
End Sub
(Note: I didn't show my SaveAs code as it is rather messy: I wanted to suppress the default warning about losing macros, but wanted to also protect the user from inadvertantly overwriting previous file. If anyone is interested, I could post it)
I have a question on the macro events here. Below is my code. This performs the below Operations’
Private Sub SaveAsTabDelimited(ByVal sFileName As String)
With ActiveWorkbook
.SaveAs Filename:=sFileName, FileFormat:=xlText, CreateBackup:=True
End With
End Sub
Public Sub test()
SaveAsTabDelimited "C:\Users\te160772\Desktop\Toad Test\Testsanthu.txt"
ActiveWorkbook.Close savechanges:=True
End Sub
It converts the excel file into tab delimited txt file
It creates a backup copy of the excel file
I wanted this action to be performed each day inorder the excel file to upload to Oracle tables on daily basis. The reason behind converting excel spreadsheet to tab delimited txt file is to preserve the format (To prevent the removal of leading zeros while exporting it to oracle)
But now I am trying to enhance this code so that the following actions should be performed without any glitch. I have tried to do this in all the possible ways .since I am very new to the programming I was not able to do this.
The code should convert the excel file to tab delimited save on my desktop (Hope that my current piece of code is sufficient for this action)
It should create a backup copy in a folder called “Repository” (A folder in a desktop). Each change to my workbook should result a backup copy with the version history if possible(Date and Time stamp in the file name)
the biggest problem associated with my code is that upon close, three separate dialogue boxes appear - one asking me if i want to save, the other asking me if i want to keep what i have copied in the clipboard, another one is replace the existing text file saved in the folder is there a way of answering these dialogue boxes (or suppressing them) from within the macro, so i do not need to manually click on yes or no each time the macro is run?
I have attached my macro to a “shape” in excel but my priority is to run my macro upon closing of my workbook. Every time when any changes happen to my workbook and when I save the workbook, it should create a tab delimited Text files which should replace the existing Txt File without any confirmation dialogue boxes.
Please help me on this. This is badly require for me
With a million thanks
The code should convert the excel file to tab delimited save on my desktop (Hope that my current piece of code is sufficient for this action)
Yes, either you can hardcode the path to the desktop or use this code to get the path to the desktop automatically
Sub GetDesktopPath()
Dim oWS As Object
Dim DskTopPath As String
Set oWS = CreateObject("WScript.Shell")
DskTopPath = oWS.SpecialFolders("Desktop")
Debug.Print DskTopPath
Set oWS = Nothing
End Sub
It should create a backup copy in a folder called “Repository” (A folder in a desktop). Each change to my workbook should result a backup copy with the version history if possible(Date and Time stamp in the file name)
You can use the Workbook_BeforeSave event to create a copy of the existing workbook.
Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
End Sub
You may want to explore ThisWorkbook.SaveCopyAs See Excel Help for more info.
the biggest problem associated with my code is that upon close, three separate dialogue boxes appear - one asking me if i want to save, the other asking me if i want to keep what i have copied in the clipboard, another one is replace the existing text file saved in the folder is there a way of answering these dialogue boxes (or suppressing them) from within the macro, so i do not need to manually click on yes or no each time the macro is run?
You can get rid of these alerts by simply sandwiching your code between
Application.DisplayAlerts = False
'~~> Your Code
Application.DisplayAlerts = True
If you are using clipboard a lot, then you might also want to clear it by using
Application.CutCopyMode = False
I have attached my macro to a “shape” in excel but my priority is to run my macro upon closing of my workbook. Every time when any changes happen to my workbook and when I save the workbook, it should create a tab delimited Text files which should replace the existing Txt File without any confirmation dialogue boxes.
You can use the Workbook_BeforeClose event to run your relevant code
Private Sub Workbook_BeforeClose(Cancel As Boolean)
End Sub
Regarding the alert, I have already explained that in the previous section.
Hope this sets you in the right path.