Dados

Bloomberg

Para importar os dados que serão utilizados, cole a seguinte Query na célula A1 de um Excel com o Add-in da Bloomberg habilitado:

let(#ret12Meses= product(1+dropna(day_to_day_total_return(dates=range(start=-12m,end=0d)))); #ret9Meses= product(1+dropna(day_to_day_total_return(dates=range(start=-9m,end=0d)))); #ret6Meses= product(1+dropna(day_to_day_total_return(dates=range(start=-6m,end=0d)))); #vol252Dias=sqrt(252)*std(day_to_day_total_return(dates=range(start=-252d,end=0d))); #carryFCFYield=free_cash_flow_yield(fill=PREV); #qualityLBAT= gross_profit(fill=PREV) / bs_tot_asset(fill=PREV); #valueEVEbitda=ev_to_ebitda(fill=PREV) ; #valuePtB= px_to_book_ratio(fill=PREV);) get(#ret12Meses,#ret9Meses, #ret6Meses, #vol252Dias, #carryFCFYield, #qualityLBAT, #valueEVEbitda, #valuePtB) for(members(‘IBX Index’))

Em seguida, na célula A2, cole a seguinte Query:

=BQL.Query(A1)

Esse procedimento em duas etapas deve gerar os dados mais recentes para cada ativo e estatística.

Import

Primeiro, importamos os dados.

dados <- read_excel("RankMarcoRaw.xlsx", skip = 1, col_names = FALSE)

Estrutura dos dados

Estatísticas dos dados

##     Ativos          #carryFCFYield       #qualityLBAT       #ret12Meses      
##  Length:97          Min.   :-141.6144   Min.   :0.005369   Min.   :-0.75126  
##  Class :character   1st Qu.:  -0.3665   1st Qu.:0.105016   1st Qu.:-0.23833  
##  Mode  :character   Median :   4.8152   Median :0.171043   Median :-0.01803  
##                     Mean   :   7.1137   Mean   :0.188467   Mean   :-0.01232  
##                     3rd Qu.:  13.0926   3rd Qu.:0.265136   3rd Qu.: 0.14571  
##                     Max.   :  92.1799   Max.   :0.487710   Max.   : 0.99525  
##                                         NA's   :18                           
##    #ret6Meses         #ret9Meses       #valueEVEbitda     #valuePtB     
##  Min.   :-0.70217   Min.   :-0.70801   Min.   : 1.604   Min.   : 0.334  
##  1st Qu.:-0.24926   1st Qu.:-0.35464   1st Qu.: 4.981   1st Qu.: 1.062  
##  Median :-0.10630   Median :-0.15937   Median : 7.717   Median : 1.901  
##  Mean   :-0.11277   Mean   :-0.17079   Mean   :11.463   Mean   : 2.505  
##  3rd Qu.: 0.04162   3rd Qu.:-0.01702   3rd Qu.:12.850   3rd Qu.: 2.776  
##  Max.   : 0.46923   Max.   : 0.60289   Max.   :59.574   Max.   :11.775  
##                                        NA's   :15       NA's   :6       
##   #vol252Dias    
##  Min.   :0.1588  
##  1st Qu.:0.3104  
##  Median :0.3827  
##  Mean   :0.4112  
##  3rd Qu.:0.4964  
##  Max.   :0.9526  
## 

Correlação entre as Variáveis

Manuseio dos Dados

Nomalização

Como trabalhamos com diferentes estatísticas que possuem distribuições bastante distintas, normalizamos os dados antes de prosseguir com a análise.

dados[,-1] <- apply(dados[,-1], 2, function(x) (x - mean(x, na.rm = TRUE)) / sd(x, na.rm = TRUE))

Média dos Retornos Acumulados

Em seguida, calculamos a média dos três retornos acumulados (12, 9 e 6 meses). Essa nova estatística que será utilizada para ordenação.

dados$ret_medio <- (dados$`#ret12Meses` + dados$`#ret9Meses` + dados$`#ret6Meses`) / 3

Ordenamento - Single Factor

  • Free Cash Flow Yield - Buy High & Sell Low
  • Lucro Bruto / Ativo Total - Buy High & Sell Low
  • Retorno Acumulado - Buy High & Sell Low
  • Price to Book - Buy Low & Sell High
  • Volatilidade - Buy Low & Sell High
  • EV / Ebitda - Buy Low & Sell High

Como temos indicadores que devem ser ordenados de forma diferente - Buy High (Low) & Sell Low (High) -, temos que multiplicar por -1 aqueles indicadores que divergirem. Por isso, multiplicamos Volatiidade, EV/Ebitda e Price to Book por -1.

dados$`#valueEVEbitda` <- dados$`#valueEVEbitda` * -1
dados$`#vol252Dias` <- dados$`#vol252Dias` * -1
dados$`#valuePtB` <- dados$`#valuePtB` * -1

Após os passos demonstrados, somos capazes de apresentar uma tabela com o valor de cada estatística para cada ativo. O leitor pode mudar a ordenação dessa tabela clicando duas vezes na seta que fica ao lado do nome da coluna.

Ordenamento - Multi Factor

Por fim, criamos uma nova tabela que é a média aritmética de cada uma das colunas para cada ativo. O leitor mais atento pode perceber que temos dois indicadores para Value. Por isso, faremos duas tabelas.

Além disso, muitos ativos não possuem todas as features disponíveis (basta olhar a tabela acima). Por esse motivo, adicionaremos uma coluna informando quais dados são faltantes. Indo além, apresentaremos mais duas tabelas, na seção “Apêndice”, em que substituimos esses valores nulos pela média dos valores não nulos antes de calcularmos a média de cada uma das colunas para cada ativo.

EV / Ebitda

dados_ev <- dados %>% select(!`#valuePtB`)
dados_ev <- apply(dados_ev, 1, function(x) mean(x, na.rm = TRUE))

Price to Book

Agora, utilizamos Price to Book como nossa estística para definir o fator valor.

dados_PtB <- dados %>% select(!`#valueEVEbitda`)
dados_PtB <- apply(dados_PtB, 1, function(x) mean(x, na.rm = TRUE))

Comparação Ordenamento Price to Book e EV / Ebitda

Por fim, comparamos a o portfólio de value construído com base em PtB e EV/Ebitda. Para isso, apresentamos qual o a posição de cada empresa no ranqueamento por cada indicador e, também, qual o número de ativos em comum no primeiro tercil de cada indicador.

rankPtB <- data.frame(rankPtB = rank(-dados_PtB$Estat), row.names = rownames(dados_PtB))

rankEV <- data.frame(rankEV = rank(-dados_ev$Estat), row.names = rownames(dados_ev))

df_rank <- merge(rankPtB, rankEV, by = 0)
rownames(df_rank) <- df_rank$Row.names
df_rank <- df_rank[,-1]

Agora, analisamos a composição do portfólio com base em cada uma das estatísticas. Primeiro, vemos quais ativos estão no portfólio construído com base no EV/Ebitida e não estão naquele construído com base no PtB. Em seguida, fazemos o contrário. Por fim, vemos quais ativos estão em ambos os portfólios.

setdiff(rownames(dados_ev[1:30, , drop = FALSE]), rownames(dados_PtB[1:30, , drop = FALSE]))
## [1] "BEEF3 BS Equity" "RADL3 BS Equity" "EGIE3 BS Equity" "BBSE3 BS Equity"
setdiff(rownames(dados_PtB[1:30, , drop = FALSE]), rownames(dados_ev[1:30, , drop = FALSE]))
## [1] "PSSA3 BS Equity" "BRML3 BS Equity" "EQTL3 BS Equity" "HYPE3 BS Equity"
intersect(rownames(dados_PtB[1:30, , drop = FALSE]), rownames(dados_ev[1:30, , drop = FALSE]))
##  [1] "SANB11 BS Equity" "GOAU4 BS Equity"  "ITUB4 BS Equity"  "PETR3 BS Equity" 
##  [5] "BRAP4 BS Equity"  "PETR4 BS Equity"  "MRFG3 BS Equity"  "JBSS3 BS Equity" 
##  [9] "VALE3 BS Equity"  "BBAS3 BS Equity"  "VIVT3 BS Equity"  "GGBR4 BS Equity" 
## [13] "TAEE11 BS Equity" "TIMS3 BS Equity"  "CMIN3 BS Equity"  "ENBR3 BS Equity" 
## [17] "CPLE6 BS Equity"  "BRKM5 BS Equity"  "PCAR3 BS Equity"  "CMIG4 BS Equity" 
## [21] "SBSP3 BS Equity"  "CPFE3 BS Equity"  "ABEV3 BS Equity"  "CRFB3 BS Equity" 
## [25] "CSNA3 BS Equity"  "USIM5 BS Equity"

Apêndice

EV / Ebitda (NA = 0)

A tabela que será gerada é idêntica àquela gerada anteriormente com uma diferença: nesse caso sustituímos os valores faltantes (NAs) pela média daquela coluna (no caso 0, dado que normalizamos os dados).

dados_ev[is.na(dados_ev)] <- 0
dados_ev <- apply(dados_ev, 1, mean)

Price to Book (NA = 0)

Agora, utilizamos Price to Book como nossa estística para definir o fator valor.

dados_PtB <- dados %>% select(!`#valueEVEbitda`)

A tabela que será gerada é idêntica àquela gerada anteriormente com uma diferença: nesse caso sustituímos os valores faltantes (NAs) pela média daquela coluna (no caso 0, dado que normalizamos os dados).

dados_PtB[is.na(dados_PtB)] <- 0
dados_PtB <- apply(dados_PtB, 1, mean)

Comparação Ordenamento Price to Book e EV / Ebitda (NA = 0)

Por fim, comparamos a o portfólio de value construído com base em PtB e EV/Ebitda. Para isso, apresentamos qual o a posição de cada empresa no ranqueamento por cada indicador e, também, qual o número de ativos em comum no primeiro tercil de cada indicador.

rankPtB <- data.frame(rankPtB = rank(-dados_PtB$Estat), row.names = rownames(dados_PtB))

rankEV <- data.frame(rankEV = rank(-dados_ev$Estat), row.names = rownames(dados_ev))

df_rank <- merge(rankPtB, rankEV, by = 0)
rownames(df_rank) <- df_rank$Row.names
df_rank <- df_rank[,-1]

Agora, analisamos a composição do portfólio com base em cada uma das estatísticas. Primeiro, vemos quais ativos estão no portfólio construído com base no EV/Ebitida e não estão naquele construído com base no PtB. Em seguida, fazemos o contrário. Por fim, vemos quais ativos estão em ambos os portfólios.

setdiff(rownames(dados_ev[1:30, , drop = FALSE]), rownames(dados_PtB[1:30, , drop = FALSE]))
## [1] "BEEF3 BS Equity" "RADL3 BS Equity" "EGIE3 BS Equity" "BBSE3 BS Equity"
setdiff(rownames(dados_PtB[1:30, , drop = FALSE]), rownames(dados_ev[1:30, , drop = FALSE]))
## [1] "PSSA3 BS Equity" "EQTL3 BS Equity" "HYPE3 BS Equity" "BRML3 BS Equity"
intersect(rownames(dados_PtB[1:30, , drop = FALSE]), rownames(dados_ev[1:30, , drop = FALSE]))
##  [1] "GOAU4 BS Equity"  "PETR3 BS Equity"  "PETR4 BS Equity"  "MRFG3 BS Equity" 
##  [5] "ITUB4 BS Equity"  "BRAP4 BS Equity"  "SANB11 BS Equity" "JBSS3 BS Equity" 
##  [9] "VALE3 BS Equity"  "VIVT3 BS Equity"  "GGBR4 BS Equity"  "TAEE11 BS Equity"
## [13] "TIMS3 BS Equity"  "CMIN3 BS Equity"  "ENBR3 BS Equity"  "CPLE6 BS Equity" 
## [17] "BBAS3 BS Equity"  "BRKM5 BS Equity"  "PCAR3 BS Equity"  "CMIG4 BS Equity" 
## [21] "SBSP3 BS Equity"  "CPFE3 BS Equity"  "ABEV3 BS Equity"  "CRFB3 BS Equity" 
## [25] "CSNA3 BS Equity"  "USIM5 BS Equity"