Automating and looping a Web Query

abesimpson

Active Member
Joined
May 3, 2003
Messages
435
My spreadsheet is linked to a stock data web page using the little documented .iqy function. I have set cell A1 to the web page ticker symbol, so that whenever this cell value is changed the data in the spreadsheet is automatically updated.

My problem is in several parts:
1. Read TickerSymbol.csv file which is comprised of just ticker symbols,
2. Insert (TickerSymbol.csv) symbol 1 into cell A1,
3. Save the results to a file c:\XXX\Symbol1.csv,
4. Insert (TickerSymbol.csv) symbol 2,
5. repeat, repeat

Any and all help would be greatly appreciated.


abe
 
Yes - you made the RefreshStyle change in the wrong routine, Create_Dynamic_Query_From_Iqy_File, which is not called. It should be made in Create_Dynamic_Query_From_URL. Also, you didn't make the dataEndRow change, perhaps because the call to Save_Stock_Data has an extra parameter which it isn't expecting - my mistake.

Here is the fully updated code:
Code:
'Uses a dynamic web query, using either an .iqy file or a URL connection string, to retrieve stock data from
'Yahoo Finance (http://finance.yahoo.com).
'The stock quote symbols are read from a file containing one symbol per line.
'For each symbol, the stock data is retrieved using the dynamic web query and then saved in a file called TKR.csv.

'The dynamic web query is contained in the file YahooFinanceQuote.iqy, which contains:
'   WEB
'   1
'   http://finance.yahoo.com/q?s=["quote symbol","Enter cell containing quote symbol, e.g. =B1"]&=
 
Option Explicit
 
Const cQueryName = "YahooFinanceQuote"                  'Name of the dynamic web query
Const cSymbolsFile = "c:\Temp\Excel\TickerSymbols.csv"  'File containing symbols to be retrieved, one per line
Const cSaveToFolder = "c:\Temp\Excel\"                  'Folder in which to create the symbol.csv files

Const cIqyFile = "F:\Temp\Excel\YahooFinanceQuote.iqy"  'The .iqy file
Const cURL = "http://finance.yahoo.com/q?s="            'Yahoo Finance URL with the query field (s=) but not the field value

Const cParameterCell = "B1"                             'Cell containing the query field (s=) field value (Excel dynamic parameter)
Const cDataStartCell = "A2"                             'Cell where retrieved data begins

Sub Retrieve_All_Symbols()

    Dim fileNum As Integer
    Dim symbol As String
    Dim queryName As String
    Dim dataEndRow As Integer
    
    'Get web query (if it has been created manually) and create it if it doesn't exist
    
    queryName = Get_Web_Query_Name
    If queryName = "" Then
        queryName = Create_Dynamic_Query_From_URL(cQueryName, cURL, cParameterCell, cDataStartCell)
        'queryName = Create_Dynamic_Query_From_Iqy_File(cQueryName, cIqyFile, cParameterCell, cDataStartCell)
    End If
       
    fileNum = FreeFile
    Open cSymbolsFile For Input As #fileNum
    While Not EOF(fileNum)
        Line Input #fileNum, symbol
                
        'Put this quote symbol in the cell associated with the web query.
        'The web query doesn't automatically refresh, despite the RefreshOnChange property being set.  Therefore the
        'explicit Refresh below is required to retrieve the data for the symbol
                
        ActiveSheet.Range(cParameterCell).Value = symbol
        ActiveSheet.QueryTables(1).Refresh
                
        'Find the last row of data in column A
        
        dataEndRow = ActiveSheet.Cells(ActiveSheet.Rows.Count, "A").End(xlUp).Row
                
        'Save the data returned
        
        Save_Stock_Data symbol, Range(cDataStartCell & ":B" & dataEndRow)
        
    Wend
    Close #fileNum
    
End Sub

Private Sub Save_Stock_Data(symbol As String, dataRange As Range)

    'Save the stock data for the symbol in the file .csv
    
    Dim dataOutputFile As String
    Dim fileNum As Integer
    Dim csvLine As String
    Dim previousRow As Integer
    Dim cell As Range
    
    dataOutputFile = cSaveToFolder & symbol & ".csv"
    
    fileNum = FreeFile
    Open dataOutputFile For Output As #fileNum
    
    csvLine = ""
    previousRow = dataRange.Row
    For Each cell In dataRange
        If cell.Row = previousRow Then
            csvLine = csvLine & cell.Value & ","
        Else
            Print #fileNum, Left(csvLine, Len(csvLine) - 1)
            csvLine = cell.Value & ","
            previousRow = cell.Row
        End If
    Next
    Print #fileNum, Left(csvLine, Len(csvLine) - 1)
    Close #fileNum
    
End Sub

