rb3

Wilson Freitas

Agenda

  • Missão
  • Um pouco de história
  • O que o 📦 {rb3} tem?
  • Aplicações

Missão




Prover acesso estruturado a todo conteúdo útil disponível no site da B3.

Um pouco de história

  • O {rb3} nasceu como {rbmfbovespa} com o objetivo de ler os arquivos disponíveis no site da Bolsa.
  • Esse pacote nunca foi para o CRAN.
  • Em abril/2022, Perlin me procurou pra colocar uma função para fazer download da curva de juros da Bolsa (então B3) no pacote {fixedincome}.
  • Nasce {rb3} como continuação do {rbmfbovespa} com o Perlin integrando o projeto.
  • Em 2023 o projeto foi aceito no rOpenSci

O que o 📦 {rb3} tem?

  • Curvas de juros: juros nominais (prefixados), juros reais, cupom cambial
  • Preços de ajuste de contratos futuros: DI1, DOL, IND, DAP, …
  • Cotações diárias não ajustadas: ações, BDRs, ETFs, FIIs, FIAGROs, …
  • Prêmio de opções de ações
  • Séries históricas de índices: IBOV, IBXL, IBXX, SMLL, …
  • Composição e pesos de ações nos índices
  • Segmentos das ações
  • Eventos corporativos de empresas: dividendos, subscrição, grupamento, desdobramento, …
  • Cache

Curvas de juros

  • Histórico começa em 2018
  • yc_get()
  • yc_ipca_get()
  • yc_usd_get()
  • yc_mget()
  • yc_ipca_mget()
  • yc_usd_mget()

Curva de juros nominais (prefixados)

library(rb3)

df_yc <- yc_mget(
  first_date = Sys.Date() - 255 * 5,
  last_date = Sys.Date(),
  by = 255
)

df_yc
# A tibble: 1,105 × 6
   refdate    cur_days biz_days forward_date  r_252  r_360
   <date>        <int>    <dbl> <date>        <dbl>  <dbl>
 1 2020-03-19        1        1 2020-03-20   0.0365 0     
 2 2020-03-19        4        2 2020-03-23   0.0365 0.0259
 3 2020-03-19        7        5 2020-03-26   0.0365 0.0372
 4 2020-03-19       11        7 2020-03-30   0.0365 0.0331
 5 2020-03-19       12        8 2020-03-31   0.0365 0.0347
 6 2020-03-19       13        9 2020-04-01   0.0365 0.036 
 7 2020-03-19       14       10 2020-04-02   0.0365 0.0372
 8 2020-03-19       21       15 2020-04-09   0.0365 0.0372
 9 2020-03-19       27       18 2020-04-15   0.0365 0.0347
10 2020-03-19       32       21 2020-04-20   0.0365 0.0342
# ℹ 1,095 more rows

Curvas de juros nominais (prefixados)

Code
library(tidyverse)

ggplot(
  df_yc,
  aes(x = forward_date, y = r_252, group = refdate, color = factor(refdate))
) +
  geom_line(linewidth = 1) +
  labs(
    title = "Yield Curves for Brazil",
    subtitle = "Built using interest rates future contracts",
    caption = str_glue("Data imported using rb3 at {Sys.Date()}"),
    x = "Forward Date",
    y = "Annual Interest Rate",
    color = "Reference Date"
  ) +
  theme_light() +
  scale_y_continuous(labels = scales::percent)

Curva de juros reais (cupom de IPCA)

Code
df_ipca_yc <- yc_ipca_mget(
  first_date = Sys.Date() - 255 * 5,
  last_date = Sys.Date(),
  by = 255
)

ggplot(
  df_ipca_yc,
  aes(x = forward_date, y = r_252, group = refdate, color = factor(refdate))
) +
  geom_line(linewidth = 1) +
  labs(
    title = "DIxIPCA Yield Curves for Brazil",
    subtitle = "Built using interest rates future contracts",
    caption = str_glue("Data imported using rb3 at {Sys.Date()}"),
    x = "Forward Date",
    y = "Annual Interest Rate",
    color = "Reference Date"
  ) +
  theme_light() + 
  scale_y_continuous(labels = scales::percent)

Inflação Implícita

pre_factor <- df_yc |>
  mutate(factor_pre = (1 + r_252) ^ (biz_days/252)) |>
  select(refdate, forward_date, biz_days, factor_pre)

ipca_factor <- df_ipca_yc |>
  mutate(factor_ipca = (1 + r_252) ^ (biz_days/252)) |>
  select(refdate, forward_date, biz_days, factor_ipca)

inflation <- pre_factor |>
  left_join(ipca_factor,
            by = c("refdate", "forward_date", "biz_days")) |>
  mutate(
    inflation = (factor_pre / factor_ipca) ^ (252 / biz_days) - 1
  )

