Macro en VBA para descargarse series históricas de Yahoo Finances

1 de diciembre, 2019 Incluye: GOOG 3
Como persona curiosa que soy me interesa la ciencia en general. Aunque eso sí: he de reconocer que lo que realmente me apasiona es la Economía... [+ info]
Como persona curiosa que soy me interesa la ciencia en... [+ info]

Muchas veces deseamos descargar en un Excel una determinada serie histórica. Siempre podemos acceder a una web como la de Yahoo Finances y copiar los datos manualmente, o descargar un archivo que el propio Yahoo pone a nuestra disposición.

0fcc39109c002a095e490fa44c85357f27874edb.jpg

El problema radica en que este Excel viene con los datos de cada periodo temporal acumulados en filas:

08f13eb0cbbe359ce409210be70c8a2e670d01e9.jpg

Para solucionar esta pequeña molestia, a continuación voy a presentarles una macro programada en Excel, la cual lo hará automáticamente. Esta macro nos permitirá descargar los datos del periodo seleccionado, y además organizarlos por celdas. Aunque por supuesto, esto mismo también se puede realizar fácilmente en Excel de forma manual. (Si desea saber cómo, lo explica muy bien Óscar Carchano —profesor de la Universidad de Valencia— en el siguiente enlace: click aquí). 

La ventaja que presentaría mi macro, es que con ligeros cambios, puede reutilizarse el código para descargar de forma sencilla datos procedentes de cualquier página web.

Primer paso: Programar una función que nos descargue en formato texto los datos de una página web

La función en cuestión será la siguiente:

'Función para descargar toda la info. en formato texto de una pág. web.
'Como parámetro de entrada, la fun. recibirá una dirección web en formato texto.
Function ObtenerLink(Link As String) As String
    
    Dim A, Aux As String
    Dim HTTP As Object
    'Creamos un objeto
    Set HTTP = CreateObject("MSXML2.XMLHTTP")
    
    'Con dicho Objeto
    With HTTP
        'Abrimos el link
        .Open "GET", Link, False
        .send
        'Descargamos el texto de la web como respuesta, 
        'y lo introducimos en una variable creada para tal efecto.
        Aux = .responseText
    End With
    
    'Nos interesan nada más que los datos que hay a partir de "]},"; así pues lo dividimos con "split"
    A = Split(Aux, "]},", -1, vbTextCompare)
    'La función nos va a devolver sólo la 2ª parte, que es la que deseamos
    ObtenerLink = A(1)
End Function

Segundo Paso: Generar el enlace con la serie selecionada

Una vez programada la función con la que nos descargaremos la información, a continuación deberemos programar otra que nos genere el enlace que necesitamos:

'Función para obtener una url. La función recibirá como entrada el nombre de la compañía, 
'una fecha de inicio y una fecha final:
Function YahooHistorico(Empresa As String, FechaI As Date, FechaF As Date) As String
    Dim periodo1, periodo2, DataValue As Date
    Dim Link As String
    
' Según queramos el intervalo de la información [ Minutos: 1m, 2m, 5m, 15m, 30m, 60m, 90m,
' Horas 1h, días (es el que tenemos puesto) 1d, 5d, Semanas: 1wk, Meses: 1mo, 3mo].
' Esto se modifica en el link tras: "&interval="
    'La fecha introducida, la transformamos en el formato que Yahoo Finances reconoce:
    periodo1 = (FechaI - DateValue("1 enero, 1970")) * 86400
    periodo2 = (FechaF - DateValue("1 enero, 1970")) * 86400
    
    'Generamos el link que necesitamos, poniendo donde corresponde el nombre de la compañía, 
    'la fecha inicial y la final:
    Link = "https://query1.finance.yahoo.com/v8/finance/chart/" & Empresa & "?symbol=" & Empresa & "&period1=" & periodo1 & "&period2=" & periodo2 & "&interval=1d&includePrePost=true&events=div%2Csplit"
    
    'Lo mandamos a la otra función que hemos programado anteriormente:
    YahooHistorico = ObtenerLink(Link)
End Function  

Para obtener el nombre de la compañía, lo tomamos de la web de Yahoo Finances:

1c37d94b865d59d5c84a477d8c0ed53af2ba8726.jpg

En este caso, para el ejemplo con el que nosotros vamos a trabajar, el nombre de nuestra empresa será "GOOG" (Google).

Tercer Paso: Programar nuestra macro

Para finalizar, a continuación programaremos nuestra macro. Con ella, tras introducir el nombre de la empresa, la fecha inicio y la final, se nos descargará toda la serie histórica de la compañía en nuestro Excel, tal y como deseamos:

'Macro extraer datos históricos de Yahoo Finances
Sub YhFDescargaSerieH()
    'Antes de comenzar, congelamos la actualización de la página de nuestro Excel
    Application.ScreenUpdating = False
      
    'Declaramos las variables que vamos a necesitar
    Dim i, j, DatFinal As Integer
    Dim FechaCo As Date
    Dim Respuesta, Aux, Datos, Columnas(6, 0), Escri As String
    
    'Aquí llamamos a la función que nos va a generar el enlace:
    'introducimos *entre comillas* el nombre de la empresa, 
    'la fecha de inicio de la serie que deseamos descargar y la final.
    Respuesta = YahooHistorico("GOOG", "01/12/2018", "01/11/2019")
    
    'Comenzamos a trocear los datos: Cuando encuentre la apertura de corchete,
    'insertará un salto de línea
     Datos = Split(Respuesta, "[", -1, vbTextCompare)
        
    'Introducimos los distintos datos en una matriz:
    Columnas(0, 0) = Datos(1)
    Columnas(1, 0) = Datos(4)
    Columnas(2, 0) = Datos(7)
    Columnas(3, 0) = Datos(5)
    Columnas(4, 0) = Datos(3)
    Columnas(5, 0) = Datos(9)
    Columnas(6, 0) = Datos(6)
    
