How to download data from Yahoo finance limited to 100 rows - excel

So I'm doing this project where I have to download historical stock data from yahoo finance. Got this code. It's working fine, BUT it only downloads max 100 rows. I tried to scan the web for answers or a different code (this one is just recorded macro from excel) but I saw a few tutorials on YouTube that use his solution and it's just fine.
.. I don't understand it then
Sub Makro6()
' Dowload stock prices from Yahoo Finance based on input
Dim ws As Worksheet
Set ws = Sheets("Data")
'clear previous queries
For Each qr In ThisWorkbook.Queries
qr.Delete
Next qr
'clear Data sheet
ws.Select
Cells.Clear
'clear graphs
'ws.ChartObjects.Delete
'stock = Sheets("Main").Range("A2")
StartDate = toUnix(Sheets("Main").Range("A4"))
EndDate = toUnix(Sheets("Main").Range("A6"))
Application.CutCopyMode = False
ActiveWorkbook.Queries.Add Name:="Table 2 (3)", Formula:= _
"let" & Chr(13) & "" & Chr(10) & " Zdroj = Web.Page(Web.Contents(""https://finance.yahoo.com/quote/" & stock & "/history?period1=" & StartDate & "&period2=" & EndDate & "&interval=1d&filter=history&frequency=1d""))," & Chr(13) & "" & Chr(10) & " Data2 = Zdroj{2}[Data]," & Chr(13) & "" & Chr(10) & " #""Změněný typ"" = Table.TransformColumnTypes(Data2,{{""Date"", type date}, {""Open"", type text}, {""High"", type text}, {""Low"", type text}, {""Close*"", type tex" & _
"t}, {""Adj Close**"", type text}, {""Volume"", type text}})" & Chr(13) & "" & Chr(10) & "in" & Chr(13) & "" & Chr(10) & " #""Změněný typ"""
With ActiveSheet.ListObjects.Add(SourceType:=0, Source:= _
"OLEDB;Provider=Microsoft.Mashup.OleDb.1;Data Source=$Workbook$;Location=""Table 2 (3)"";Extended Properties=""""" _
, Destination:=Range("$A$1")).QueryTable
.CommandType = xlCmdSql
.CommandText = Array("SELECT * FROM [Table 2 (3)]")
.RowNumbers = False
.FillAdjacentFormulas = False
.PreserveFormatting = True
.RefreshOnFileOpen = False
.BackgroundQuery = True
.RefreshStyle = xlInsertDeleteCells
.SavePassword = False
.SaveData = True
.AdjustColumnWidth = True
.RefreshPeriod = 0
.PreserveColumnInfo = True
.ListObject.DisplayName = "Table_2_3"
.Refresh BackgroundQuery:=False
End With
Sheets("Data").Select
'' Sort data by date from oldest to newest
ws.ListObjects("Table_2_3").Sort.SortFields. _
Clear
ws.ListObjects("Table_2_3").Sort.SortFields. _
Add2 Key:=Range("A1:A99"), SortOn:=xlSortOnValues, Order:=xlAscending, _
DataOption:=xlSortNormal
With ws.ListObjects("Table_2_3").Sort
.Header = xlYes
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
Call DeleteDividends
Call Stochastics
End Sub
The code works for other websites. I tried to download Wikipedia page list of total 120 and it loaded data no problem.
The problem is the data from Yahoo finance website is a project requirement

If you check against the page you will discover only 100 results are initially present within the HTMLTable rows (tbody to be precise).
Enter the css selector [data-test="historical-prices"] tbody tr in the browser elements tab search box (F12 to open dev tools)and you will see this:
The rest of the rows are fed dynamically from a data store as you scroll down the page. Of course, your current method doesn't pick up on these. You can in fact issue an xhr request, regex out the appropriate javascript object housing all the rows, and parse with a json parser.
Here is roughly what you should currently see in response:
I use jsonconverter.bas as my json parser. Download raw code from here and add to standard module called jsonConverter . You then need to go VBE > Tools > References > Add reference to Microsoft Scripting Runtime.
#TimWilliams wrote a better unix conversion function here but I thought I would have a play at writing something different. I would advise you to stick with his as it is safer and faster.
VBA:
Option Explicit
Public Sub GetYahooData()
'< VBE > Tools > References > Microsoft Scripting Runtime
Dim json As Object, re As Object, s As String, xhr As Object, ws As Worksheet
Dim startDate As String, endDate As String, stock As String
Set ws = ThisWorkbook.Worksheets("Sheet1")
Set re = CreateObject("VBScript.RegExp")
Set xhr = CreateObject("MSXML2.XMLHTTP")
stock = "AAPL"
startDate = "1534809600"
endDate = "1566345600"
With xhr
.Open "GET", "https://finance.yahoo.com/quote/" & stock & "/history?period1=" & startDate & "&period2=" & endDate & "&interval=1d&filter=history&frequency=1d&_guc_consent_skip=" & GetCurrentUnix(Now()), False
.setRequestHeader "User-Agent", "Mozilla/5.0"
.send
s = .responseText
End With
s = GetJsonString(re, s)
If s = "No match" Then Exit Sub
Set json = JsonConverter.ParseJson(s)
WriteOutResults ws, json
End Sub
Public Sub WriteOutResults(ByVal ws As Worksheet, ByVal json As Object)
Dim item As Object, key As Variant, headers(), results(), r As Long, c As Long
headers = json.item(1).keys
ReDim results(1 To json.Count, 1 To UBound(headers) + 1)
For Each item In json
r = r + 1: c = 1
For Each key In item.keys
results(r, c) = item(key)
c = c + 1
Next
Next
With ws
.Cells(1, 1).Resize(1, UBound(headers) + 1) = headers
.Cells(2, 1).Resize(UBound(results, 1), UBound(results, 2)) = results
End With
End Sub
Public Function GetJsonString(ByVal re As Object, ByVal responseText As String) As String
With re
.Global = True
.MultiLine = True
.IgnoreCase = False
.Pattern = "HistoricalPriceStore"":{""prices"":(.*?\])" 'regex pattern to get json string
If .test(responseText) Then
GetJsonString = .Execute(responseText)(0).SubMatches(0)
Else
GetJsonString = "No match"
End If
End With
End Function
Public Function GetCurrentUnix(ByVal t As Double) As String
With CreateObject("htmlfile")
.parentWindow.execScript "function GetTimeStamp(t){return new Date(t).getTime() / 1000}", "jscript"
GetCurrentUnix = .parentWindow.GetTimeStamp(Now)
End With
End Function
Regex:
Python:
I initially wrote as python if of interest:
import requests, re, json
from bs4 import BeautifulSoup as bs
p = re.compile('HistoricalPriceStore":{"prices":(.*?\])')
r = requests.get('https://finance.yahoo.com/quote/AAPL/history?period1=1534809600&period2=1566345600&interval=1d&filter=history&frequency=1d&_guc_consent_skip=1566859607')
data = json.loads(p.findall(r.text)[0])

Related

How to avoid Power Query error with empty query from VBA Excel?

I would like to import a text file into Excel filtering just what I want through a VBA macro. The amount of data is large so I use efficently the Power queries. I have a list of several things to filter and process differently and this list could change. So for each "feature" to filter I reload the query in a new sheet.
If the filter makes the query empty I get an error from the Power Query that I am not able to skip with:
Application.EnableEvents = False
Application.ScreenUpdating = False
Application.DisplayAlerts = False
Debugging I see that the error comes out between the query creation and the paste to the sheet, see (*) in the code below.
Does somebody know if there is a way to have the number of records into the query in order to be able to use an if statement and skip the paste phase?
The only other idea that I have is to write automatically a row for each feature into the txt file to filter but it is not an elegant method
A thing that I do not understand is that the problem appear using a function, see below, but not using directly a macro.
When I use the function the error shown does not appear always but in any case the code finish the function but the main macro stops.
test.txt
946737295 9CE78280 FF 1 5 FF FF FF FF FF
946737295 9CE78280 C0 FF 0 0 0 0 FF FF
946737295 9CE68082 C0 4 0 FF FF FF FF FF
and the macro is:
Function readTxt(input_path As String, Pgn As String, B2 As String, B3 As String) As Boolean
Dim Wb As Workbook
Dim Ws As Worksheet
Dim Conn As WorkbookConnection
Dim mFormula As String
Dim query As WorkbookQuery
Set Wb = ActiveWorkbook
Set Ws = Wb.ActiveSheet
On Error Resume Next
Application.EnableEvents = False
Application.ScreenUpdating = False
Application.DisplayAlerts = False
mFormula = "let " & _
"Source = Csv.Document(File.Contents(""" & input_path & """),[Delimiter=""#(tab)"", Columns=10, Encoding=65001, QuoteStyle=QuoteStyle.Csv])," & _
"#""Step1"" = Table.SelectRows(Source, each Text.Contains([Column2], """ & Pgn & """) and [Column5] = """ & B3 & """ and [Column4] = """ & B2 & """)," & _
"#""Step2"" = Table.RemoveColumns(Step1,{""Column2"", ""Column3"", ""Column4"", ""Column5"", ""Column9"", ""Column10""})" & _
"in #""Step2"""
Set query = Wb.Queries.Add("test_7", mFormula)
With Ws.ListObjects.Add(SourceType:=0, Source:= _
"OLEDB;Provider=Microsoft.Mashup.OleDb.1;Data Source=$Workbook$;Location=" & "test_7" & ";Extended Properties=""""", Destination:=Ws.Range("A3"), XlListObjectHasHeaders:=xlYes).QueryTable
'.ListObject.TotalsRowRange
.CommandType = xlCmdSql
.AdjustColumnWidth = False
.ListObject.Name = "test"
.CommandText = "SELECT * FROM [" & "test_7" & "]"
.Refresh BackgroundQuery:=False
End With
If Err.Number <> 0 Then
Err.Clear
End If
query.Delete
Application.EnableEvents = True
Application.ScreenUpdating = True
Application.DisplayAlerts = True
readTxt = True 'output
On Error GoTo 0
End Function
Sub readTxt()
Dim Wb As Workbook
Dim Ws As Worksheet
Dim Conn As WorkbookConnection
Dim mFormula As String
Dim query As WorkbookQuery
Set Wb = ActiveWorkbook
Dim i As Integer
Dim C3 As String
On Error Resume Next
Application.EnableEvents = False
Application.ScreenUpdating = False
Application.DisplayAlerts = False
C3 = "F2"
For i = 1 To 2
If i = 2 Then
C3 = "FF"
Sheets.Add After:=ActiveSheet
End If
Set Ws = Wb.ActiveSheet
mFormula = "let " & _
"Source = Csv.Document(File.Contents(""C:\test.txt""),[Delimiter=""#(tab)"", Encoding=65001, QuoteStyle=QuoteStyle.Csv])," & _
"#""Step1"" = Table.SelectRows(Source, each Text.Contains([Column2], ""E7"") and [Column3] = """ & C3 & """)" & _
"in #""Step1"""
Set query = Wb.Queries.Add("Test_text", mFormula)
' (*) THE ERROR OF POWER QUERY APPEARS HERE
With Ws.ListObjects.Add(SourceType:=0, Source:= _
"OLEDB;Provider=Microsoft.Mashup.OleDb.1;Data Source=$Workbook$;Location=" & "Test_text" & ";Extended Properties=""""", Destination:=Ws.Range("A3"), XlListObjectHasHeaders:=xlYes).QueryTable
.CommandType = xlCmdSql
.AdjustColumnWidth = False
.ListObject.Name = "test"
.CommandText = "SELECT * FROM [" & "Test_text" & "]"
.Refresh BackgroundQuery:=False
End With
query.Delete
Next
Application.EnableEvents = True
Application.ScreenUpdating = True
Application.DisplayAlerts = True
On Error GoTo 0
End Sub
Thanks,
Ruggero
You can check if a step (table) has some specific columns using this code:
let Source = Csv.Document(File.Contents("C:\temp\test.txt"),[Delimiter=";", Encoding=65001, QuoteStyle=QuoteStyle.Csv]),
#"Step1" = Table.SelectRows(Source, each Text.Contains([Column2], "E7") and [Column3] = "F1"),
result_error = "Some error",
check_columns = Table.HasColumns(#"Step1", {"Column2", "Column3"}),
result = if check_columns = true then #"Step1" else result_error
in result
See the check_columns step and the conditional result

How to use a variable to represent a link?

I recorded a macro and tried to adapt it using a for loop with the different links I want to scrape data from.
The problem is, that VBA doesn't recognize my variable as a link. When I type in a link directly in the code, it works. I do not only need data from one link, but from 500.
Here is my code fragment:
Dim Link As String
Link = "https://coinmarketcap.com/currencies/bitcoin/historical-data/"
For i = 1 To 5
Link = Cells(i, 1)
ActiveWorkbook.Queries.Add Name:="Table 0 (3)", Formula:= _
"let" & Chr(13) & "" & Chr(10) & " Quelle = Web.Page(Web.Contents(""https://coinmarketcap.com/currencies/ontology/historical-data/""))," & Chr(13) & "" & Chr(10) & " Data0 = Quelle{0}[Data]," & Chr(13) & "" & Chr(10) & " #""Geänderter Typ"" = Table.TransformColumnTypes(Data0,{{""Date"", type date}, {""Open*"", type number}, {""High"", type number}, {""Low"", type number}, {""Close**"", type number}, {""Volume"", type number}, {""Market Cap" & _
""", type number}})" & Chr(13) & "" & Chr(10) & "in" & Chr(13) & "" & Chr(10) & " #""Geänderter Typ"""
With ActiveSheet.ListObjects.Add(SourceType:=0, Source:= _
"OLEDB;Provider=Microsoft.Mashup.OleDb.1;Data Source=$Workbook$;Location=""Table 0 (3)"";Extended Properties=""""" _
, Destination:=Range("$D$1")).QueryTable
.CommandType = xlCmdSql
.CommandText = Array("SELECT * FROM [Table 0 (3)]")
.RowNumbers = False
.FillAdjacentFormulas = False
.PreserveFormatting = True
.RefreshOnFileOpen = False
.BackgroundQuery = True
.RefreshStyle = xlInsertDeleteCells
.SavePassword = False
.SaveData = True
.AdjustColumnWidth = True
.RefreshPeriod = 0
.PreserveColumnInfo = True
.ListObject.DisplayName = "Table_0__3"
.Refresh BackgroundQuery:=False
End With
Next
As soon as I change the link (""https://coinmarketcap.comblabla"") for the variable "link", I get an application or object defined error. When I dig deeper and click on the array, Excel tells me that the Import "link" is not connected to an export.
You can get the main historic data table and the info above with the code below. It is a little tricky and somewhat fragile as a lot of this relies on the current page styling, which can change. The historic data bit, which is an actual table, is a more robust.
You can loop using new URLs picked from cells, for example, and simply have a Sheets.Add line in at the start of each loop so you have a new Activesheet to write data to.
Below, should be enough to get you started depending on your requirements.
I get the top bit:
using
.Cells(1, 1) = IE.document.querySelector(".col-xs-6.col-sm-8.col-md-4.text-left").innerText. This is not very robust. The document's styling could be changed. However, it is not an easy part of the page to access and obtaining it will likely be vulnerable which ever method you choose currently. I am using the element's classname (".") to retrieve the information using the .querySelector method of document to apply the CSS selector .col-xs-6.col-sm-8.col-md-4.text-left. That is the same as .getElementsByClassName(0).
I get the middle bit:
With
Set aNodeList = IE.document.querySelectorAll("[class*='coin-summary'] div")
This uses the CSS selector [class*='coin-summary'] div , which are the div tags within elements' with a className containing the string 'coin-summary'.
That CSS selector returns a list so the .querySelectorAll method is used to return a nodeLIst which is then traversed.
I get the end historic data (which is an actual table), using the table tag:
Set hTable = .document.getElementsByTagName("table")(0)
I then traverse the rows, and cells within rows, of the table.
VBA:
Option Explicit
Public Sub GetInfo()
Dim IE As Object
Set IE = CreateObject("InternetExplorer.Application")
Application.ScreenUpdating = False
With IE
.Visible = True
.navigate "https://coinmarketcap.com/currencies/bitcoin/historical-data/"
While .Busy Or .readyState < 4: DoEvents: Wend '<== Loop until loaded
Dim hTable As HTMLTable
Set hTable = .document.getElementsByTagName("table")(0)
Dim tSection As Object, tRow As Object, tCell As Object, tr As Object, td As Object, r As Long, c As Long, hBody As Object
Dim headers(), headers2()
headers = Array("Date", "Open*", "High", "Low", "Close**", "volume", "Market Cap")
headers2 = Array("Market Cap", "Volume (24h)", "Circulating Supply", "Max Supply")
With ActiveSheet
.Cells.ClearContents
.Cells(1, 1) = IE.document.querySelector(".col-xs-6.col-sm-8.col-md-4.text-left").innerText
Dim aNodeList As Object, i As Long, resumeRow As Long
Set aNodeList = IE.document.querySelectorAll("[class*='coin-summary'] div")
resumeRow = .Cells(.Rows.Count, "A").End(xlUp).Row + 2
.Range("A" & resumeRow).Resize(1, UBound(headers2) + 1) = headers2
For i = 0 To aNodeList.Length - 1
.Cells(resumeRow + 1, i + 1) = aNodeList.item(i).innerText
Next i
r = .Cells(.Rows.Count, "A").End(xlUp).Row + 2
.Cells(r, 1).Resize(1, UBound(headers) + 1) = headers
Set hBody = hTable.getElementsByTagName("tbody")
For Each tSection In hBody 'HTMLTableSection
Set tRow = tSection.getElementsByTagName("tr") 'HTMLTableRow
For Each tr In tRow
r = r + 1
Set tCell = tr.getElementsByTagName("td")
c = 1
For Each td In tCell 'DispHTMLElementCollection
.Cells(r, c).Value = td.innerText 'HTMLTableCell
c = c + 1
Next td
Next tr
Next tSection
End With
'Quit '<== Remember to quit application
Application.ScreenUpdating = True
End With
End Sub
Output in sheet (sample):
Some example data from page:
This will get the data from that table.
Option Explicit
Sub Web_Table_Option_One()
Dim xml As Object
Dim html As Object
Dim objTable As Object
Dim result As String
Dim lRow As Long
Dim lngTable As Long
Dim lngRow As Long
Dim lngCol As Long
Dim ActRw As Long
Set xml = CreateObject("MSXML2.XMLHTTP.6.0")
With xml
.Open "GET", "https://coinmarketcap.com/currencies/bitcoin/historical-data/", False
.send
End With
result = xml.responseText
Set html = CreateObject("htmlfile")
html.body.innerHTML = result
Set objTable = html.getElementsByTagName("Table")
For lngTable = 0 To objTable.Length - 1
For lngRow = 0 To objTable(lngTable).Rows.Length - 1
For lngCol = 0 To objTable(lngTable).Rows(lngRow).Cells.Length - 1
ThisWorkbook.Sheets("Sheet1").Cells(ActRw + lngRow + 1, lngCol + 1) = objTable(lngTable).Rows(lngRow).Cells(lngCol).innerText
Next lngCol
Next lngRow
ActRw = ActRw + objTable(lngTable).Rows.Length + 1
Next lngTable
End Sub
You can certainly loop through an array of URLs, and iterate through each one. Where are these 500 URLs? If they are not the same as the one you provided, you may have your work cut out for you. Normally, all web sites are very different , and screen scraping is a highly customized process.

Macro Loops for Generation

I am creating a template, like an excel form (CATALOG) that is needed to be generated into PDF and in another sheet, must be copied to another sheet and also to be saved in an excel form. I have a generate button where my macro is. But the problem is, it keeps looping as it keeps saving infinitely. I can't find what's wrong. Hope you can help. thanks in advance! :)
Here's the code:
Sub savetopdf()
Dim FilePath As String
Dim FileName As String
Dim FileName2 As String
Dim MyDate As String
Dim client As String
Dim ref As Integer
Dim type1 As String
Dim NewBook As Workbook
Application.DisplayAlerts = False
Rows("27").EntireRow.Hidden = True
Rows("46").EntireRow.Hidden = True
Rows("47").EntireRow.Hidden = True
Rows("59").EntireRow.Hidden = True
Rows("63").EntireRow.Hidden = True
Rows("69").EntireRow.Hidden = True
Rows("78").EntireRow.Hidden = True
Rows("90").EntireRow.Hidden = True
Rows("96").EntireRow.Hidden = True
ThisWorkbook.Sheets("CATALOG").Shapes("Rounded Rectangle 3").Visible = False
FilePath = "\\10.10.19.20\2017\5. SALES OPERATIONS\4. ENTERPRISE BUSINESS
GROUP\CUSTOMER DATA BASE\Maintenance-Warranty Summary"
MyDate = Format(Date, "MM-DD-YYYY")
ref = ThisWorkbook.Sheets("CATALOG").Range("G13").Value + 1
client = ThisWorkbook.Sheets("CATALOG").Range("C5").Value
type1 = ThisWorkbook.Sheets("CATALOG").Range("C16").Value
With ThisWorkbook.Sheets("CATALOG").PageSetup
.CenterHeader = ""
.Orientation = xlPortrait
.PrintArea = "$B$2:$F$98"
.PrintTitleRows = ActiveSheet.Rows(2).Address
.Zoom = False
.FitToPagesTall = 1
.FitToPagesWide = 1
End With
FileName = FilePath & "\" & MyDate & "_" & ref & "_" & client
ThisWorkbook.Sheets("Catalog").ExportAsFixedFormat Type:=xlTypePDF,
FileName:=FileName, _
Quality:=xlQualityStandard, _
IncludeDocProperties:=False, _
IgnorePrintAreas:=False, _
From:=1, _
To:=1, _
OpenAfterPublish:=True
FileName2 = FilePath & "\" & MyDate & "_" & ref & "_" & client
Set NewBook = Workbooks.Add
ThisWorkbook.Sheets("INVENTORY LIST").Copy Before:=NewBook.Sheets(1)
NewBook.SaveAs FileName:=FileName2, FileFormat:=xlOpenXMLWorkbook
ThisWorkbook.Sheets("CATALOG").Range("G13").Value = ref
ThisWorkbook.Save
End Sub

How to refresh table data on all sheets

I need to run a VBScript that can dynamically set a SQL Server connection string, taking server name and database name from Excel cells, and refresh tables in all worksheets of the file.
I currently have this script against a 'Refresh' button on the 'Setup' sheet (from where it takes the server and database names):
Sub Refresh_Click()
Dim Sh As Worksheet
Dim sServer As String
Dim sDatabase As String
Dim sTableName As String
Dim vDestinationRg As Variant
Dim sQuery(1 To 24) As String
Dim vQueryArray As Variant
Dim i As Integer
Dim j As Integer
Dim isSplit As Boolean
Dim sUsername As String
Dim sPassword As String
Set Sh = ActiveSheet
j = 1
isSplit = True
vQueryArray = Application.Transpose(Sh.Range("U1:U10"))
For i = LBound(vQueryArray) To UBound(vQueryArray)
If vQueryArray(i) <> "" Then
isSplit = False
sQuery(j) = sQuery(j) & Trim(vQueryArray(i)) & vbCrLf
ElseIf Not isSplit Then
isSplit = True
j = j + 1
End If
Next i
sServer = Sheets("Setup").Range("F5").Value
sDatabase = Sheets("Setup").Range("F7").Value
vDestinationRg = Array("$H$12")
sUsername = "username"
sPassword = "********"
For i = LBound(sQuery) To UBound(sQuery)
If sQuery(i) = "" Then Exit Sub
sTableName = "Result_Table_" & Replace(Replace(Sh.Name, " ", ""), "-", "") & "_" & i
On Error Resume Next
Sh.ListObjects(sTableName).Delete
On Error GoTo 0
With Sh.ListObjects.Add(SourceType:=0, Source:=Array( _
"OLEDB;Provider=SQLOLEDB.1;User Id=" & sUsername & "; Password=" & sPassword & ";Data Source=" & sServer & ";Initial Catalog=" & sDatabase & ""), Destination:=Sh.Range(vDestinationRg(i - 1))).QueryTable
.CommandText = sQuery(i)
.RowNumbers = False
.FillAdjacentFormulas = False
.PreserveFormatting = True
.RefreshOnFileOpen = False
.BackgroundQuery = True
.RefreshStyle = xlInsertDeleteCells
.SavePassword = False
.SaveData = True
.AdjustColumnWidth = True
.RefreshPeriod = 0
.PreserveColumnInfo = True
.ListObject.DisplayName = sTableName
.Refresh BackgroundQuery:=False
End With
Next
End Sub
I have a select query written in cell "U1" of the 'Setup' sheet and it creates and populates the table into the destination range starting from "H12".
But instead of placing the query on the 'Setup' sheet I want to write queries on different worksheets which would populate tables in the respective worksheets, with only this one Refresh button click on the Setup sheet.
How can I do this?
I have been told it can be achieved without writing VBScript also, but no luck there! I tried adding SQL server connections to the workbook, but can't make it dynamic from there.

excel vba http request download data from yahoo finance

I am in the process of making a program I wrote using excel vba faster.
The program downloads stock market data from the asx.
I want to get data from 2 urls:
MY CODE
url2 = "http://ichart.finance.yahoo.com/table.txt?s=bhp.ax"
Set XMLHTTP = CreateObject("WinHttp.WinHttpRequest.5.1")
XMLHTTP.Open "GET", url2, False
XMLHTTP.send
result = XMLHTTP.responseText
ActiveCell.Value = result
Set XMLHTTP = Nothing
URL 1. http://ichart.finance.yahoo.com/table.txt?s=bhp.ax
MY PROBLEM.
This file is very large. I thought I could simply store the result of these http requests and print it to the debug window or directly to a cell. However these methods seem to be cutting off parts of the data?
if I download the txt file from url 2 in notepad++ it has almost 200 000 characters
but it excel it has between 3 -5 000. What is the best way to handle these requests so that all the data is captured and I can parse it all later?
URL 2. from the first URL I only want the JSON data which results from the YQL query.
MY PROBLEM
I am not sure how to get just the json data when you follow the link below, and or how to store it so that the problem experienced with URL 1 (missing data) does not occur.
http://developer.yahoo.com/yql/console/?q=select%20symbol%2C%20ChangeRealtime%20from%20yahoo.finance.quotes%20where%20symbol%20in%20%28%22YHOO%22%2C%22AAPL%22%2C%22GOOG%22%2C%22MSFT%22%29%20|%20sort%28field%3D%22ChangeRealtime%22%2C%20descending%3D%22true%22%29%0A%09%09&env=http%3A%2F%2Fdatatables.org%2Falltables.env#h=select%20*%20from%20yahoo.finance.quotes%20where%20symbol%20in%20%28%22bhp.ax%22%29
Many Thanks, Josh.
Try this revised code
Sub GetYahooFinanceTable()
Dim sURL As String, sResult As String
Dim oResult As Variant, oData As Variant, R As Long, C As Long
sURL = "http://ichart.finance.yahoo.com/table.txt?s=bhp.ax"
Debug.Print "URL: " & sURL
sResult = GetHTTPResult(sURL)
oResult = Split(sResult, vbLf)
Debug.Print "Lines of result: " & UBound(oResult)
For R = 0 To UBound(oResult)
oData = Split(oResult(R), ",")
For C = 0 To UBound(oData)
ActiveSheet.Cells(R + 1, C + 1) = oData(C)
Next
Next
Set oResult = Nothing
End Sub
Function GetHTTPResult(sURL As String) As String
Dim XMLHTTP As Variant, sResult As String
Set XMLHTTP = CreateObject("WinHttp.WinHttpRequest.5.1")
XMLHTTP.Open "GET", sURL, False
XMLHTTP.Send
Debug.Print "Status: " & XMLHTTP.Status & " - " & XMLHTTP.StatusText
sResult = XMLHTTP.ResponseText
Debug.Print "Length of response: " & Len(sResult)
Set XMLHTTP = Nothing
GetHTTPResult = sResult
End Function
This will split up the data into Rows so the max text length are not reached in a cell. Also this have further split the data with commas into corresponding columns.
You may like to try following code from http://investexcel.net/importing-historical-stock-prices-from-yahoo-into-excel/
I just modify the qurl variable to your url and it work, it pouring 4087 line of data to my excel sheet, nicely formatted without any problem.
Just name your sheet1 as Data.
Sub GetData()
Dim DataSheet As Worksheet
Dim EndDate As Date
Dim StartDate As Date
Dim Symbol As String
Dim qurl As String
Dim nQuery As Name
Dim LastRow As Integer
Application.ScreenUpdating = False
Application.DisplayAlerts = False
Application.Calculation = xlCalculationManual
Sheets("Data").Cells.Clear
Set DataSheet = ActiveSheet
' StartDate = DataSheet.Range("startDate").Value
' EndDate = DataSheet.Range("endDate").Value
' Symbol = DataSheet.Range("ticker").Value
' Sheets("Data").Range("a1").CurrentRegion.ClearContents
' qurl = "http://ichart.finance.yahoo.com/table.csv?s=" & Symbol
' qurl = qurl & "&a=" & Month(StartDate) - 1 & "&b=" & Day(StartDate) & _
' "&c=" & Year(StartDate) & "&d=" & Month(EndDate) - 1 & "&e=" & _
' Day(EndDate) & "&f=" & Year(EndDate) & "&g=" & Sheets("Data").Range("a1") & "&q=q&y=0&z=" & _
' Symbol & "&x=.csv"
qurl = "http://ichart.finance.yahoo.com/table.txt?s=bhp.ax"
Debug.Print qurl
QueryQuote:
With Sheets("Data").QueryTables.Add(Connection:="URL;" & qurl, Destination:=Sheets("Data").Range("a1"))
.BackgroundQuery = True
.TablesOnlyFromHTML = False
.Refresh BackgroundQuery:=False
.SaveData = True
End With
Sheets("Data").Range("a1").CurrentRegion.TextToColumns Destination:=Sheets("Data").Range("a1"), DataType:=xlDelimited, _
TextQualifier:=xlDoubleQuote, ConsecutiveDelimiter:=False, Tab:=True, _
Semicolon:=False, Comma:=True, Space:=False, other:=False
Sheets("Data").Columns("A:G").ColumnWidth = 12
LastRow = Sheets("Data").UsedRange.Row - 2 + Sheets("Data").UsedRange.Rows.Count
Sheets("Data").Sort.SortFields.Add Key:=Range("A2"), _
SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
With Sheets("Data").Sort
.SetRange Range("A1:G" & LastRow)
.Header = xlYes
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
.SortFields.Clear
End With
End Sub
(the above is not my code, it was taken from the excel file they posted on investexcel.net link above)

Resources