Inflação Implícita

Code
ggplot(
  inflation |> filter(forward_date < as.Date("2034-01-01")),
  aes(
    x = forward_date,
    y = inflation,
    group = refdate,
    color = factor(refdate)
  )
) +
  geom_line(linewidth = 1) +
  labs(
    title = "Implied Inflation for Brazil",
    subtitle = "Built using interest rates future contracts",
    caption = str_glue("Data imported using rb3 at {Sys.Date()}"),
    x = "Forward Date",
    y = "Annual Interest Rate",
    color = "Reference Date"
  ) +
  theme_light() +
  scale_y_continuous(labels = scales::percent)

Contratos Futuros

  • Histórico começa em 1990
  • futures_get()
  • futures_mget()

Contratos Futuros de DI1

  • A curva de juros nominais é construída a partir dos contratos futuros de DI1
fut <- futures_get("2023-09-01")
fut |> filter(commodity == "DI1") |> head(15)
# A tibble: 15 × 8
   refdate    commodity maturity_code symbol price_previous   price change
   <date>     <chr>     <chr>         <chr>           <dbl>   <dbl>  <dbl>
 1 2023-09-01 DI1       U23           DI1U23        100000  100000    0   
 2 2023-09-01 DI1       V23           DI1V23         99037.  99037.  -0.23
 3 2023-09-01 DI1       X23           DI1X23         98059.  98059.   0.26
 4 2023-09-01 DI1       Z23           DI1Z23         97173.  97172.  -1.28
 5 2023-09-01 DI1       F24           DI1F24         96317.  96317.  -0.63
 6 2023-09-01 DI1       G24           DI1G24         95406.  95404.  -2.48
 7 2023-09-01 DI1       H24           DI1H24         94661.  94651.  -9.11
 8 2023-09-01 DI1       J24           DI1J24         93893.  93884.  -9.53
 9 2023-09-01 DI1       K24           DI1K24         93087.  93068. -19.0 
10 2023-09-01 DI1       M24           DI1M24         92351.  92328. -23.2 
11 2023-09-01 DI1       N24           DI1N24         91677.  91649. -28.8 
12 2023-09-01 DI1       Q24           DI1Q24         90918.  90885. -33.2 
13 2023-09-01 DI1       U24           DI1U24         90171.  90165.  -6.36
14 2023-09-01 DI1       V24           DI1V24         89549.  89501. -48.2 
15 2023-09-01 DI1       F25           DI1F25         87548.  87484. -63.9 
# ℹ 1 more variable: settlement_value <dbl>

Contratos Futuros de DI1 + Curva de juros prefixado

  • Como identificar os contratos de DI1 na curva de juros prefixados?
Super dataset
yc <- yc_get("2023-09-01")
fut <- futures_get("2023-09-01")
df <- yc_superset(yc, fut)
df |> head(10)
# A tibble: 10 × 7
   refdate    cur_days biz_days forward_date r_252 r_360 symbol
   <date>        <int>    <dbl> <date>       <dbl> <dbl> <chr> 
 1 2023-09-01        3        1 2023-09-04   0.132 0     <NA>  
 2 2023-09-01        7        4 2023-09-08   0.130 0.105 <NA>  
 3 2023-09-01       12        7 2023-09-13   0.130 0.107 <NA>  
 4 2023-09-01       14        9 2023-09-15   0.130 0.119 <NA>  
 5 2023-09-01       20       13 2023-09-21   0.130 0.12  <NA>  
 6 2023-09-01       21       14 2023-09-22   0.130 0.123 <NA>  
 7 2023-09-01       27       18 2023-09-28   0.130 0.123 <NA>  
 8 2023-09-01       28       19 2023-09-29   0.130 0.126 <NA>  
 9 2023-09-01       31       20 2023-10-02   0.130 0.119 DI1V23
10 2023-09-01       33       22 2023-10-04   0.129 0.123 <NA>  

Construindo a curva de juros prefixados

Com o pacote {fixedincome} podemos construir a curva de juros prefixados a partir dos contratos futuros de DI1.

df_curve <- bind_rows(
  df |> filter(biz_days == 1) |> select(biz_days, r_252),
  df |> filter(!is.na(symbol)) |> select(biz_days, r_252)
)


library(fixedincome)

curve <- spotratecurve(
  df_curve$r_252, df_curve$biz_days, "discrete", "business/252", "Brazil/ANBIMA",
  refdate = as.Date("2023-09-01")
)

Curva de juros prefixados

ggspotratecurveplot(curve)

Cache do 📦 {rb3}

  • O sistema de cache do {rb3} armazena todos os arquivos baixados e processados em um diretório (opção rb3.cachedir)
