2

The URL from Yahoo is not working when I try to retrieve quotes from a particular stock. There are several discussion about it, However, it seems nothing is shown regarding VBA macro

Sub Get_Data()
Dim URL As String
Dim Ticker As String
Dim http As New WinHttpRequest
Dim sCotes As String
Dim Lignes
Dim Valeurs
Dim i As Long
Dim j As Long
Dim sLigne As String
Dim sValeur As String

Ticker = Range("Ticker")

URL = "https://query1.finance.yahoo.com/v7/finance/download/TECK?period1=1540456339&period2=1571992339&interval=1d&events=history&crumb=kjOZLFv6ch2"
http.Send
sCotes = http.ResponseText

MsgBox sCotes

Lignes = Split(sCotes, Chr(10))
For i = 1 To UBound(Lignes) 'until the end of the Lignes variable
  sLigne = Lignes(i)
  Valeurs = Split(sLigne, ",")
  For j = 0 To UBound(Valeurs) - 1
  Select Case j
  Case 0
  sValeur = DateSerial(CLng(Left(Valeurs(0), 4)), CLng(Mid(Valeurs(0), 6, 2)), CLng(Right(Valeurs(0), 2)))
  Case 5
  sValeur = CLng(Valeurs(5))
  Case Else
  sValeur = CDbl(Replace(Valeurs(j), ".", ","))
  End Select
  Range("A1").Offset(i, j) = sValeur
  Application.StatusBar = Format(Cells(i, 1), "Short Date")
  Next
Next
Application.StatusBar = False

End Sub

Execution error at the step Http.send : "This method cannot be called until the Open method has been called"

QHarr
  • 83,427
  • 12
  • 54
  • 101
lb2019
  • 65
  • 2
  • 8

3 Answers3

1

You would need to use the "open" method before attempting to send and GET is perfectly fine. However, a few things....

There is an easier way. The headers worth adding are the User-Agent and one to mitigate being served cached results. The following shows you how to get a json response from the server for a specified time period and write to Excel. Note: You need to concatenate the ticker into the url. You should probably also test the response code from server to ensure successful.

I use jsonconverter.bas as the json parser to handle response. 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. Remove the top Attribute line from the copied code.

The values for startDate and endDate need to be passed as unix timestamps. @TimWilliams wrote a nice function, toUnix, for converting Date to Unix here which I use. I have added my own function to manage the conversion in the opposite direction.

This method avoids using any session based identifiers so avoids your issue with invalid cookie crumb.


VBA:

Option Explicit

Public Sub GetYahooHistoricData()
    Dim ticker As String, ws As Worksheet, url As String, s As String
    Dim startDate As Long, endDate As Long

    Set ws = ThisWorkbook.Worksheets("Sheet1")
    ticker = ws.Range("ticker")                  'Range A1. Above write out range

    endDate = toUnix("2019-10-27")
    startDate = toUnix("2018-10-25")
    url = "https://query1.finance.yahoo.com/v8/finance/chart/" & ticker & "?region=US&lang=en-US&includePrePost=false&interval=1d&period1=" & startDate & "&period2=" & endDate & "&corsDomain=finance.yahoo.com&.tsrc=finance"

    With CreateObject("MSXML2.XMLHTTP")
        .Open "GET", url, False
        .setRequestHeader "User-Agent", "Mozilla/5.0"
        .setRequestHeader "If-Modified-Since", "Sat, 1 Jan 2000 00:00:00 GMT"
        .send
        s = .responseText
    End With

    Dim json As Object

    Set json = JsonConverter.ParseJson(s)("chart")("result")

    Dim dates As Object, results(), rows As Object, adjClose As Object, r As Long, headers()

    headers = Array("date", "close", "volume", "open", "high", "low", "adjclose")
    Set dates = json(1)("timestamp")

    ReDim results(1 To dates.Count, 1 To UBound(headers) + 1)

    Set rows = json(1)("indicators")("quote")(1)
    Set adjClose = json(1)("indicators")("adjclose")(1)("adjclose")

    For r = 1 To dates.Count
        results(r, 1) = GetDate(dates(r))
        results(r, 2) = rows("close")(r)
        results(r, 3) = rows("volume")(r)
        results(r, 4) = rows("open")(r)
        results(r, 5) = rows("high")(r)
        results(r, 6) = rows("low")(r)
        results(r, 7) = adjClose(r)
    Next

    With ws
        .Cells(3, 1).Resize(1, UBound(headers) + 1) = headers
        .Cells(4, 1).Resize(UBound(results, 1), UBound(results, 2)) = results
    End With
End Sub

Public Function GetDate(ByVal t As Variant) As String
    GetDate = Format$(t / 86400 + DateValue("1970-01-01"), "yyyy-mm-dd")
End Function

Public Function toUnix(ByVal dt As Variant) As Long
    toUnix = DateDiff("s", "1/1/1970", dt)
End Function

Example top 10 rows:

enter image description here

QHarr
  • 83,427
  • 12
  • 54
  • 101
0

Try replacing this code

URL = "https://query1.finance.yahoo.com/v7/finance/download/TECK?period1=1540456339&period2=1571992339&interval=1d&events=history&crumb=kjOZLFv6ch2"
http.Send

with this code:

set http = Server.Createobject("MSXML2.ServerXMLHTTP.6.0")
URL = "https://query1.finance.yahoo.com/v7/finance/download/TECK?period1=1540456339&period2=1571992339&interval=1d&events=history&crumb=kjOZLFv6ch2"
http.open "POST", URL, False
http.Send

The error is pretty clear: you need to call the open method before the Send method. Also this would be a POST request. You also may need to put these two lines after the open method:

http.setRequestHeader "Content-Type", "application/x-www-form-urlencoded" 
http.setRequestHeader "Content-Length", 0
Max Voisard
  • 1,685
  • 1
  • 8
  • 18
  • Can you really make the code work with "GET"? This is the response I receive - `"finance": { "error": { "code": "Unauthorized", "description": "Invalid cookie"` – Vityata Oct 27 '19 at 15:40
  • It works pretty well with POST to me. And it posts data - `period1=1540456339`, `events=history`, `crumb=kjOZLFv6ch2` and etc. – Vityata Oct 27 '19 at 16:16
  • @Vityata You may be right, after looking at this thread: https://stackoverflow.com/questions/44030983/yahoo-finance-url-not-working. I've edited my answer. – Max Voisard Oct 27 '19 at 16:22
  • That's interesting, because that's the same error @Vityata said he received when using the GET request instead of the POST request. So now it looks like it will return the same error no matter what request is used. In that case, your cookie crumb of "kjOZLFv6ch2" must be invalid, so figure out the right cookie crumb that identifies you as a Yahoo! user. – Max Voisard Oct 27 '19 at 16:51
0

The question is about 99% duplicate as the one from here - How can I send an HTTP POST request to a server from Excel using VBA?. Anyway, the mistake is obviously, because the .Send() method simply sends a completely empty Dim http As New WinHttpRequest object.

To make the code work, copy the example from the duplcated question and print the http.ResponseText:

Sub TestMe()

    Dim http As Object
    Dim url As String
    Set http = CreateObject("MSXML2.ServerXMLHTTP.6.0")
    url = "https://query1.finance.yahoo.com/v7/finance/download/TECK?period1=1540456339&period2=1571992339&interval=1d&events=history&crumb=kjOZLFv6ch2"
    http.Open "POST", url, False
    http.Send
    MsgBox http.responsetext

End Sub
Vityata
  • 42,633
  • 8
  • 55
  • 100