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`) / 3Ordenamento - 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` * -1Apó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"