Curso de Python Para Trading - Parte 1 : Datos de Mercado con OpenBB

Curso de Python Para Trading - Parte 1 : Datos de Mercado con OpenBB

Table of contents

Que es OpenBB

OpenBB es una plataforma open-source donde han integrado mas de 100 diferentes fuentes de datos, de todo tipo de asset clases, desde acciones, opciones, criptoactivos,forex, datos macroeconomicos y mucho mas. Dando opciones de acceso desde una App estilo Bloomberg, una consola CLI estilo old bloomberg,y dejando una puerta abierta a los programadores de python mediante su paquete openbb.

Historicamente acceder a datos financieros era un reto considerable, donde era caro, inaccesible y requeria demasiado tiempo. Desde OpenBB simplifican todo este proceso, centralizando en un unico punto, todas las fuentes de datos. Utilizando una unica libreria para obtener todos nuestros datos en tiempo real.

Instalacion de las librerias necesarias

Utilizando el stack dockerizado que hemos creado

GitHub - quantarmyz/quantstack: QUANTARMY quantstack | One-click quantitative envoirment based in docker, debian, conda, jupyterlabs,zipline-reloaded and arcticdb
QUANTARMY quantstack | One-click quantitative envoirment based in docker, debian, conda, jupyterlabs,zipline-reloaded and arcticdb - quantarmyz/quantstack

cargamos el entorno que utilizamos desde un terminal, y ejecutamos el siguiente comando, que lo que hara, sera instalar el gateway en python que nos interconectara con openBB, pudiendo trabajar con toda la potencia de openBB desde python, de una forma extremadamente sencilla

!pip install openbb[all]

Primer Uso de OpenBB

Una vez descargada la libreria, al cargar por primera vez la libreria en python, descargara y instalara unos paquetes adicionales en segundo plano.

from openbb import obb
obb.user.preferences.output_type = 'dataframe'

Una vez finalizado, se recomienda volver a cargar el kernel, y la libreria estara totalmente funcional.

Obteniendo datos Acciones

Comparando Datos Fundamentales

obb.equity.fundamental.metrics("AAPL,MSFT").T
0 1
symbol AAPL MSFT
market_cap 3414690000000.0 3109760000000.0
pe_ratio 34.2 35.45
foward_pe 30.26 27.23
eps 6.57 11.8
price_to_sales 8.86 12.69
price_to_book 51.25 11.58
book_value_per_share 4.38 36.11
price_to_cash 55.25 41.17
cash_per_share 4.06 10.16
price_to_free_cash_flow 32.73 41.98
debt_to_equity 1.52 0.36
long_term_debt_to_equity 1.29 0.31
quick_ratio 0.91 1.27
current_ratio 0.95 1.27
gross_margin 0.4596 0.6976
profit_margin 0.2644 0.3596
operating_margin 0.3127 0.4464
return_on_assets 0.3059 0.1907
return_on_investment 0.6668 0.2508
return_on_equity 1.6058 0.3713
payout_ratio 0.1532 0.2542

Datos de Precio

data = obb.equity.price.historical("SPY")

Si deseamos cambiar el timeframe, lo hacemos mediante el parametro interval

  • 1m = One Minute
  • 1h = One Hour
  • 1d = One Day
  • 1W = One Week
  • 1M = One Month

En este caso, lo dejamos por defecto, en timeframe diario.

open high low close volume
date
2004-01-02 111.74 112.19 110.73 111.23 38072300
2004-01-05 111.69 112.52 111.59 112.44 27959800
2004-01-06 112.16 112.73 112.00 112.55 20472800
2004-01-07 112.39 113.06 111.89 112.93 30170400
2004-01-08 113.25 113.41 112.77 113.38 36438400
... ... ... ... ... ...
2024-09-25 571.19 571.89 568.91 570.04 37682308
2024-09-26 574.49 574.71 569.90 572.30 44788926
2024-09-27 573.42 574.22 570.42 571.47 41082707
2024-09-30 570.50 574.38 568.08 573.76 59333099
2024-10-01 573.41 574.06 566.00 568.62 70827736

5227 rows × 5 columns

Comparando Sectores de forma fundamental