Private Function Create_Dynamic_Query_From_URL(queryName As String, URL As String, parameterCell As String, _
        destinationCell As String) As String

    Dim qt As QueryTable
    Dim URLquery As String
       
    'Code in this function was generated by the Macro Recorder as a result of
    'Data - Import External Data - Import Data - browse to .iqy file.
    'and then modified to include the quote symbol parameter in the connection string - see http://www.jkp-ads.com/Articles/WebQuery.asp
    'Therefore the .iqy file is not needed and the Parameter Value dialogue box doesn't appear when the querytable is added.
                
    'This is the URL from the .iqy file
    'http://finance.yahoo.com/q?s=["quote symbol","Enter cell containing quote symbol, e.g. =B1"]&=
                
    URLquery = "[""quote symbol"",""Enter cell containing quote symbol, e.g. =B1""]"
    
    Set qt = ActiveSheet.QueryTables.Add(Connection:="URL;" & URL & URLquery, Destination:=Range(destinationCell))
    
    With qt
        .Name = queryName
        .FieldNames = True
        .RowNumbers = False
        .FillAdjacentFormulas = False
        .PreserveFormatting = False
        .RefreshOnFileOpen = False
        .BackgroundQuery = False    'False because data requests must be synchronous. Was True when generated by Macro Recorder
        .RefreshStyle = xlOverwriteCells 'Was xlInsertDeleteCells
        .SavePassword = False
        .SaveData = True
        .AdjustColumnWidth = True
        .RefreshPeriod = 0
        .WebSelectionType = xlAllTables
        .WebFormatting = xlWebFormattingAll
        .WebPreFormattedTextToColumns = False
        .WebConsecutiveDelimitersAsOne = True
        .WebSingleBlockTextImport = False
        .WebDisableDateRecognition = False
        .WebDisableRedirections = True
        With .Parameters(1)
            .SetParam xlRange, ActiveSheet.Range(parameterCell)
            .RefreshOnChange = True
        End With
        .Refresh BackgroundQuery:=False
    End With
    
    Create_Dynamic_Query_From_URL = qt.Name
    
End Function

Private Function Create_Dynamic_Query_From_Iqy_File(queryName As String, iqyFile As String, parameterCell As String, _
        destinationCell As String) As String

    Dim qt As QueryTable
    
    'Code in this function was generated by the Macro Recorder as a result of
    'Data - Import External Data - Import Data - browse to .iqy file
    'and then modified to suit this program
        
    Set qt = ActiveSheet.QueryTables.Add(Connection:="FINDER;" & iqyFile, Destination:=Range(destinationCell))
    
    With qt
        .Name = queryName
        .FieldNames = True
        .RowNumbers = False
        .FillAdjacentFormulas = False
        .PreserveFormatting = False
        .RefreshOnFileOpen = False
        .BackgroundQuery = False    'False because data requests must be synchronous. Was True when generated by Macro Recorder
        .RefreshStyle = xlInsertDeleteCells
        .SavePassword = False
        .SaveData = True
        .AdjustColumnWidth = True
        .RefreshPeriod = 0
        .WebSelectionType = xlAllTables
        .WebFormatting = xlWebFormattingAll
        .WebPreFormattedTextToColumns = False
        .WebConsecutiveDelimitersAsOne = True
        .WebSingleBlockTextImport = False
        .WebDisableDateRecognition = False
        .WebDisableRedirections = True
        
        .Refresh BackgroundQuery:=False
    End With
    
    Create_Dynamic_Query_From_Iqy_File = qt.Name
    
End Function

Private Function Get_Web_Query_Name() As String
    
    Dim qt As QueryTable
    
    'Returns the name of the first web query on the active sheet, or "" if no queries exist
    
    If ActiveSheet.QueryTables.Count > 0 Then
        Get_Web_Query_Name = ActiveSheet.QueryTables(1).Name
    Else
        Get_Web_Query_Name = ""
    End If
    
End Function

'=========== Debugging and Information routines ===========

Private Sub Show_All_Queries()
    Dim qt As QueryTable
    For Each qt In ActiveSheet.QueryTables
        Debug.Print qt.Name
    Next
End Sub

Private Sub Delete_Query(queryName As String)
    Dim qt As QueryTable
    For Each qt In ActiveSheet.QueryTables
        If qt.Name = queryName Then qt.Delete
    Next
End Sub

Sub Delete_All_Queries()
    Dim qt As QueryTable
    For Each qt In ActiveSheet.QueryTables
        Debug.Print "Deleted " & qt.Name
        qt.Delete
    Next
End Sub
If it still doesn't work properly, post your list of symbols.
 
Last edited:
Upvote 0

Excel Facts

Does the VLOOKUP table have to be sorted?
No! when you are using an exact match, the VLOOKUP table can be in any order. Best-selling items at the top is actually the best.
That did it.

I didn't add the dynamic query part intentionally in order to minimize my potential to introduce error. Obviously even that didn't work.

