-1

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?

Community
  • 1
  • 1
user1700890
  • 7,144
  • 18
  • 87
  • 183
  • I'm not familiar with RTD but have you tried using the WinAPI `Sleep` function? This should put the Excel application to "sleep" for a specified interval. Saving every 1 minute seems unnecessarily taxing, no? Is the application so unstable that a longer interval would not be suitable? – David Zemens Feb 08 '15 at 18:31
  • Thank you, David. I think I already tried 'Sleep'. The issue with it is that Excel does not get to update the worksheet fully, Excel keeps saving old data. I can increase saving interval to 5 minutes, but my goal is to collect real time data, so I would like to have saving interval as small as technically possible. – user1700890 Feb 08 '15 at 19:51
  • I'm still curious why you feel the need to *save* the document so often... are you making a new copy of the file at each save point? If so, that's terribly redundant is it not? And if not, each "save" operation overrwrites the previous save, so why not use a less intense interval, or why bother auto-saving it at all? Assuming your application is stable and does not randomly "crash" there is no real risk of data loss... – David Zemens Feb 08 '15 at 20:03
  • The above code saves data to a different file on every iteration. It even saves into .csv file, to make storage easier. Nothing is overwritten. Every saved file contains market price data as of particular moment in time (when it was saved). There are no issues with application stability. I simply would like to collect historical price data. – user1700890 Feb 08 '15 at 20:12
  • You should be using a database for this. – David Zemens Feb 08 '15 at 20:27
  • I agree, but the issue is to grab data from =RTD("tos.rtd", , "ASK", ".SPX150220C750") with some interval. Where I output data does not really matter, pausing RTD and refreshing it is the main problem. – user1700890 Feb 08 '15 at 20:35

2 Answers2

3

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.

David Zemens
  • 53,033
  • 11
  • 81
  • 130
2

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

Peter1956
  • 21
  • 1