obb.equity.compare.groups(group="industry",metric="valuation").T
0 1 2 3 4 5 6 7 8 9 ... 135 136 137 138 139 140 141 142 143 144
name Pharmaceutical Retailers Insurance - Reinsurance REIT - Mortgage Coking Coal Airlines Marine Shipping Financial Conglomerates Insurance - Life Paper & Paper Products Thermal Coal ... Biotechnology REIT - Industrial REIT - Specialty Uranium REIT - Residential REIT - Office REIT - Healthcare Facilities Shell Companies Real Estate - Diversified Infrastructure Operations
market_cap 7980000000 50930000000 58520000000 10270000000 126700000000 40150000000 35370000000 300640000000 17030000000 11610000000 ... 1302310000000 301390000000 425450000000 33400000000 201730000000 76590000000 163750000000 27320000000 7570000000 34940000000
performance_1D 0.0232 0.0024 -0.001 0.005 -0.0179 0.0052 -0.0036 0.0117 0.0077 0.0107 ... -0.0119 -0.0122 -0.0031 0.0214 -0.0066 -0.0011 -0.0055 -0.0018 0.0002 -0.0111
forward_pe 5.1 7.2 7.45 7.71 8.08 8.43 9.04 9.07 9.41 9.49 ... 35.87 39.97 41.55 47.82 49.76 56.3 66.47 138.44 147.61 151.85
eps_growth_past_5_years -0.0482 0.5531 -0.2214 0.0583 -0.0431 0.2148 0.0292 -0.0107 0.7162 0.1513 ... 0.0123 0.0735 0.1308 0.1901 0.1472 -0.2137 -0.1288 NaN 0.1838 NaN
eps_growth_next_5_years 0.0569 0.0746 0.0313 0.0626 0.1492 0.0992 0.1386 0.0891 0.0839 -0.0487 ... 0.1187 0.0181 0.1124 NaN 0.0175 0.0068 0.3635 NaN 0.1975 0.1425
sales_growth_past_5_years 0.0371 0.2218 0.3533 0.1565 0.2438 0.2487 -0.0061 0.0554 0.1615 0.1014 ... 2.8221 0.192 1.1581 2.5959 0.0841 0.0651 0.1157 0.6025 0.2097 0.0814
volume 3530000 115690 6380000 155130 11860000 3030000 286490 1810000 211010 326830 ... 89480000 1480000 2089999 9190000 1720000 1920000 3610000 1020000 27680 95120
price_to_sales 0.05 0.95 1.84 0.97 0.47 1.33 1.22 1.14 0.99 1.16 ... 10.21 12.22 7.39 13.47 8.28 3.93 7.08 26.2 4.81 3.34
price_to_book 0.57 1.31 0.88 1.67 2.16 1.14 1.19 1.66 1.84 1.42 ... 5.37 2.73 6.48 4.31 2.66 1.11 2.11 2.39 1.93 7.74
price_to_cash 9.77 NaN 4.17 7.11 2.3 6.33 3.38 3292.14 3.83 9.08 ... 6.7 127.49 42.58 22.22 56.66 8.74 30.35 40.93 7.39 8.61
price_to_free_cash_flow 419.39 2.85 6.73 9.71 28.04 9.46 3.74 4.88 25.63 6.79 ... 48.67 25.91 44.93 98.93 23.16 13.92 28.53 109.4 72.23 33.73
pe NaN 7.01 24.3 8.37 12.11 6.31 11.01 13.83 49.52 7.37 ... 55.96 41.22 46.15 88.93 44.87 88.88 112.84 58.46 95.48 38.81
peg NaN 0.94 7.77 1.34 0.81 0.64 0.79 1.55 5.9 NaN ... 4.72 22.75 4.11 NaN 25.58 130.73 3.1 NaN 4.83 2.72

14 rows × 145 columns

Derivados Datos de una curva de Futuros

data = obb.derivatives.futures.curve(symbol="VX")
expiration price
0 2024-10 20.50
1 2024-11 19.35
2 2024-12 18.90
3 2025-01 19.30
4 2025-02 19.50
5 2025-03 19.60
6 2025-04 19.65
7 2025-05 19.75
8 2025-06 19.85

Plotear la curva

import pandas as pd
data.index = pd.to_datetime(data.expiration)
data.plot()

Descargar y plotear diferentes contratos

expirations = [
    "2024-12",
    "2025-12",
    "2026-12",
    "2027-12",
    "2028-12",
    "2029-12",
    "2030-12",
]
contracts = []
for expiration in expirations:
    df = (
        obb
        .derivatives
        .futures
        .historical(
            symbol="CL",
            expiration=expiration,
            start_date="2020-01-01",
            end_date="2022-12-31"
        )
    ).rename(columns={
        "close": expiration
            })
    contracts.append(df[expiration])
