Nota

Esta página fue generada a partir de docs/tutorials/11_time_series.ipynb.

Carga y Procesamiento de Datos de Series Temporales del Mercado de Valores#

Introducción#

En muchos problemas en finanzas, uno comienza con series de tiempo. Aquí, mostramos cómo generar series de tiempo pseudoaleatorias, descargar series de tiempo reales del mercado de valores de varios proveedores comunes y cómo calcular medidas de similitud de series de tiempo.

[1]:
%matplotlib inline
from qiskit_finance import QiskitFinanceError
from qiskit_finance.data_providers import *
import datetime
import matplotlib.pyplot as plt
from pandas.plotting import register_matplotlib_converters

register_matplotlib_converters()
[2]:
data = RandomDataProvider(
    tickers=["TICKER1", "TICKER2"],
    start=datetime.datetime(2016, 1, 1),
    end=datetime.datetime(2016, 1, 30),
    seed=1,
)
data.run()

Una vez que los datos son cargados, puedes ejecutar una variedad de algoritmos en ellos para agregar los datos. En particular, puedes calcular la matriz de covarianza o una variante, lo que consideraría medidas de similitud de series de tiempo alternativas basadas en la deformación dinámica del tiempo (dynamic time warping, DTW). En DTW, se pueden acomodar cambios que varían en velocidad, por ejemplo, el precio de una acción siguiendo el precio de otra acción con un pequeño retraso.

[3]:
means = data.get_mean_vector()
print("Means:")
print(means)

rho = data.get_similarity_matrix()
print("A time-series similarity measure:")
print(rho)
plt.imshow(rho)
plt.show()

cov = data.get_covariance_matrix()
print("A covariance matrix:")
print(cov)
plt.imshow(cov)
plt.show()
Means:
[33.97683271 97.61130683]
A time-series similarity measure:
[[1.00000000e+00 5.41888011e-04]
 [5.41888011e-04 1.00000000e+00]]
../_images/tutorials_11_time_series_5_1.png
A covariance matrix:
[[2.08413157 0.20842107]
 [0.20842107 1.99542187]]
../_images/tutorials_11_time_series_5_3.png

Si lo deseas, puedes consultar las series de tiempo pseudoaleatorias subyacentes utilizando lo siguiente. Ten en cuenta que los miembros de la clase privada (que comienzan con un guión bajo) pueden cambiar en futuras versiones de Qiskit.

[4]:
print("The underlying evolution of stock prices:")
for (cnt, s) in enumerate(data._tickers):
    plt.plot(data._data[cnt], label=s)
plt.legend()
plt.xticks(rotation=90)
plt.show()

for (cnt, s) in enumerate(data._tickers):
    print(s)
    print(data._data[cnt])
The underlying evolution of stock prices:
../_images/tutorials_11_time_series_7_1.png
TICKER1
[33.345584192064784, 34.167202335565946, 34.49763941174933, 33.19448218014497, 34.099838046818086, 34.5462126191821, 34.009259383821814, 34.59037748801817, 34.95494988420424, 35.24908238085977, 35.27750462217556, 35.82421760878801, 35.08776352178634, 34.92485357379329, 34.442734261113316, 35.04158047374794, 35.0813025812296, 34.78884583026451, 34.00693736790767, 33.7497451272888, 33.757887307807145, 33.48228440250777, 34.77634821690598, 35.783072532211776, 33.07191005324581, 31.182896807278134, 31.008124715222973, 30.585934303646617, 30.799577301145227]
TICKER2
[96.8774156647853, 98.99525441983634, 97.88323365714406, 97.50562865001707, 99.5484002575094, 100.19510325371124, 100.85816662608751, 100.34416025440004, 98.69608508354439, 98.86354982776713, 98.97256391558868, 97.7452118613441, 97.06198519956354, 96.98994151983632, 96.04518989677554, 95.94691992892332, 96.04240295639278, 96.07798919344826, 95.57169753513395, 96.16544560691977, 97.0566125612021, 97.37746086576867, 96.55923063837835, 97.29088292216379, 96.78944290369674, 97.66860352198472, 96.59681610510728, 97.51128330823606, 97.49121985362058]

