Dentre as diversas alternativas de investimentos em renda fixa temos os instrumentos pós-fixados, que em teoria são mais seguros por serem menos impactados pelo risco de mercado (que provem das oscilações das expectativas das taxas de juros). Uma jabuticaba de nosso mercado são os títulos pós-fixados em percentual de CDI. Como o CDI é o indexador mais comum utilizado nas emissões de dívida, uma alternativa seria realizar a emissão pagando o CDI mais uma taxa (spread), nesse modelo temos uma taxa pós-fixada (indexador) e uma pré-fixada (spread), fica uma coisa meio híbrida. O título indexado a um percentual do CDI traz a característica de ser totalmente pós-fixado, de forma que se o nível da taxa aumenta, o título paga mais juros e quando diminui o paga menos. O mesmo não acontece com o título que paga um spread aditivo, que possui uma fração pré-fixada na composição da taxa.

Pois bem, um título que paga percentual de CDI tem o seu valor nominal \(N\) corrigido pela seguinte fórmula:

\[ N \prod_{t=1}^n (1 + p\cdot((1 + CDI_t)^{1/252}-1)) \]

onde \(p\) é o percentual sobre o CDI pago. Note que o CDI é convertido de uma taxa anual para uma taxa diária e o percentual é aplicado sobre essa taxa diária. O ponto aqui é: Como fazer a avaliação do valor nominal \(N\) no vencimento do contrato? O CDI atual é conhecido, mas não podemos assumir que este será o valor vigente durante todo o período do título. A maneira correta de fazermos essa avaliação é extraír da estrutura a termos de juros as taxas a termo diárias e utilizar estas taxas na fórmula acima.

Para fazer isso vamos começar importando os pacotes e configurando o calendário padrão em bizdays.

library(glue)
library(xml2)
library(stringr)
library(bizdays)
library(tidyverse)
library(tidyr)

bizdays.options$set(default.calendar="Brazil/ANBIMA")

A função get_curve baixa as curvas de taxas referenciais da B3.

get_curve <- function (refdate, ticker="PRE") {
  refdate <- as.Date(refdate)
  url <- "http://www2.bmf.com.br/pages/portal/bmfbovespa/lumis/lum-taxas-referenciais-bmf-ptBR.asp"
  url <- glue("{url}?Data={format(refdate, '%d/%m/%Y')}&Data1={format(refdate, '%Y%m%d')}&slcTaxa={ticker}")
  doc <- read_html(url)
  tbl <- xml_find_all(doc, "//table[contains(@id, 'tb_principal1')]")
  num <- xml_find_all(tbl[[1]], "td") %>%
    xml_text() %>%
    str_trim() %>%
    str_replace(",", ".") %>%
    as.numeric()

  dc <- num[c(TRUE, FALSE, FALSE)]
  tx_252 <- num[c(FALSE, TRUE, FALSE)]

  terms <- bizdayse(refdate, dc)
  ix <- (terms %% 21) == 0
  terms <- c(terms[1], terms[ix])
  rates <- c(tx_252[1], tx_252[ix])/100
  log_pu <- log((1 + rates)^(terms/252))
  rate <- function(pu, term) pu^(252/term) - 1

  log_price_interpolator <- approxfun(terms, log_pu, method="linear")
  function (term) {
    pu <- exp(log_price_interpolator(term))
    rate(pu, term)*100
  }
}

As taxas retornadas são as taxas à vista relacionadas aos prazos, precisamos converter para as taxas a termo. Para isso vamos aplicar a relação de não arbitragem de taxas de juros.

\[ (1 + r_{2})^{T_{2}} = (1 + r_{1})^{T_{1}} \cdot (1 + r_{12})^{T_2 - T_1} \]

Pela função get_curve vamos obter as taxas à vista para todos os dias, em seguida vamos aplicar a relação acima para calcular as taxas a termo diárias para os 252 dias úteis seguintes a nossa data de referência.

pre <- get_curve("2020-11-11")
terms_ <- seq(1, 252, 1)
curve_ <- pre(terms_)
fwd_curve_ <- numeric(length(terms_))

fwd_curve_[1] <- curve_[1]
for (t_ in terms_[-1]) {
  f_short <- (1 + curve_[t_-1]/100)^((t_-1)/252)
  f_long <- (1 + curve_[t_]/100)^(t_/252)
  fwd_curve_[t_] <- ((f_long/f_short)^(252) - 1) * 100
}

O vetor fwd_curve_ tem as taxas a termo diárias para os 252 dias úteis. Este vetor representa a variável \(CDI_t\) da fórmula acima do valor nominal futuro. Dessa forma, podemos aplicar diretamente o percentual da fórmula sobre as taxas neste vetor. Temos que a taxa à vista para 252 dias é de 3.2121207. Para um valor nominal de R$ 1.000,00 essa taxa produz um valor futuro de

1000 * (1 + curve_[length(curve_)]/100)
## [1] 1032.121

Assumindo um percentual de 105% temos, para o mesmo valor nominal

1000 * prod(1 + ((1 + fwd_curve_/100) ^ (1/252) - 1) * 1.05)
## [1] 1033.754

Em termos de taxa nominal temos

(prod(1 + ((1 + fwd_curve_/100) ^ (1/252) - 1) * 1.05) - 1)
## [1] 0.03375396

Podemos até fazer um gráfico da razão entre a taxa com percentual e a taxa nominal pelo percentual

tx_perc <- function(p, curve) {
  (prod(1 + ((1 + curve/100) ^ (1/252) - 1) * p) - 1) * 100
}

tibble(
  Percentual = seq(1, 2, 0.01),
  Taxas = sapply(Percentual, tx_perc, curve = fwd_curve_) / curve_[length(curve_)]
) %>%
  ggplot(aes(x = Percentual, y = Taxas)) +
  geom_point()

Note que apesar do gráfico apresentar uma reta, pelo menos visualmente, podemos ver que 200% da taxa a termo não produz o dobro da taxa à vista, isso acontece porque as taxas na estrutura a termo estão crescendo e dessa maneira, nos primeiros dias de acumulo de taxa temos uma taxa menor do que a dos últimos dias. Esse é o comportamento esperado, portanto, sempre que for comparar um investimento pré-fixado com outro pré-fixado, é importante considerar o prazo no investimento e levar em consideração o formato da estrutura a termo, pois com esse formato crescente é importante avaliar bem o percentual pago.