historical = (
    pd
    .DataFrame(contracts)
    .transpose()
    .dropna()
)
historical.plot()

Obteniendo una cadena de opciones

Respecto a la cadena de opciones, las trataremos de forma separada en un proximo articulo, todas las posilibidades que proporciona OpenBB. Pero de momento, par snapear la cadena actual de un ticker en concreto, se realizaria de la siguiente forma

chains = obb.derivatives.options.chains(symbol="SPY")
underlying_symbol underlying_price contract_symbol expiration dte strike option_type open_interest volume theoretical_price ... low prev_close change change_percent implied_volatility delta gamma theta vega rho
0 SPY 568.1201 SPY241002C00300000 2024-10-02 0 300.0 call 5 12 268.1850 ... 268.16 269.485001 -0.725 -0.00269 0.0000 1.0000 0.0000 -0.0024 0.0000 0.0000
1 SPY 568.1201 SPY241002P00300000 2024-10-02 0 300.0 put 10 0 0.0001 ... 0.00 0.005000 0.000 0.00000 7.0620 0.0000 0.0000 -0.0001 0.0000 0.0000
2 SPY 568.1201 SPY241002C00310000 2024-10-02 0 310.0 call 0 0 258.1850 ... 0.00 259.535004 0.000 0.00000 0.0000 1.0000 0.0000 -0.0024 0.0000 0.0000
3 SPY 568.1201 SPY241002P00310000 2024-10-02 0 310.0 put 0 0 0.0002 ... 0.00 0.005000 0.000 0.00000 6.7156 0.0000 0.0000 -0.0002 0.0000 0.0000
4 SPY 568.1201 SPY241002C00320000 2024-10-02 0 320.0 call 0 0 248.1850 ... 0.00 249.514999 0.000 0.00000 0.0000 1.0000 0.0000 -0.0024 0.0000 0.0000
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
9863 SPY 568.1201 SPY270115P00890000 2027-01-15 835 890.0 put 0 0 321.8150 ... 0.00 320.589996 0.000 0.00000 0.2833 -1.0000 0.0000 -0.0640 0.0000 0.0000
9864 SPY 568.1201 SPY270115C00895000 2027-01-15 835 895.0 call 0 0 0.8942 ... 0.00 0.875000 0.000 0.00000 0.1243 0.0253 0.0006 -0.0034 0.5654 0.2984
9865 SPY 568.1201 SPY270115P00895000 2027-01-15 835 895.0 put 0 0 326.8150 ... 0.00 325.589996 0.000 0.00000 0.2861 -1.0000 0.0000 -0.0640 0.0000 0.0000
9866 SPY 568.1201 SPY270115C00900000 2027-01-15 835 900.0 call 225 0 0.8464 ... 0.00 0.925000 0.000 0.00000 0.1265 0.0240 0.0005 -0.0033 0.5430 0.2836
9867 SPY 568.1201 SPY270115P00900000 2027-01-15 835 900.0 put 0 0 331.8150 ... 0.00 330.589996 0.000 0.00000 0.2888 -1.0000 0.0000 -0.0640 0.0000 0.0000

9868 rows × 29 columns

Descargando una opcion especifica

Si dentro de la cadena, queremos bajar un contrato en especifico, debemos tratarlo como si estuvieramos descargando un ticker de una accion, pero el simbolo es el identificador de la opcion. De la siguiente forma

data = obb.equity.price.historical(
    symbol="SPY241220C00550000",
        provider="yfinance")
open high low close volume split_ratio dividend
date
2023-10-02 2.340000 2.340000 2.140000 2.140000 1004 0.0 0.0
2023-10-03 2.240000 2.240000 2.010000 2.030000 47 0.0 0.0
2023-10-04 2.050000 2.200000 2.050000 2.200000 4 0.0 0.0
2023-10-06 2.030000 2.600000 2.030000 2.600000 26 0.0 0.0
2023-10-09 2.500000 2.780000 2.500000 2.780000 19 0.0 0.0
... ... ... ... ... ... ... ...
2024-09-26 37.959999 37.980000 35.630001 36.500000 30 0.0 0.0
2024-09-27 36.790001 36.790001 35.880001 35.939999 32 0.0 0.0
2024-09-30 35.500000 37.480000 33.799999 37.480000 21 0.0 0.0
2024-10-01 35.619999 35.619999 33.090000 34.660000 62 0.0 0.0
2024-10-02 32.570000 32.570000 32.570000 32.570000 2 0.0 0.0