Claramente, puedes adaptar el número y los nombres de los tickers, y el rango de fechas:

[5]:
data = RandomDataProvider(
    tickers=["CompanyA", "CompanyB", "CompanyC"],
    start=datetime.datetime(2015, 1, 1),
    end=datetime.datetime(2016, 1, 30),
    seed=1,
)
data.run()
for (cnt, s) in enumerate(data._tickers):
    plt.plot(data._data[cnt], label=s)
plt.legend()
plt.xticks(rotation=90)
plt.show()
../_images/tutorials_11_time_series_9_0.png

Acceso a series de tiempo de precios de cierre#

Si bien el acceso a los datos en tiempo real generalmente requiere un pago, es posible acceder a los precios de cierre históricos (ajustados) a través de Wikipedia y Nasdaq Data Link de forma gratuita, luego de registrarse en: https://data.nasdaq.com/sign-up En el código a continuación, es necesario especificar los tickers concretos de los activos reales de NASDAQ y el token de acceso que obtienes de Nasdaq Data Link; al ejecutar el código de abajo, estás aceptando los términos y condiciones de Nasdaq Data Link, incluida una exención de responsabilidad. Ten en cuenta que se requieren al menos dos tickers para el cálculo de las matrices de covarianza y de series de tiempo, pero cientos de tickers pueden ir más allá de los límites de uso justo de Nasdaq Data Link.

[6]:
stocks = ["GOOG", "AAPL"]

token = "REPLACE-ME"
if token != "REPLACE-ME":
    try:
        wiki = WikipediaDataProvider(
            token=token,
            tickers=stocks,
            start=datetime.datetime(2016, 1, 1),
            end=datetime.datetime(2016, 1, 30),
        )
        wiki.run()
    except QiskitFinanceError as ex:
        print(ex)
        print("Error retrieving data.")

Una vez cargados los datos, puedes volver a calcular la matriz de covarianza o sus variantes de DTW.

[7]:
if token != "REPLACE-ME":
    if wiki._data:
        if wiki._n <= 1:
            print(
                "Not enough wiki data to plot covariance or time-series similarity. Please use at least two tickers."
            )
        else:
            rho = wiki.get_similarity_matrix()
            print("A time-series similarity measure:")
            print(rho)
            plt.imshow(rho)
            plt.show()

            cov = wiki.get_covariance_matrix()
            print("A covariance matrix:")
            print(cov)
            plt.imshow(cov)
            plt.show()
    else:
        print("No wiki data loaded.")

Si lo deseas, puedes ver la serie de tiempo subyacente utilizando:

[8]:
if token != "REPLACE-ME":
    if wiki._data:
        print("The underlying evolution of stock prices:")
        for (cnt, s) in enumerate(stocks):
            plt.plot(wiki._data[cnt], label=s)
        plt.legend()
        plt.xticks(rotation=90)
        plt.show()

        for (cnt, s) in enumerate(stocks):
            print(s)
            print(wiki._data[cnt])
    else:
        print("No wiki data loaded.")

[Opcional] Configurar un token para acceder a series temporales recientes y detalladas#

Si deseas descargar datos profesionales, deberás configurar un token con uno de los principales proveedores. Ilustremos ahora los datos con NASDAQ Data on Demand, que puede proporcionar precios de oferta y demanda a una resolución arbitraria, así como agregados, como precios de cierre ajustados diariamente, para activos de NASDAQ y de NYSE.