options(rb3.cachedir = file.path("C:\\Users\\wilso\\R", "rb3-cache"))
  • O cache pode ser utilizado como um banco de dados rudimentar.
  • Todas as funções possuem os argumentos:
    • cache_folder = cachedir()
    • do_cache = TRUE

Histórico de juros prefixados de longo prazo

dc <- yc_mget(
    first_date = "2019-01-01",
    last_date = "2023-09-01",
    cache_folder = "rb3-data"
)


unique(dc$refdate) |> map(function(date, df) {
    df_curve <- df |>
        filter(refdate == date, biz_days > 0) |>
        filter(!duplicated(biz_days))
    curve <- spotratecurve(
        df_curve$r_252,
        df_curve$biz_days,
        "discrete", "business/252", "Brazil/ANBIMA",
        refdate = date
    )
    interpolation(curve) <- interp_flatforward()
    curve
}, df = dc) -> curves

Histórico de juros prefixados de longo prazo

curves |>
    map_dfr(\(x) tibble(
        refdate = x@refdate,
        r_BRL_10y = as.numeric(x[[2520]])
    )) -> rates_10y

Índices da B3

  • Diversas funções que retoram dados relacionados aos índides divulgados pela B3.
  • indexes_get(): Lista os índices disponíveis
  • index_get(): Séries históricas dos índices
  • index_comp_get(): Composição dos índices
  • index_weights_get(): Pesos dos ativos que compõem os índices

Composição de índices da B3

index_weights_get("IBOV")
# A tibble: 92 × 3
   symbol  weight   position
   <chr>    <dbl>      <dbl>
 1 ABEV3  0.0316  4380195841
 2 ALPA4  0.00196  201257220
 3 AMER3  0.00711  596875824
 4 ASAI3  0.00603  794531367
 5 AZUL4  0.00357  327741172
 6 B3SA3  0.0395  5987625321
 7 BBAS3  0.0234  1420530937
 8 BBDC3  0.0112  1516726535
 9 BBDC4  0.0461  5160570290
10 BBSE3  0.00848  671629692
# ℹ 82 more rows

Composição de índices da B3

index_weights_get("IBOV") |>
    top_weight(10) |>
    ggdonut("IBOV")

Composição de índices da B3

index_weights_get("IBXX") |>
    top_weight(10) |>
    ggdonut("IBXX")

Composição de índices da B3

index_weights_get("IBXL") |>
    top_weight(10) |>
    ggdonut("IBXL")

Composição de índices da B3

index_weights_get("SMLL") |>
    top_weight(10) |>
    ggdonut("SMLL")

Dados de ações - Arquivo COTAHIST

  • Função cotahist_get() para obter dados do arquivo COTAHIST
  • Arquivos: diário, mensal e anual
  • Histórico desde 1990 para arquivos anuais
  • cotahist_get_symbols()
  • cotahist_equity_get()
  • cotahist_etfs_get()
  • cotahist_indexes_get()
  • cotahist_equity_options_get()
  • cotahist_index_options_get()
  • cotahist_funds_options_get()
  • cotahist_bdrs_get()
  • cotahist_units_get()
  • cotahist_fiis_get()
  • cotahist_fidcs_get()
  • cotahist_fiagros_get()

Série histórica de ETFs

ch <- cotahist_get(as.Date("2023-01-01"), "yearly")

cotahist_etfs_get(ch) |>
  filter(symbol == "BOVA11") |>
  ggplot(aes(x = refdate, y = close)) +
  geom_line()

Opções de ações

ch <- cotahist_get(as.Date("2023-09-01"), "daily")
yc <- yc_get(as.Date("2023-09-01"))


op1 <- cotahist_options_by_symbol_superset("PETR4", ch, yc)
# A tibble: 380 × 28
   refdate    symbol  type  strike maturity_date  open  high   low close average
   <date>     <chr>   <fct>  <dbl> <date>        <dbl> <dbl> <dbl> <dbl>   <dbl>
 1 2023-09-01 PETRI4… Call   14.7  2023-09-15    17.8  17.8  17.8  17.8    17.8 
 2 2023-09-01 PETRI2… Call    0.34 2023-09-15    32    32    32    32      32   
 3 2023-09-01 PETRL1  Call   12.8  2023-12-15    20    20    20    20      20   
 4 2023-09-01 PETRL5… Call   27.8  2023-12-15     6     6     5.8   5.8     5.8 
 5 2023-09-01 PETRL5… Call   28.8  2023-12-15     4.9   5.2   4.9   5.18    5.18
 6 2023-09-01 PETRL5… Call   29.8  2023-12-15     4.3   4.5   4.26  4.5     4.33
 7 2023-09-01 PETRX1  Put    12.8  2023-12-15     0.01  0.01  0.01  0.01    0.01
 8 2023-09-01 PETRX2… Put     3.79 2023-12-15     0.01  0.01  0.01  0.01    0.01
 9 2023-09-01 PETRX4… Put    23.8  2023-12-15     0.2   0.2   0.2   0.2     0.2 
