Muito grato pelos meus rápidos 2 anos no BDMG, pelos meus colegas estagiários e chefia.
Para este exercício, sinto-me na obrigação de agradecer especialmente ao Vinicio Stort, que foi quem compartilhou o modelo pela primeira vez.
Como se costuma dizer: eventuais erros remanescentes são todos minha culpa.
Considerando uma moeda em que se tem 50% de chance de cair cara e 50% de chance de cair coroa (uma moeda justa), sabemos que o provável é que em múltiplos lançamentos metade dos resultados sejam cara, metade coroa.
Embora isso seja esperado (doravante, lembre que a palavra esperado(a) estará relacionado a ideia de média e resultado típico)1, podemos estar interessados em saber outros resultados possíveis. Podemos querer saber o quão frequente ocorrem resultados com mais caras ou com menos caras. Isto é, podemos querer saber os valores mais extremos, mais distantes da média.
Com efeito, é possível estimar facilmente o valor esperado quando as probabilidades de ocorrência dos eventos são conhecidas. Abaixo, o exemplo Loteria DIM DIM FÁCIL mostra isto.
Seus prêmios e as respectivas probabilidades de ocorrência destes são conforme descrito na tabela:
Valor Prêmio | Probabilidade de Ocorrência |
---|---|
5 | 0.90 |
1000 | 0.09 |
10000 | 0.01 |
O ganho esperado será a multiplicação linha a linha do Valor Prêmio * Probabilidade de Ocorrência:
5 x 0,9 = 4,5
1000 x 0,09 = 90
10000 x 0,01 = 100
Somando, temos o valor total esperado:
4,5 + 90 + 100 = 194,5
O ganho esperado dessa loteria é 194,5. Ou seja, para ela ser lucrativa, com certeza iria te cobrar além de R$200 para que pudesse jogar.2
Mas e os outros resultados possíveis? É neste ponto em que entra a Simulação de Monte Carlo.
A Simulação de Monte Carlo3 é, em termos informais, uma forma de testar os múltiplos resultados possíveis que podem ocorrer em um processo incerto, utilizando a geração de números aleatórios para modelar diferentes cenários e estimar probabilidades, expectativas e distribuições de variáveis de interesse.
Neste exércicio, a simulação será uma tentativa de calcular as perdas por inadimplência de uma carteira de crédito. Cada linha corresponde a um cliente que deve um saldo (deve uma parte do seu empréstimo) e tem seu risco de inadimplência que foi calculado previamente, a chamada probabilidade de default (pd). O evento que pode ou não ocorrer é, portanto, o cliente pagar ou não um empréstimo contraído. De antemão podemos calcular a perda esperada, tal como fizemos para a Loteria DIM DIM FÁCIL.
Porém, como analista de risco de crédito de um banco posso estar interessado, por exemplo, nos piores cenários que podem ocorrer ou no que vai acontecer se eu emprestar mais dinheiro a clientes com maior probabilidade de default.
Os parâmetros de entrada serão criados artificialmente, conforme poderá ser visto no primeiro chunk (pedaço de código).
O chunk (pedaço de código) a seguir define os parâmetros da simulação. O objeto df_saldo_clientes é uma tabela simulada correspondente à carteira de crédito.
Maiores explicações estão nos comentários com #.
Funções com r na frente, tais como rbeta() e runif(), geram números aleatórios.
# Definir uma semente gera os mesmos números aleatórios. Isso garante
# a reprodutibilidade do código.
set.seed(123)
# Número de clientes que serão criados.
n_clientes <- 10^3
# Dataframe com os clientes, saldo devedor e probabilidade de default.
df_saldo_clientes <- data.frame(
cnpj = 1:length(n_clientes), # Simulando que cada número de 1 até o número de clientes é o CNPJ do cliente.
saldo = runif(n_clientes, 1000, 10000), # Saldo entre 1.000 e 10.000
pd = rbeta(n_clientes, 2, 20) # PDs mais realistas (maioria abaixo de 10%)
)
# Número de simulações de Monte Carlo, portanto,
# número em que a simulação de perdas, dada as probalidades, será repetida
# para que seja encontrada as múltiplas possibilidades de perda, desde as
# mais otimistas, até o valor esperado (média), até as mais pessimistas.
n_simulacoes <- 10^5
# Criando função de simulação que será iterada. ITERAÇÃO = REPETIÇÃO
simular <- function() {
# Gera números aleatórios em quantidade igual ao número de linhas
numeros_aleatorios <- runif(n_clientes)
# Simulando um default acontecendo ou não. Essa parte costuma gerar dúvida.
# Onde o número aleatório é menor que que pd de um cliente, é a simulação de evento com probabilidade igual a pd ocorrendo. Se o número gerado é menor que a pd do cliente, então o default ocorre e aí o saldo do cliente é multiplicado por 1 e soma ao total de perdas da simulação.
vetor_default <- numeros_aleatorios < df_saldo_clientes$pd
# Soma do total de defaults que ocorreram na iteração.
sum(df_saldo_clientes$saldo * vetor_default)
}
O chunk a seguir é a execução da simulação. O uso da função dentro de replicate() é importante para que o código seja mais rápido. A linguagem R tem alguns modos de se fazer código que não raramente são mais rápidos que um for(). Naturalmente, isso é mais importante para um maior número de computações. Neste caso aqui apresentado, já pode apresentar diferença de tempo de computação relevante.
# Rodando a simulação de forma vetorizada (sem loop)
perdas_simuladas <- replicate(n_simulacoes, simular())
É interessante verificar se a perda esperada simulada é bastante semelhante à perda esperada calculada apenas com os dados iniciais. Deve ser, pois a média da simulação deve convergir à media da distribuição original.
Ademais, os resultados podem ser expressos em termos percentuais: total de inadimplência dividido pelo saldo total. Por exemplo, tem-se R$100 mil emprestados a várias pessoas. R$10 mil não são pagos, então a taxa de inadimplência é 10%.
A seguir, no chunk, são apresentados o valor esperado inicial (baseado na distribuição original sem simulação), o valor esperado simulado, etc. Conferir os comentários.
# Saldo inicial
cat(saldo_inicial <- sum(df_saldo_clientes$saldo))
5475500
# Perda Esperada calculada pelo risco.
cat(perda_esperada_risco <- sum(df_saldo_clientes$saldo * df_saldo_clientes$pd))
519119
# Taxa de Inadimplência Esperada utilizando os dados inciais
cat(round(perda_esperada_risco*100/saldo_inicial,2), "%", sep = "")
9.48%
# Perda Esperada, Valor Esperado.
# Este valor é o centro da distribuição. Indica o mais provável de acontecer.
# Deve ser muito semelhante à Perda Esperada calculada inicialmente.
cat(perda_esperada_simulacao <- mean(perdas_simuladas))
518909
# De fato os valores são muito semelhantes, conforme o esperado.
cat(perda_esperada_simulacao - perda_esperada_risco)
-210.0377
# Média
cat(mean(perdas_simuladas))
518909
# Mediana
cat(median(perdas_simuladas))
518034.6
O histograma abaixo é uma representação gráfica da distribuição das perdas estimadas com a Simulação de Monte Carlo.
A distribuição gerada na simulação permite ver ocorrências muito favoráveis, as mais à esquerda, em que, apesar de haver probabilidade de não pagamento, poucos clientes foram de fato inadimplentes.
O mais provável são os valores ao centro, isto é, no centro ou nas adjacências dele. Conforme o gráfico, esses valores ocorreram em maior frequência.
E, por fim, à direita, temos valores também menos prováveis em que a inadimplência é muito alta. Apesar de serem também menos prováveis, tal como os do lado esquerdo são, esses valores são muito relevantes pois indicam os piores cenários que poderiam ocorrer, eventualmente, catastróficos para quem emprestou o dinheiro.
Os resultados são apresentados como valor total no histograma superior, e como taxa de inadimplência no histograma inferior. As linhas verticais indicam respectivamente os percentis 50% (mediana), 95%, 97,5%, 99% e 100% (valor máximo de inadimplência encontrado na simulação).
Além do histograma, outros indicadores podem auxiliar na tomada de decisão.
O Value at Risk (VaR) representa um limite superior para as perdas esperadas dentro de um determinado nível de confiança. Ele é análogo à ideia de um intervalo de confiança, permitindo que decisões sejam tomadas com base em uma estimativa de risco. No entanto, considerar apenas o pior dos cenários pode ser excessivamente conservador e levar a políticas de risco restritivas, que podem comprometer a competitividade da instituição financeira e, em última instância, afetar sua rentabilidade.
A análise do histograma permite visualizar que as perdas extremas são raras, mas podem ser severas. Em particular, a diferença entre o percentil 99% e o evento de perda máxima (100%) pode ser significativa, evidenciando uma cauda longa nos extremos da distribuição.
Um VaR de 95% indica o nível de perda que não foi ultrapassado em 95% das simulações, ou seja, considerando a simulação, há apenas 5% de probabilidade de uma perda mais severa ocorrer.
Para avaliar melhor os riscos extremos, utiliza-se o Expected Shortfall (ES) ou Conditional Value at Risk (CVaR). Essa métrica calcula a média das perdas que excedem o limite estipulado pelo VaR. Por exemplo, considerando um VaR de 95%, o CVaR representa a média das perdas que ocorreram nos 5% piores cenários simulados.
A seguir, os resultados dos VaRs para os percentis 97,5%, 99% e 100%, e o CVaR a 95%.
# 95% Value at Risk (VaR)
VaR_95 <- quantile(perdas_simuladas, c(0.95, 0.975, 0.99, 1)) # múltiplos Value at Risk (VaR)
CVaR_95 <- mean(perdas_simuladas[perdas_simuladas >= VaR_95[1]]) # CVaR ou Expected Shortfall
# Mostrando novamente a perda esperada simulada
cat(paste("Perda Esperada:", round(perda_esperada_simulacao, 2)))
Perda Esperada: 518909.01
# Mostrando os Values at Risk
cat(paste(c("Value at Risk (95%):","Value at Risk (97,5%):","Value at Risk (99%):", "Value at Risk (100%):" ), round(VaR_95, 2)), sep ="\n")
Value at Risk (95%): 611186.55
Value at Risk (97,5%): 628891.39
Value at Risk (99%): 650501.81
Value at Risk (100%): 797152.86
# CVaR a 95%
cat(paste("Expected Shortfall (95% CVaR):", round(CVaR_95, 2)))
Expected Shortfall (95% CVaR): 635563.67
# A prática função R base summary() para dar uma última olhada nos quantis.
(summary(perdas_simuladas))
Min. 1st Qu. Median Mean 3rd Qu. Max.
309033 481269 518035 518909 555424 797153
Os resultados obtidos ajudam a estimar a exposição ao risco e fornecem uma base para estratégias de crédito mais equilibradas.
Nem sempre a média representa os resultados mais prováveis. Considere, por exemplo, três salários: 1.500, 1.500 e 50.000. A média é quase 18.000, um valor que não reflete bem a distribuição, pois uma pessoa ganha 50.000 enquanto as outras duas recebem apenas 1.500.
No entanto, no exercício da carteira de crédito e em outras distribuições com menos assimetria, a média pode ser uma boa referência para descrever o comportamento geral dos dados e o resultado típico.↩︎
Por R$194,50, considerando inexistir qualquer outro custo além do prêmio, o lucro da empresa lotérica é nulo.↩︎
Origem da Simulação de Monte Carlo segundo o ChatGPT (em pesquisas anteriores na internet encontrei resultados semelhantes):
O termo “Simulação de Monte Carlo” tem origem no período da Segunda Guerra Mundial, quando foi usado por cientistas trabalhando no Projeto Manhattan, que desenvolveu a bomba atômica.
Foi o matemático Stanislaw Ulam, junto com John von Neumann e Nicholas Metropolis, que formalizou o método enquanto estudava problemas de difusão de nêutrons em materiais fissíveis. Ulam percebeu que, ao invés de resolver equações complexas diretamente, poderia estimar soluções gerando números aleatórios e observando a frequência de diferentes resultados.
O nome “Monte Carlo” foi sugerido por Nicholas Metropolis em referência ao famoso cassino de Monte Carlo, em Mônaco, onde jogos de azar dependem de números aleatórios – uma analogia direta ao método estatístico usado na simulação.↩︎