246 rows × 7 columns

Forex

obb.currency.price.historical("usdjpy", provider="yfinance").to_df()
open high low close volume
date
2023-08-22 146.238007 146.389999 145.501999 146.238007 0.0
2023-08-23 145.763000 145.813004 144.580002 145.763000 0.0
2023-08-24 144.673004 145.947006 144.621002 144.673004 0.0
2023-08-25 146.067001 146.604996 145.733994 146.067001 0.0
2023-08-28 146.531006 146.716003 146.278000 146.531006 0.0
... ... ... ... ... ...
2024-08-16 149.222000 149.229996 147.639008 149.222000 0.0
2024-08-19 147.955994 147.959000 145.220993 147.955994 0.0
2024-08-20 146.699005 147.319000 145.533997 146.699005 0.0
2024-08-21 145.347000 146.339005 144.981003 145.347000 0.0
2024-08-22 145.117996 146.524994 144.839996 146.287003 0.0

Validacion de Datos.

Como extra, vamos a comparar los datos de diferentes proveedores, para poder tener una aproximacion de la calidad de los datos que estamos gestionando. Los datos son los inputs del proceso, y una materia prima de baja calidad, generara modelos de baja calidad. Para esta prueba, vamos a verificar el volumen, sobre el ticker QQQ (Nasdaq Composite ETF).

Para validad que los datos de los diferentes proveedores son correctos, deberiamos obtener el mismo volumen para todos los proveedores.

Primero vamos a recolectar los datos necesarios.

yahoo = obb.equity.price.historical("QQQ", provider="yfinance").to_df()
alphavantage = obb.equity.price.historical("QQQ", provider="alpha_vantage").to_df()
intrinio = obb.equity.price.historical("QQQ", provider="intrinio").to_df()
fmp = obb.equity.price.historical("QQQ", provider="fmp").to_df()
polygon = obb.equity.price.historical("QQQ", provider="polygon").to_df()

Mediante el siguiente codigo, descargamos de diferentes proveedores el ticker QQQ en formato Pandas DataFrame.

Ahora procesamos los datos, creando un nuevo dataframe, con los ultimos 10 casos del volumen de los diferentes proveedores y eliminamos los valores NA

compare = pd.DataFrame()
compare["AV Volume"] = alphavantage["volume"].tail(10)
compare["FMP Volume"] = fmp["volume"].tail(10)
compare["Intrinio Volume"] = intrinio["volume"].tail(10)
compare["Yahoo Volume"] = yahoo["volume"].tail(10)
compare["Polygon Volume"] = polygon["volume"].tail(10)

compare.dropna(how="any")
AV Volume FMP Volume Intrinio Volume Yahoo Volume Polygon Volume
date
2024-08-09 45619558 45619558.0 45619558.0 45619600.0 45425963.0
2024-08-12 42542069 42542069.0 42542069.0 42542100.0 42533175.0
2024-08-13 52333073 52333073.0 52333073.0 52333100.0 50110167.0
2024-08-14 42446929 42446929.0 42446929.0 42446900.0 42362522.0
2024-08-15 60846812 60846812.0 60846812.0 60846800.0 60762738.0
2024-08-16 44430728 44430728.0 44430728.0 44430700.0 44368969.0
2024-08-19 39121793 39121793.0 39121793.0 39121800.0 38648958.0
2024-08-20 33732264 33732264.0 33732264.0 33732300.0 33693989.0
2024-08-21 41514600 38682509.0 41514600.0 41467000.0 41532360.0

Como conclusion, podemos ver que no siempre coincide, asi que cada uno debe ejecutar sus procedimientos oportunos para saber que precio es real, y que precio no.

Conclusiones

Estos articulos cortos, pretenden ir al foco del tema en cuestion de una forma concentrada. Mediante este articulo, puedes acceder y descargar series temporales de diferentes asset clases, para posteriormente gestionarlas en nuestra datalake, o de la forma independendiente necesaria.

Jesús Cuesta

Odesa (Ucrania)
Inversor desde 2014. Research desde 2017. He trabjado en diferentes gestoras de capital, y Hedgefunds Crypto. Apasasionado en el codigo, los datos y las finanzas. Acualmente localizado en Ucrania.