10 2023-09-01 PETRX4… Put    25.8  2023-12-15     0.29  0.29  0.29  0.29    0.29
# ℹ 370 more rows
# ℹ 18 more variables: volume <dbl>, traded_contracts <dbl>,
#   transactions_quantity <int>, distribution_id <int>,
#   symbol.underlying <chr>, open.underlying <dbl>, high.underlying <dbl>,
#   low.underlying <dbl>, close.underlying <dbl>, average.underlying <dbl>,
#   best_bid <dbl>, best_ask <dbl>, volume.underlying <dbl>,
#   traded_contracts.underlying <dbl>, …

Opções de ações

library(bizdays)
library(oplib)

maturities <- unique(op1$maturity_date) |> sort()
close_underlying <- op1$close.underlying[1]

op_vol <- op1 |>
  filter(maturity_date %in% maturities[1:2]) |>
  mutate(
    biz_days = bizdays(
      refdate, following(maturity_date, "Brazil/ANBIMA"), "Brazil/ANBIMA"
    ),
    time_to_maturity = biz_days / 252,
    rate = log(1 + r_252),
    impvol = bsmimpvol(
      close, type, close.underlying, strike, time_to_maturity, rate, 0
    ),
    delta = bsmdelta(
      type, close.underlying, strike, time_to_maturity, rate, 0, impvol
    )
  ) |>
  select(
    symbol, volume,
    type, close.underlying, strike, time_to_maturity, rate, impvol,
    delta, biz_days, volume
  )

Opções de ações

op_vol
# A tibble: 334 × 10
   symbol   volume type  close.underlying strike time_to_maturity  rate impvol  delta biz_days
   <chr>     <dbl> <fct>            <dbl>  <dbl>            <dbl> <dbl>  <dbl>  <dbl>    <dbl>
 1 PETRI400   5331 Call              32.6  14.7            0.0357 0.122  NA    NA            9
 2 PETRI200   6400 Call              32.6   0.34           0.0357 0.122  NA    NA            9
 3 PETRJ237 699536 Call              32.6  14.8            0.131  0.121  NA    NA           33
 4 PETRI281 275641 Call              32.6  22.4            0.0357 0.122   1.03  0.979        9
 5 PETRJ245  15235 Call              32.6  18.8            0.131  0.121  NA    NA           33
 6 PETRJ250 305844 Call              32.6  19.3            0.131  0.121  NA    NA           33
 7 PETRJ260  31770 Call              32.6  20.3            0.131  0.121  NA    NA           33
 8 PETRJ265  50406 Call              32.6  20.8            0.131  0.121  NA    NA           33
 9 PETRJ240 129715 Call              32.6  18.3            0.131  0.121  NA    NA           33
10 PETRI254   1282 Call              32.6  19.7            0.0357 0.122  NA    NA            9
# ℹ 324 more rows

Volatilidade implícita

Dinâmica da Volatilidade implícita



ch <- cotahist_get(as.Date("2023-01-01"), "yearly")
yc <- yc_mget(first_date = as.Date("2023-01-01"),
              last_date = as.Date("2023-09-01"))
op <- cotahist_options_by_symbol_superset("PETR4", ch, yc)

Dinâmica da Volatilidade implícita

op_vol <- op |>
  mutate(
    biz_days = bizdays(
      refdate, following(maturity_date, "Brazil/B3"), "Brazil/B3"
    ),
    time_to_maturity = biz_days / 252,
    rate = log(1 + r_252),
    bsm_impvol = bsmimpvol(
      close, type, close.underlying, strike, time_to_maturity, rate, 0
    ),
    delta = bsmdelta(
      type, close.underlying, strike, time_to_maturity, rate, 0, bsm_impvol
    )
  ) |>
  select(
    refdate, symbol, volume, maturity_date,
    type, close.underlying, strike, time_to_maturity, rate,
    biz_days, close, high, low, bsm_impvol, delta
  )

Dinâmica da Volatilidade implícita

op1 <- op_vol |>
  split(op_vol$refdate) |>
  map_dfr(function(df) {
    first_mat <- df$maturity_date[which.min(df$maturity_date)]
    filter(df, maturity_date == first_mat)
  })


op1_atm <- split(op1, op1$refdate) |>
  map_dfr(function(df) {
    df_type <- filter(df, type == "Put")
    df1 <- df_type[which.min(abs(abs(df_type$delta) - 0.5)), ]

    df_type <- filter(df, type == "Call")
    df2 <- df_type[which.min(abs(abs(df_type$delta) - 0.5)), ]

    bind_rows(df1, df2)
  })

Dinâmica da Volatilidade implícita