For j = 1 To 6
        'Separamos los datos
        Aux = Split(Columnas(j, 0), ",", -1, vbTextCompare)
        'Escribimos las columnas con los valores (Las fechas las dejamos para el final).
'Atención: Salvo la columna de las fechas (que siempre es la primera), 
'Yahoo cambia el orden de todas las demás.
            For i = 0 To UBound(Aux) - 2
                Cells(3 + i, j + 1) = Aux(i)
            Next i
            Cells(UBound(Aux) + 2, j + 1) = Replace(Aux(i), "]", "")
    Next j
        
    'Quitamos los corchetes que aparecen en los datos de la última fila
    Cells(UBound(Aux) + 2, 3) = Replace(Cells(UBound(Aux) + 2, 3), "}", "")
    Cells(UBound(Aux) + 2, 6) = Replace(Cells(UBound(Aux) + 2, 6), "}}}", "")
    
    'Escribimos los datos almacenados en la primera columna, que como indiqué más arriba, siempre son las fechas.    
    j = 0
    'Necesitamos una variable que nos señale cuál es la última fila porque a veces hay más datos acumulados al final de la columna de las fechas.
    'Por ello, indicaremos que el bucle termine en "DatFinal" en vez de en "UBound(Aux)-2" como en los anteriores.
    DatFinal = i
    Aux = Split(Columnas(0, 0), ",", -1, vbTextCompare)
    
    For i = 0 To DatFinal
                'Transformamos la primera columna en una fecha válida
                Escri = Aux(i)
                Escri = Replace(Escri, "]", "")
                FechaCo = (Escri + DateValue("1 enero, 1970")) / 86400
                'La ajustamos añadiendo días, años... según nos convenga.
                FechaCo = DateAdd("yyyy", 70, FechaCo)
                FechaCo = DateAdd("d", 2, FechaCo)
                Cells(3 + i, j + 1) = FechaCo
    Next i
    
    'Descongelamos nuestra hoja
    Application.ScreenUpdating = True
End Sub

Y con esto estaría ya todo listo: ejecutando nuestra macro, ya disponemos de los datos que deseamos bien organizados en nuestro Excel:

39c9e0ba1af296231124ef85c785778f6c1daff0.jpg

Ustedes podrán añadir y editar lo que deseen del código para hacerlo más completo o mejorarlo, pero la idea general pienso que se ve clara en el presente artículo. Así que esto ha sido todo, espero que las funciones y la macro presentadas en este post les sean de utilidad.

Por mi parte nada más:

Un saludo, y hasta la próxima.

Usuarios a los que les gusta este artículo:

Este artículo tiene 3 comentarios
Buenas tardes Mario, en primer lugar agradecerte por este Post, ha sido realmente útil y enriquecedor.
Ahora mismo estoy haciendo lo mismo pero evaluando cotización de monedas de cambio y me frustra lo que hace Yahoo de cambiar el orden de las columnas exceptuando la de fecha. Quería preguntarte, ¿sabes como puedo controlar eso? ¿alguna idea?
Muchas gracias de antemano.
22/03/2020 12:46
Estimado Javier:
Antes de nada, ¡muchas gracias por leerme!

Respondiéndole a su cuestión, el caso, es que pienso que sí debe tener una solución relativamente sencilla... Si se fija, en la parte del código donde paso la información desde la matriz "Datos" a las variables "Columnas": "Columnas(0, 0) = Datos(1)" no sigo un orden ascendente… (el siguiente que pongo es "Datos(4)") Esto es así porque estuve trasteando un rato para ver si organizaba las columnas y dejaba el cuadro bonito.

Finalmente, tras haberle dedicado dos tardes a programar todo esto, cuando vi que Yahoo alteraba orden, y dado que a mí en realidad no me importaba, lo dejé ahí…

Pues bien, ¿cómo se podría proceder? Pues habiéndole echado un vistazo ahora rápido, si mira lo que contiene "Datos(2)" --Ver Foto 1-- ahí aparece la etiqueta que correspondería a "Datos(3)".

Para el resto, si en vez de llegar a "UBound(Aux) - 2", ponemos "UBound(Aux) - 1", se comprueba que el último dato que tenemos es el de la etiqueta de la columna siguiente. --Ver Foto 2--.

Por tanto, teniendo en cuenta que las etiquetas están en realidad ahí, se puede simplemente añadir un par de líneas de código al final para que las escriba en los encabezados que corresponda...

Así, lo 1º que habría que hacer es poner los "Columnas(0, 0) = Datos(1)" por orden:

Columnas(0, 0) = Datos(1)
Columnas(1, 0) = Datos(3)
Columnas(2, 0) = Datos(4)
Columnas(3, 0) = Datos(5)
Columnas(4, 0) = Datos(6)
Columnas(5, 0) = Datos(7)
Columnas(6, 0) = Datos(9)

Y luego, dado que sabemos que a "Columnas(1, 0)" le corresponde la etiqueta de "Datos(2)", a "Columnas(6, 0)" la de "Datos(8)" o el valor final contenido en " Columnas(5, 0)", a "Columnas(2, 0)" el dato final de "Columnas(1, 0)"… (el resto igual que este último), pues ya podríamos escribir los encabezados correspondientes de cada columna.

Espero haberle resultado de ayudada…
Reciba un cordial saludo,
Mario Gutiérrez.
23/03/2020 20:01
Escriba un nuevo comentario

Identifíquese ó regístrese para comentar el artículo.