I have to ask, what do you do for a living? Where did you acquire you all this knowledge?


Regards

a
 
Upvote 0
Two small problem have appeared (I PROMISE I'll stop).

1- Row 1 should be part of the saved data as the TKR name is in cell B1 (I know the TKR is the file name, but harder for me to get that into an Access database)

2- If I have an unknown (delisted) ticker I get an error (the web query returned no data...), and the "Sub Retrieve_All_Symbols()" crashes on line "ActiveSheet.QueryTables(1).Refresh". Is it possible to just skip past these kind of errors as stocks are renamed, delisted all the time.


Regards
 
Upvote 0
1. Use this: Save_Stock_Data saveToFolder, symbol, Range("A1:B" & dataEndRow)

2. With 'junk' symbols my web query still works (it doesn't say the web query returned no data) and the program doesn't crash. Give examples of symbols which cause the problems you describe.

As for all this knowledge, it's not much - just what anyone can find by using Google and this forum. Your OP caught my curiosity as I'd never used .iqy files and dynamic web queries before so I decided to find out about them.
 
Upvote 0
Wow, 8000+ ticker symbols! I only asked for examples of ones that don't work, and don't have time to wade through 8000. Fortunately, AQR-U is one that doesn't work and is early in the list. The reason that one returns "Run-time error 1004, This web query returned no data ..." is because the quote page (http://finance.yahoo.com/q?s=AQR-U&=) contains no HTML tables.

Here is the full code which handles delisted symbols in the way you require. I've also provided code (currently commented out) which reads the TickerSymbols.csv and saves the symbol.csv files in the same folder as the workbook, instead of specific folders - read the comments.
Code:
'Uses a dynamic web query, using either an .iqy file or a URL connection string, to retrieve stock data from
'Yahoo Finance (http://finance.yahoo.com).
'The stock quote symbols are read from a file containing one symbol per line.
'For each symbol, the stock data is retrieved using the dynamic web query and then saved in a file called <symbol>.csv.

'The dynamic web query is contained in the file YahooFinanceQuote.iqy, which contains:
'   WEB
'   1
'   http://finance.yahoo.com/q?s=["quote symbol","Enter cell containing quote symbol, e.g. =B1"]&=

 
Option Explicit
 
'Name of the dynamic web query
Const cQueryName = "YahooFinanceQuote"

'File containing symbols to be retrieved, one per line.
Const cSymbolsFilename = "TickerSymbols.csv"

'Folder containing the symbols file
Const cSymbolsFolder = "C:\Temp\Excel\"

'Folder in which to create the symbol.csv files
Const cSaveToFolder = "C:\Temp\Excel\"

'The .iqy file.  This file should be in the same folder as the workbook.  Not used if URL web query is called.
Const cIqyFilename = "YahooFinanceQuote.iqy"

'Yahoo Finance URL with the query field (s=) but not the field value
Const cURL = "http://finance.yahoo.com/q?s="

'Cell containing the query field (s=) field value (Excel dynamic parameter)
Const cParameterCell = "B1"

'Cell where retrieved data begins
Const cDataStartCell = "A2"


Public Sub Retrieve_All_Symbols()

    Dim symbolsFile As String
    Dim iqyFile As String
    Dim saveToFolder As String
    Dim fileNum As Integer
    Dim symbol As String
    Dim queryName As String
    Dim dataEndRow As Integer
    
    symbolsFile = cSymbolsFolder & cSymbolsFilename
    
    'Or if the symbols file is in the same folder as the workbook
    'symbolsFile = ActiveWorkbook.Path & "\" & cSymbolsFilename
    
    iqyFile = ActiveWorkbook.Path & "\" & cIqyFilename
        
    saveToFolder = cSaveToFolder
    
    'Or to save the symbol.csv files in the same folder as the workbook
    'saveToFolder = ActiveWorkbook.Path & "\"
            
    'Get web query (if it has been created manually) and create it if it doesn't exist
    
    queryName = Get_Web_Query_Name
    If queryName = "" Then
        queryName = Create_Dynamic_Query_From_URL(cQueryName, cURL, cParameterCell, cDataStartCell)
        'queryName = Create_Dynamic_Query_From_Iqy_File(cQueryName, iqyFile, cParameterCell, cDataStartCell)
    End If
    
    fileNum = FreeFile
    Open symbolsFile For Input As #fileNum
    While Not EOF(fileNum)
        Line Input #fileNum, symbol
                
        'Put this quote symbol in the cell associated with the web query.
        'The web query doesn't automatically refresh, despite the RefreshOnChange property being set.  Therefore the
        'explicit Refresh below is required to retrieve the data for the symbol
        
        ActiveSheet.Range(cParameterCell).Value = symbol
        
        'Delisted ticker symbols such as AQR-U cause the web query to
        'return "Run-time error 1004, This web query returned no data ..."
        'because the quote page (e.g. http://finance.yahoo.com/q?s=AQR-U&=) contains no tables
        
        On Error Resume Next
        ActiveSheet.QueryTables(queryName).Refresh
        
        If Err.Number = 0 Then
            On Error GoTo 0
            
            'No error occurred.  Find the last row of data in column A
            
            dataEndRow = ActiveSheet.Cells(ActiveSheet.Rows.Count, "A").End(xlUp).row
                    
            'Save the data returned
            
            Save_Stock_Data saveToFolder, symbol, Range("A1:B" & dataEndRow)
        
        ElseIf Err.Number <> 1004 Then
            On Error GoTo 0
        
            'An unexpected error occurred
            
            MsgBox "Error number " & Err.Number & vbNewLine & Err.Description, , "Run-time error"
        End If
            
    Wend
    Close #fileNum
    
End Sub


Private Sub Save_Stock_Data(folder As String, symbol As String, dataRange As Range)

    'Save the stock data for the symbol in the file <symbol>.csv
    
    Dim dataOutputFile As String
    Dim fileNum As Integer
    Dim csvLine As String
    Dim previousRow As Integer
    Dim cell As Range
    
    dataOutputFile = folder & symbol & ".csv"
    
    fileNum = FreeFile
    Open dataOutputFile For Output As #fileNum
    
    csvLine = ""
    previousRow = dataRange.row
    For Each cell In dataRange
        If cell.row = previousRow Then
            csvLine = csvLine & cell.Value & ","
        Else
            Print #fileNum, Left(csvLine, Len(csvLine) - 1)
            csvLine = cell.Value & ","
            previousRow = cell.row
        End If
    Next
    Print #fileNum, Left(csvLine, Len(csvLine) - 1)
    
    Close #fileNum
    
End Sub


Private Function Create_Dynamic_Query_From_URL(queryName As String, URL As String, parameterCell As String, _
        destinationCell As String) As String

    Dim qt As QueryTable
    Dim URLquery As String
       
    'Code in this function was generated by the Macro Recorder as a result of
    'Data - Import External Data - Import Data - browse to .iqy file.
    'and then modified to include the quote symbol parameter in the connection string - see http://www.jkp-ads.com/Articles/WebQuery.asp
    'Therefore the .iqy file is not needed and the Parameter Value dialogue box doesn't appear when the querytable is added.
                
    'This is the URL from the .iqy file
    'http://finance.yahoo.com/q?s=["quote symbol","Enter cell containing quote symbol, e.g. =B1"]&=
                
    URLquery = "[""quote symbol"",""Enter cell containing quote symbol, e.g. =B1""]"
    
    Set qt = ActiveSheet.QueryTables.Add(Connection:="URL;" & URL & URLquery, Destination:=Range(destinationCell))
    
    With qt
        .Name = queryName
        .FieldNames = True
        .RowNumbers = False
        .FillAdjacentFormulas = False
        .PreserveFormatting = False
        .RefreshOnFileOpen = False
        .BackgroundQuery = False    'False because data requests must be synchronous. Was True when generated by Macro Recorder
        .RefreshStyle = xlOverwriteCells
        .SavePassword = False
        .SaveData = True
        .AdjustColumnWidth = True
        .RefreshPeriod = 0
        .WebSelectionType = xlAllTables
        .WebFormatting = xlWebFormattingAll
        .WebPreFormattedTextToColumns = False
        .WebConsecutiveDelimitersAsOne = True
        .WebSingleBlockTextImport = False
        .WebDisableDateRecognition = False
        .WebDisableRedirections = True
        With .Parameters(1)
            .SetParam xlRange, ActiveSheet.Range(parameterCell)
            .RefreshOnChange = True         'But doesn't trigger an automatic refresh when value of parameter cell changes
        End With
        .Refresh BackgroundQuery:=False
    End With
    
    Create_Dynamic_Query_From_URL = qt.Name
    
End Function


Private Function Create_Dynamic_Query_From_Iqy_File(queryName As String, iqyFile As String, parameterCell As String, _
        destinationCell As String) As String

    Dim qt As QueryTable
    
    'Code in this function was generated by the Macro Recorder as a result of
    'Data - Import External Data - Import Data - browse to .iqy file
    'and then modified to suit this program
        
    Set qt = ActiveSheet.QueryTables.Add(Connection:="FINDER;" & iqyFile, Destination:=Range(destinationCell))
    
    With qt
        .Name = queryName
        .FieldNames = True
        .RowNumbers = False
        .FillAdjacentFormulas = False
        .PreserveFormatting = False
        .RefreshOnFileOpen = False
        .BackgroundQuery = False    'False because data requests must be synchronous. Was True when generated by Macro Recorder
        .RefreshStyle = xlOverwriteCells
        .SavePassword = False
        .SaveData = True
        .AdjustColumnWidth = True
        .RefreshPeriod = 0
        .WebSelectionType = xlAllTables
        .WebFormatting = xlWebFormattingAll
        .WebPreFormattedTextToColumns = False
        .WebConsecutiveDelimitersAsOne = True
        .WebSingleBlockTextImport = False
        .WebDisableDateRecognition = False
        .WebDisableRedirections = True
        
        'This With ... End With block sets the web query's parameter value to the specified cell.  Without this,
        'the 'Set Parameter Value' dialogue box appears
        
        'With .Parameters(1)
        '    .SetParam xlRange, ActiveSheet.Range(parameterCell)
        '    .RefreshOnChange = True
        'End With
        
        .Refresh BackgroundQuery:=False
    End With
    
    Create_Dynamic_Query_From_Iqy_File = qt.Name
    
End Function


Private Function Get_Web_Query_Name() As String
    
    Dim qt As QueryTable
    
    'Returns the name of the first web query on the active sheet, or "" if no queries exist
    
    If ActiveSheet.QueryTables.Count > 0 Then
        Get_Web_Query_Name = ActiveSheet.QueryTables(1).Name
    Else
        Get_Web_Query_Name = ""
    End If
    
End Function


'=========== Debugging and Information routines ===========

Private Sub Show_All_Queries()
    Dim qt As QueryTable
    For Each qt In ActiveSheet.QueryTables
        Debug.Print qt.Name
    Next
End Sub

Private Sub Delete_Query(queryName As String)
    Dim qt As QueryTable
    For Each qt In ActiveSheet.QueryTables
        If qt.Name = queryName Then qt.Delete
    Next
End Sub

Sub Delete_All_Queries()
    Dim qt As QueryTable
    For Each qt In ActiveSheet.QueryTables
        Debug.Print "Deleted " & qt.Name
        qt.Delete
    Next
End Sub
 
Upvote 0
First; another thank you
Second; I understand if you give up on me, as it appears that I am not adding any value to this exercise.
Third; There remains a problem with (I think) "on error goto 0"

On running against the complete TKR list:
1- the macro saves up to GFX.csv,
2- continues to run (with cell value B2 changing),
3- but does not update the table or save any additional results

Thanks again

a
 
Upvote 0
No, I won't give up yet as this is getting interesting! You may not be adding much to this exercise but I hope you are learning something.

I reproduced your problem, but it's nothing to do with 'On Error Goto 0'.

After a while, any web query, even a manual one, returns 'Run-time error 1004 The file could not be accessed ...'. The behaviour you describe happens because the program thinks error 1004 is caused by a delisted ticker symbol and ignores it, as you require.

However, error 1004 with the error description 'The file could not be accessed ...' seems to be related to IE's temporary internet files - see http://www.vbforums.com/showthread.php?t=453684. The solution is to periodically delete the temporary files that IE creates for http://finance.yahoo.com/q?s=XXX and I've modified my program to do this. With my method of deleting files, I don't think it's necessary to unhide protected operating system files as some of those posts say.

The command which deletes the temporary files is run asynchronously. In a test, the program froze after about 30 minutes, possibly because the asynchronous DEL command deleted a file which the web query still needed, although I had also changed some properties in the web query so it's hard to tell why. (Bad practice to change more than one variable when testing...). If you find that this happens, I have a synchronous ShellX function which can be called instead - see the comments in Delete_Yahoo_IE_Temporary_Files.

I've also put calls to DoEvents in the main loop to allow Windows to process other events. Without this, you can't do things like switch windows or stop the VB debugger.

Here is the full main program:
Code:
'Uses a dynamic web query, using either an .iqy file or a URL connection string, to retrieve stock data from
'Yahoo Finance (http://finance.yahoo.com).
'The stock quote symbols are read from a file containing one symbol per line.
'For each symbol, the stock data is retrieved using the dynamic web query and then saved in a file called <symbol>.csv.

'The dynamic web query is contained in the file YahooFinanceQuote.iqy, which contains:
'   WEB
'   1
'   http://finance.yahoo.com/q?s=["quote symbol","Enter cell containing quote symbol, e.g. =B1"]&=

 
Option Explicit
 
'Name of the dynamic web query
Const cQueryName = "YahooFinanceQuote"

'File containing symbols to be retrieved, one per line.
Const cSymbolsFilename = "Yahoo Finance TickerSymbols.csv"
'Const cSymbolsFilename = "TickerSymbols.csv"

'Folder containing the symbols file
Const cSymbolsFolder = "C:\Temp\Excel\"

'Folder in which to create the symbol.csv files.  This folder must exist
Const cSaveToFolder = "C:\Temp\Excel\"

'The .iqy file.  This file should be in the same folder as the workbook.  Not used if URL web query is called.
Const cIqyFilename = "YahooFinanceQuote.iqy"

'Yahoo Finance URL with the query field (s=) but not the field value
Const cURL = "http://finance.yahoo.com/q?s="

'Cell containing the query field (s=) field value (Excel dynamic parameter)
Const cParameterCell = "B1"

'Cell where retrieved data begins
Const cDataStartCell = "A2"

'Delete temporary internet files every n symbols
Const cDeleteTemporaryFilesEvery = 20

'For debugging
Const cDEBUG = True



Public Sub Retrieve_All_Symbols()

    Dim symbolsFile As String
    Dim iqyFile As String
    Dim saveToFolder As String
    Dim fileNum As Integer
    Dim symbol As String
    Dim queryName As String
    Dim dataEndRow As Integer
    Dim s As Integer
    Dim numSymbols As Long
    
    symbolsFile = cSymbolsFolder & cSymbolsFilename
    
    'Or if the symbols file is in the same folder as the workbook
    symbolsFile = ActiveWorkbook.Path & "\" & cSymbolsFilename
    
    iqyFile = ActiveWorkbook.Path & "\" & cIqyFilename
        
    saveToFolder = cSaveToFolder
    
    'Or to save the symbol.csv files in the same folder as the workbook
    'saveToFolder = ActiveWorkbook.Path & "\"
            
    'Get web query (if it has been created manually) and create it if it doesn't exist
    
    queryName = Get_Web_Query_Name
    If queryName = "" Then
        queryName = Create_Dynamic_Query_From_URL(cQueryName, cURL, cParameterCell, cDataStartCell)
        'queryName = Create_Dynamic_Query_From_Iqy_File(cQueryName, iqyFile, cParameterCell, cDataStartCell)
    End If
    
    numSymbols = 0
    fileNum = FreeFile
    Open symbolsFile For Input As #fileNum
    While Not EOF(fileNum)
        
        DoEvents
        
        Line Input #fileNum, symbol
        numSymbols = numSymbols + 1
        
        If cDEBUG Then Debug.Print numSymbols & " " & symbol
                
        'Put this quote symbol in the cell associated with the web query.
        'The web query doesn't automatically refresh, despite the RefreshOnChange property being set.  Therefore the
        'explicit Refresh below is required to retrieve the data for the symbol
        
        ActiveSheet.Range(cParameterCell).Value = symbol
        
        'Delisted ticker symbols such as AQR-U cause the web query to
        'return "Run-time error 1004, This web query returned no data ..."
        'because the quote page (e.g. http://finance.yahoo.com/q?s=AQR-U&=) contains no tables
        
        On Error Resume Next
        ActiveSheet.QueryTables(queryName).Refresh BackgroundQuery:=False
              
        If Err.Number = 0 Then
        
            'No error occurred
            
            On Error GoTo 0
            If cDEBUG Then Debug.Print "Retrieved OK"
        
            'Find the last row of data in column A
            
            dataEndRow = ActiveSheet.Cells(ActiveSheet.Rows.count, "A").End(xlUp).row
                
            'Save the data returned
            
            Save_Stock_Data saveToFolder, symbol, Range("A1:B" & dataEndRow)
        
        ElseIf Err.Number = 1004 Then
        
            'The expected error "This web query returned no data ..." occurred - ignore it
            
            On Error GoTo 0
            If cDEBUG Then Debug.Print "Web query returned no data"
        
        Else
            
            'An unexpected error occurred - tell the user
            
            On Error GoTo 0
            If cDEBUG Then Debug.Print "Error " & Err.Number & " " & Err.Description
            
            MsgBox "Error number " & Err.Number & vbNewLine & Err.Description, , "Run-time error"
        
        End If
        
        DoEvents
        
        'Every n symbols delete Yahoo Finance files from IE temporary internet files cache
        
        'Without this, after a while any web query, even a manual one, returns
        '   "Run-time error 1004  The file could not be accessed ...",
        'which is trapped by the error handler above.
        'It seems that this error is related to IE's temporary internet files -
        'see http://www.vbforums.com/showthread.php?t=453684 for other people with the same problem with Yahoo Finance quotes.
        'The solution is to periodically delete the temporary files that IE creates for
        'http://finance.yahoo.com/q?s=XXX
        
        If numSymbols Mod cDeleteTemporaryFilesEvery = 0 Then
            Delete_Yahoo_IE_Temporary_Files
            DoEvents
        End If
            
    Wend
    
    Close #fileNum
    
End Sub


Private Sub Save_Stock_Data(folder As String, symbol As String, dataRange As Range)

    'Save the stock data for the symbol in the file <symbol>.csv
    
    Dim dataOutputFile As String
    Dim fileNum As Integer
    Dim csvLine As String
    Dim previousRow As Integer
    Dim cell As Range
    
    dataOutputFile = folder & symbol & ".csv"
    
    fileNum = FreeFile
    Open dataOutputFile For Output As #fileNum
    
    csvLine = ""
    previousRow = dataRange.row
    For Each cell In dataRange
        If cell.row = previousRow Then
            csvLine = csvLine & cell.Value & ","
        Else
            Print #fileNum, Left(csvLine, Len(csvLine) - 1)
            csvLine = cell.Value & ","
            previousRow = cell.row
        End If
    Next
    Print #fileNum, Left(csvLine, Len(csvLine) - 1)
    
    Close #fileNum
    
End Sub


Private Function Create_Dynamic_Query_From_URL(queryName As String, URL As String, parameterCell As String, _
        destinationCell As String) As String

    Dim qt As QueryTable
    Dim URLquery As String
       
    'Code in this function was generated by the Macro Recorder as a result of
    'Data - Import External Data - Import Data - browse to .iqy file.
    'and then modified to include the quote symbol parameter in the connection string - see http://www.jkp-ads.com/Articles/WebQuery.asp
    'Therefore the .iqy file is not needed and the Parameter Value dialogue box doesn't appear when the querytable is added.
                
    'This is the URL from the .iqy file
    'http://finance.yahoo.com/q?s=["quote symbol","Enter cell containing quote symbol, e.g. =B1"]&=
                
    URLquery = "[""quote symbol"",""Enter cell containing quote symbol, e.g. =B1""]&="
    
    Set qt = ActiveSheet.QueryTables.Add(Connection:="URL;" & URL & URLquery, Destination:=Range(destinationCell))
    
    With qt
        .Name = queryName
        .FieldNames = True
        .RowNumbers = False
        .FillAdjacentFormulas = False
        .PreserveFormatting = False
        .RefreshOnFileOpen = False
        .BackgroundQuery = False    'False because data requests must be synchronous. Was True when generated by Macro Recorder
        .RefreshStyle = xlOverwriteCells
        .SavePassword = False
        .SaveData = True
        .AdjustColumnWidth = True
        .RefreshPeriod = 0
        .WebSelectionType = xlAllTables
        .WebFormatting = xlWebFormattingAll
        .WebPreFormattedTextToColumns = False
        .WebConsecutiveDelimitersAsOne = True
        .WebSingleBlockTextImport = False
        .WebDisableDateRecognition = False
        .WebDisableRedirections = True
        With .Parameters(1)
            .SetParam xlRange, ActiveSheet.Range(parameterCell)
            .RefreshOnChange = True         'But doesn't trigger an automatic refresh when value of parameter cell changes
        End With
        '.Refresh BackgroundQuery:=False
    End With
    
    Create_Dynamic_Query_From_URL = qt.Name
    
End Function


Private Function Create_Dynamic_Query_From_Iqy_File(queryName As String, iqyFile As String, parameterCell As String, _
        destinationCell As String) As String

    Dim qt As QueryTable
    
    'Code in this function was generated by the Macro Recorder as a result of
    'Data - Import External Data - Import Data - browse to .iqy file
    'and then modified to suit this program
        
    Set qt = ActiveSheet.QueryTables.Add(Connection:="FINDER;" & iqyFile, Destination:=Range(destinationCell))
    
    With qt
        .Name = queryName
        .FieldNames = True
        .RowNumbers = False
        .FillAdjacentFormulas = False
        .PreserveFormatting = False
        .RefreshOnFileOpen = False
        .BackgroundQuery = False    'False because data requests must be synchronous. Was True when generated by Macro Recorder
        .RefreshStyle = xlOverwriteCells
        .SavePassword = False
        .SaveData = True
        .AdjustColumnWidth = True
        .RefreshPeriod = 0
        .WebSelectionType = xlAllTables
        .WebFormatting = xlWebFormattingAll
        .WebPreFormattedTextToColumns = False
        .WebConsecutiveDelimitersAsOne = True
        .WebSingleBlockTextImport = False
        .WebDisableDateRecognition = False
        .WebDisableRedirections = True
        
        'This With ... End With block sets the web query's parameter value to the specified cell.  Without this,
        'the 'Set Parameter Value' dialogue box appears
        
        'With .Parameters(1)
        '    .SetParam xlRange, ActiveSheet.Range(parameterCell)
        '    .RefreshOnChange = True
        'End With
        
        .Refresh BackgroundQuery:=False
    End With
    
    Create_Dynamic_Query_From_Iqy_File = qt.Name
    
End Function


Private Function Get_Web_Query_Name() As String
    
    Dim qt As QueryTable
    
    'Returns the name of the first web query on the active sheet, or "" if no queries exist
    
    If ActiveSheet.QueryTables.count > 0 Then
        Get_Web_Query_Name = ActiveSheet.QueryTables(1).Name
    Else
        Get_Web_Query_Name = ""
    End If
    
End Function


Private Sub Delete_Yahoo_IE_Temporary_Files()

    'Delete Yahoo Finance files (filenames matching q[*.* and lookup*.*) from the IE cache
    
    Static TemporaryInternetFilesPath As String
    Static ComSpec As String
    Dim oWSH As Object
    Dim IECacheKey As String
    Dim ShellXResult As Long
    Dim DOScommand As String

    If TemporaryInternetFilesPath = "" Then
        IECacheKey = "HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders\Cache"
        Set oWSH = CreateObject("WScript.Shell")
        TemporaryInternetFilesPath = oWSH.RegRead(IECacheKey) & "\Content.IE5\"
    End If
    
    If ComSpec = "" Then ComSpec = Environ$("ComSpec")
    
    'Run DEL commands asynchronously
    
    DOScommand = "DEL /Q /S " & Chr(34) & TemporaryInternetFilesPath & "q[*.*" & Chr(34)
    Shell ComSpec & " /c " & DOScommand, vbHide
    
    DOScommand = "DEL /Q /S " & Chr(34) & TemporaryInternetFilesPath & "lookup*.*" & Chr(34)
    Shell ComSpec & " /c " & DOScommand, vbHide
    
    'May need synchronous Shell function instead - http://vb-tec.de/xshell.htm
    'ShellXResult = ShellX(ComSpec & " /c " & DOScommand, vbHide)
 
End Sub


'=========== Debugging and Information routines ===========

Private Sub Show_All_Queries()
    Dim qt As QueryTable
    For Each qt In ActiveSheet.QueryTables
        Debug.Print qt.Name
    Next
End Sub

Private Sub Delete_Query(queryName As String)
    Dim qt As QueryTable
    For Each qt In ActiveSheet.QueryTables
        If qt.Name = queryName Then qt.Delete
    Next
End Sub

Sub Delete_All_Queries()
    Dim qt As QueryTable
    For Each qt In ActiveSheet.QueryTables
        Debug.Print "Deleted " & qt.Name
        qt.Delete
    Next
End Sub
 
Last edited:
Upvote 0
When I started this exercise I thought that I know something about excel. But your code has made me realize the how shallow that knowledge is. So if nothing more, I have learned humility.

The good new is that I ran the 8k Tickers and everything imported. So I guess that the big problems are now solved.

A couple of questions:
1- You mentioned IE automation as perhaps a better way to accomplish my objective. After all this would you suggest I explore that route?

2- In what way is URL connection string with parameters preferable to using the iqy feature?

3- If I run 2 or more spreadsheets and macros concurrently do you think they will step on one another (Yes, I will test this).

4- Should I run the "Sub Delete_All_Queries()" before I run "Sub Retrieve_All_Symbols()"?



Thanks again

a
 
Upvote 0
Thanks for the update. To answer your questions:

1. I think the web query method is fine if you want to extract all data in specific HTML table(s) from a web page, and it's efficient because it doesn't use the IE browser components. But if you want to extract specific parts of the web page or if the page doesn't use HTML tables then you would have to use IE automation or WinHttpRequest together with DOM manipulation. IE automation has a resource overhead because it uses the IE browser, whereas WinHttpRequest doesn't. Search this forum for 'InternetExplorer' or 'WinHttpRequest' for examples.

2. Unless Excel opens the .iqy file every time the query is refreshed (I haven't checked), I don't think there is any difference between the .iqy file and URL connection string methods - the URL in the .iqy file is identical to the Connection:=URL; string. If you want to try the .iqy method, you'll need to uncomment the 'With .Parameters ... End With' block to make it equivalent to the URL method and, of course, call it in the main loop.

3. Yes, this would be a problem because one instance of the macro could delete temporary internet files that the other instance still needs, causing the latter to fail. One solution would be to delete the files only if they were over 10 minutes old, say. Delete_Yahoo_IE_Temporary_Files would need to be modified to do this. Maybe changing IE settings (e.g. size of its cache) might help.

4. Delete_All_Queries is just for cleaning up and doesn't need to be run before running Retrieve_All_Symbols.

Hope that helps!
 
Upvote 0

Forum statistics

Threads
1,214,581
Messages
6,120,372
Members
448,957
Latest member
BatCoder

We've detected that you are using an adblocker.

We have a great community of people providing Excel help here, but the hosting costs are enormous. You can help keep this site running by allowing ads on MrExcel.com.
Allow Ads at MrExcel

Which adblocker are you using?

Disable AdBlock

Follow these easy steps to disable AdBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the icon in the browser’s toolbar.
2)Click on the "Pause on this site" option.
Go back

Disable AdBlock Plus

Follow these easy steps to disable AdBlock Plus

1)Click on the icon in the browser’s toolbar.
2)Click on the toggle to disable it for "mrexcel.com".
Go back

Disable uBlock Origin

Follow these easy steps to disable uBlock Origin

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back

Disable uBlock

Follow these easy steps to disable uBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back
Back
Top