Si no tienes una licencia de NASDAQ Data on Demand, puedes ponerte en contacto con NASDAQ (cf. https://business.nasdaq.com/intel/GIS/Nasdaq-Data-on-Demand.html) para obtener una licencia de prueba o de pago.

Si tienes y cuando tengas acceso a NASDAQ Data on Demand utilizando tu propio token, debes reemplazar más abajo REPLACE-ME con el token. Para garantizar la seguridad de la conexión, también debes tener tus propios medios para validar los certificados de NASDAQ. El constructor DataOnDemandProvider tiene un argumento opcional verify, que puede ser None o una cadena o un valor booleano. Si es None, se utilizarán certificados de confirmación (predeterminado). Si la verificación es una cadena, deberías apuntar a un certificado para la conexión HTTPS a NASDAQ (dataondemand.nasdaq.com), ya sea en forma de archivo CA_BUNDLE o de un directorio donde buscar.

[9]:
token = "REPLACE-ME"
if token != "REPLACE-ME":
    try:
        nasdaq = DataOnDemandProvider(
            token=token,
            tickers=["GOOG", "AAPL"],
            start=datetime.datetime(2016, 1, 1),
            end=datetime.datetime(2016, 1, 2),
        )
        nasdaq.run()
        for (cnt, s) in enumerate(nasdaq._tickers):
            plt.plot(nasdaq._data[cnt], label=s)
        plt.legend()
        plt.xticks(rotation=90)
        plt.show()
    except QiskitFinanceError as ex:
        print(ex)
        print("Error retrieving data.")

Otro proveedor principal de datos de mercado de valores es Exchange Data International (EDI), cuya API puede ser usada para consultar más de 100 mercados emergentes y fronterizos que son África, Asia, Extremo Oriente, América Latina y Medio Oriente, así como los mercados más establecidos. Consulta: https://www.exchange-data.com/ para un resumen de la cobertura.

El acceso nuevamente requiere un token de acceso válido que se debe reemplazar más abajo en REPLACE-ME. El token se puede obtener como una versión de prueba o de pago en: https://data.nasdaq.com/sign-up

[10]:
token = "REPLACE-ME"
if token != "REPLACE-ME":
    try:
        lse = ExchangeDataProvider(
            token=token,
            tickers=["AEO", "ABBY", "ADIG", "ABF", "AEP", "AAL", "AGK", "AFN", "AAS", "AEFS"],
            stockmarket=StockMarket.LONDON,
            start=datetime.datetime(2018, 1, 1),
            end=datetime.datetime(2018, 12, 31),
        )
        lse.run()
        for (cnt, s) in enumerate(lse._tickers):
            plt.plot(lse._data[cnt], label=s)
        plt.legend()
        plt.xticks(rotation=90)
        plt.show()
    except QiskitFinanceError as ex:
        print(ex)
        print("Error retrieving data.")

También se puede acceder a los datos de Yahoo Finance, sin necesidad de token, desde Yahoo! Finance.

[11]:
try:
    data = YahooDataProvider(
        tickers=["MSFT", "AAPL", "GOOG"],
        start=datetime.datetime(2021, 1, 1),
        end=datetime.datetime(2021, 12, 31),
    )
    data.run()
    for (cnt, s) in enumerate(data._tickers):
        plt.plot(data._data[cnt], label=s)
    plt.legend(loc="upper center", bbox_to_anchor=(0.5, 1.1), ncol=3)
    plt.xticks(rotation=90)
    plt.show()
except QiskitFinanceError as ex:
    data = None
    print(ex)
../_images/tutorials_11_time_series_22_0.png

Para conocer el uso real de los datos, consulta los cuadernos portfolio_optimization o portfolio_diversification.

[12]:
import qiskit.tools.jupyter

%qiskit_version_table
%qiskit_copyright

Version Information

Qiskit SoftwareVersion
qiskit-terra0.23.1
qiskit-aer0.11.2
qiskit-ibmq-provider0.20.0
qiskit0.41.0
qiskit-finance0.4.0
qiskit-optimization0.5.0
qiskit-machine-learning0.5.0
System information
Python version3.9.10
Python compilerClang 13.1.6 (clang-1316.0.21.2.5)
Python buildmain, Aug 9 2022 18:26:17
OSDarwin
CPUs10
Memory (Gb)64.0
Thu Feb 16 15:52:54 2023 JST

This code is a part of Qiskit

© Copyright IBM 2017, 2023.

This code is licensed under the Apache License, Version 2.0. You may
obtain a copy of this license in the LICENSE.txt file in the root directory
of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.

Any modifications or derivative works of this code must retain this
copyright notice, and modified files need to carry a notice indicating
that they have been altered from the originals.

[ ]: