Simulação de Monte Carlo: Da Teoria à Prática em Excel

Tutorial completo sobre como implementar simulação de Monte Carlo para análise de cenários em suas projeções financeiras.

Tutorial Completo: Como Implementar Simulação de Monte Carlo para Análise de Cenários em suas Projeções Financeiras

Por Prof. Ronald Fonseca | Controladoria & Dados


📊 Introdução

Se você já se deparou com a pergunta “Qual a probabilidade de atingirmos nossa meta de faturamento no próximo trimestre?” ou “Quanto de capital precisamos reservar para cobrir 95% dos cenários possíveis?”, então você precisa conhecer a Simulação de Monte Carlo.

Esta poderosa técnica estatística, batizada em homenagem ao famoso cassino de Mônaco, permite que controllers e analistas financeiros avaliem milhares de cenários possíveis simultaneamente, transformando a incerteza em informação quantificável para tomada de decisão.

Neste tutorial completo, você aprenderá:

  • ✅ Os fundamentos teóricos da Simulação de Monte Carlo
  • ✅ Implementação prática em Python (com código pronto)
  • ✅ Como fazer no Excel sem programação
  • ✅ Casos reais de aplicação em controladoria
  • ✅ Interpretação e comunicação dos resultados

🎯 O que é Simulação de Monte Carlo?

A Simulação de Monte Carlo é um método computacional que utiliza amostragem aleatória repetida para obter resultados numéricos de problemas que envolvem incerteza. Em vez de calcular um único resultado determinístico, ela gera milhares (ou milhões) de cenários possíveis, cada um baseado em valores aleatórios das variáveis de entrada.

Por que usar Monte Carlo em Finanças?

Problema tradicional:

  • Projeção determinística: “Vamos crescer 15% no próximo ano”
  • Ignora a incerteza inerente ao negócio
  • Não fornece probabilidades de diferentes resultados

Solução com Monte Carlo:

  • “Temos 68% de chance de crescer entre 12% e 18%”
  • “Há 95% de probabilidade de nossa receita ficar entre R$ 5,2M e R$ 7,8M”
  • Quantifica o risco de não atingir metas

📐 Fundamentos Matemáticos (Simplificados)

O Processo em 4 Passos:

1. Identificar variáveis incertas

  • Exemplos: crescimento de vendas, taxa de inadimplência, variação cambial

2. Definir distribuições de probabilidade

  • Normal: para variáveis simétricas (ex: retornos de ações)
  • Lognormal: para variáveis sempre positivas (ex: preços)
  • Triangular: quando você tem mínimo, máximo e mais provável
  • Uniforme: quando todos os valores têm mesma probabilidade

3. Gerar amostras aleatórias

  • Simular milhares de valores para cada variável
  • Seguindo suas respectivas distribuições

4. Calcular resultados

  • Para cada simulação, calcular o resultado final
  • Analisar a distribuição dos resultados obtidos

Exemplo Conceitual Simples:

Imagine que você quer projetar o lucro líquido do próximo ano, que depende de:

  • Receita: pode variar entre R$ 8M e R$ 12M (mais provável: R$ 10M)
  • Margem Operacional: normalmente entre 18% e 25%
  • Taxa Efetiva de Impostos: fixada em 34%

A Monte Carlo vai:

  1. Sortear um valor de receita (ex: R$ 9,3M)
  2. Sortear uma margem (ex: 21,5%)
  3. Calcular: Lucro = 9.300.000 × 0,215 × (1 – 0,34) = R$ 1.319.100
  4. Repetir isso 10.000 vezes
  5. Mostrar que há 80% de chance do lucro ficar entre R$ 1,1M e R$ 1,6M

💻 Implementação em Python

Caso 1: Projeção de Fluxo de Caixa Livre

Vamos simular o FCF (Free Cash Flow) de uma empresa considerando incertezas em vendas, custos e CAPEX.

import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns

# Configuração visual
sns.set_style("whitegrid")
plt.rcParams['figure.figsize'] = (12, 6)

# ========================================
# PARÂMETROS DO MODELO
# ========================================

np.random.seed(42)  # Reprodutibilidade

# Número de simulações
n_simulacoes = 10000

# Receita (distribuição triangular)
receita_min = 8_000_000      # R$ 8 milhões
receita_provavel = 10_000_000  # R$ 10 milhões (cenário base)
receita_max = 13_000_000     # R$ 13 milhões

# Margem EBITDA (distribuição normal)
margem_ebitda_media = 0.22   # 22%
margem_ebitda_std = 0.03     # Desvio padrão de 3%

# CAPEX como % da receita (distribuição normal)
capex_percent_media = 0.08   # 8% da receita
capex_percent_std = 0.02     # Desvio de 2%

# Depreciação (% da receita - considerada determinística)
depreciacao_percent = 0.05   # 5%

# Variação de Capital de Giro (% da variação de receita)
nwc_percent = 0.15           # 15% do crescimento de receita

# Taxa de imposto
taxa_imposto = 0.34          # 34%

# Receita do ano anterior (para calcular variação)
receita_ano_anterior = 9_500_000

# ========================================
# SIMULAÇÃO DE MONTE CARLO
# ========================================

resultados_fcf = []

for i in range(n_simulacoes):
    # Sortear Receita (distribuição triangular)
    receita = np.random.triangular(receita_min, receita_provavel, receita_max)
    
    # Sortear Margem EBITDA (distribuição normal truncada entre 10% e 35%)
    margem = np.random.normal(margem_ebitda_media, margem_ebitda_std)
    margem = np.clip(margem, 0.10, 0.35)
    
    # Calcular EBITDA
    ebitda = receita * margem
    
    # Depreciação
    depreciacao = receita * depreciacao_percent
    
    # EBIT (Lucro Operacional)
    ebit = ebitda - depreciacao
    
    # Impostos
    impostos = ebit * taxa_imposto
    
    # NOPAT (Lucro Operacional após impostos)
    nopat = ebit - impostos
    
    # Sortear CAPEX
    capex_percent = np.random.normal(capex_percent_media, capex_percent_std)
    capex_percent = np.clip(capex_percent, 0.03, 0.15)
    capex = receita * capex_percent
    
    # Variação de Capital de Giro
    variacao_receita = receita - receita_ano_anterior
    variacao_nwc = variacao_receita * nwc_percent
    
    # FCF (Free Cash Flow)
    fcf = nopat + depreciacao - capex - variacao_nwc
    
    resultados_fcf.append(fcf)

# Converter para array numpy
resultados_fcf = np.array(resultados_fcf)

# ========================================
# ANÁLISE DOS RESULTADOS
# ========================================

print("=" * 60)
print("SIMULAÇÃO DE MONTE CARLO - FLUXO DE CAIXA LIVRE (FCF)")
print("=" * 60)
print(f"\nNúmero de simulações: {n_simulacoes:,}")
print(f"\n{'ESTATÍSTICAS DESCRITIVAS':^60}")
print("-" * 60)
print(f"FCF Médio:           R$ {np.mean(resultados_fcf):,.2f}")
print(f"FCF Mediano:         R$ {np.median(resultados_fcf):,.2f}")
print(f"Desvio Padrão:       R$ {np.std(resultados_fcf):,.2f}")
print(f"\nFCF Mínimo:          R$ {np.min(resultados_fcf):,.2f}")
print(f"FCF Máximo:          R$ {np.max(resultados_fcf):,.2f}")

# Percentis (Intervalos de Confiança)
print(f"\n{'INTERVALOS DE CONFIANÇA':^60}")
print("-" * 60)
p5 = np.percentile(resultados_fcf, 5)
p25 = np.percentile(resultados_fcf, 25)
p75 = np.percentile(resultados_fcf, 75)
p95 = np.percentile(resultados_fcf, 95)

print(f"5º Percentil (Pior cenário provável):  R$ {p5:,.2f}")
print(f"25º Percentil:                          R$ {p25:,.2f}")
print(f"75º Percentil:                          R$ {p75:,.2f}")
print(f"95º Percentil (Melhor cenário provável):R$ {p95:,.2f}")

# Probabilidades de cenários
fcf_positivo = np.sum(resultados_fcf > 0) / n_simulacoes * 100
fcf_acima_1M = np.sum(resultados_fcf > 1_000_000) / n_simulacoes * 100
fcf_acima_15M = np.sum(resultados_fcf > 1_500_000) / n_simulacoes * 100

print(f"\n{'PROBABILIDADES':^60}")
print("-" * 60)
print(f"Probabilidade de FCF positivo:          {fcf_positivo:.1f}%")
print(f"Probabilidade de FCF > R$ 1 milhão:     {fcf_acima_1M:.1f}%")
print(f"Probabilidade de FCF > R$ 1,5 milhões:  {fcf_acima_15M:.1f}%")

print("\n" + "=" * 60)

# ========================================
# VISUALIZAÇÕES
# ========================================

fig, axes = plt.subplots(2, 2, figsize=(14, 10))
fig.suptitle('Análise de Monte Carlo - Projeção de FCF', 
             fontsize=16, fontweight='bold')

# 1. Histograma
axes[0, 0].hist(resultados_fcf / 1_000_000, bins=50, 
                edgecolor='black', alpha=0.7, color='steelblue')
axes[0, 0].axvline(np.mean(resultados_fcf) / 1_000_000, 
                   color='red', linestyle='--', linewidth=2, label='Média')
axes[0, 0].axvline(np.median(resultados_fcf) / 1_000_000, 
                   color='orange', linestyle='--', linewidth=2, label='Mediana')
axes[0, 0].set_xlabel('FCF (R$ milhões)')
axes[0, 0].set_ylabel('Frequência')
axes[0, 0].set_title('Distribuição do Fluxo de Caixa Livre')
axes[0, 0].legend()
axes[0, 0].grid(True, alpha=0.3)

# 2. Box Plot
axes[0, 1].boxplot(resultados_fcf / 1_000_000, vert=True)
axes[0, 1].set_ylabel('FCF (R$ milhões)')
axes[0, 1].set_title('Box Plot - Dispersão dos Resultados')
axes[0, 1].grid(True, alpha=0.3)

# 3. Distribuição Acumulada (CDF)
sorted_fcf = np.sort(resultados_fcf) / 1_000_000
cumulative = np.arange(1, len(sorted_fcf) + 1) / len(sorted_fcf) * 100
axes[1, 0].plot(sorted_fcf, cumulative, linewidth=2, color='steelblue')
axes[1, 0].axhline(50, color='red', linestyle='--', alpha=0.5, label='Mediana (50%)')
axes[1, 0].axhline(95, color='orange', linestyle='--', alpha=0.5, label='95º Percentil')
axes[1, 0].set_xlabel('FCF (R$ milhões)')
axes[1, 0].set_ylabel('Probabilidade Acumulada (%)')
axes[1, 0].set_title('Curva de Distribuição Acumulada')
axes[1, 0].legend()
axes[1, 0].grid(True, alpha=0.3)

# 4. Cenários
cenarios = ['Pessimista\n(P5)', 'Conservador\n(P25)', 
            'Base\n(Mediana)', 'Otimista\n(P75)', 'Excelente\n(P95)']
valores_cenarios = [p5/1_000_000, p25/1_000_000, 
                    np.median(resultados_fcf)/1_000_000, 
                    p75/1_000_000, p95/1_000_000]
cores = ['#d32f2f', '#ff9800', '#2196f3', '#4caf50', '#8bc34a']

bars = axes[1, 1].bar(cenarios, valores_cenarios, color=cores, edgecolor='black', alpha=0.7)
axes[1, 1].set_ylabel('FCF (R$ milhões)')
axes[1, 1].set_title('Cenários de FCF')
axes[1, 1].grid(True, alpha=0.3, axis='y')

# Adicionar valores nas barras
for bar, valor in zip(bars, valores_cenarios):
    height = bar.get_height()
    axes[1, 1].text(bar.get_x() + bar.get_width()/2., height,
                    f'R$ {valor:.2f}M',
                    ha='center', va='bottom', fontweight='bold')

plt.tight_layout()
plt.savefig('monte_carlo_fcf_analise.png', dpi=300, bbox_inches='tight')
print("\n✅ Gráficos salvos como 'monte_carlo_fcf_analise.png'")

Saída Esperada:

============================================================
SIMULAÇÃO DE MONTE CARLO - FLUXO DE CAIXA LIVRE (FCF)
============================================================

Número de simulações: 10,000

              ESTATÍSTICAS DESCRITIVAS                      
------------------------------------------------------------
FCF Médio:           R$ 1,247,834.56
FCF Mediano:         R$ 1,251,122.89
Desvio Padrão:       R$ 312,455.78

FCF Mínimo:          R$ 298,567.23
FCF Máximo:          R$ 2,187,903.45

                 INTERVALOS DE CONFIANÇA                    
------------------------------------------------------------
5º Percentil (Pior cenário provável):  R$ 715,234.12
25º Percentil:                          R$ 1,033,567.89
75º Percentil:                          R$ 1,462,890.34
95º Percentil (Melhor cenário provável):R$ 1,789,456.78

                      PROBABILIDADES                        
------------------------------------------------------------
Probabilidade de FCF positivo:          99.8%
Probabilidade de FCF > R$ 1 milhão:     73.2%
Probabilidade de FCF > R$ 1,5 milhões:  28.4%

============================================================

📊 Implementação no Excel (Sem Programação)

Para quem prefere Excel, aqui está um passo a passo completo:

Passo 1: Configurar Parâmetros

Na planilha, crie uma área de parâmetros:

┌─────────────────────────┬──────────┬──────────────┬──────────┐
│ Variável                │ Mínimo   │ Mais Provável│ Máximo   │
├─────────────────────────┼──────────┼──────────────┼──────────┤
│ Receita (R$ milhões)    │    8,0   │     10,0     │   13,0   │
│ Margem EBITDA (%)       │   18%    │      22%     │   28%    │
│ CAPEX (% Receita)       │    5%    │       8%     │   12%    │
└─────────────────────────┴──────────┴──────────────┴──────────┘

Passo 2: Criar Fórmulas de Simulação

Em uma nova aba, crie colunas para cada simulação (1 a 1000):

Coluna A: Receita simulada

=NORM.INV(RAND(), 10000000, 1000000)

Ou para distribuição triangular:

=SE(RAND() < 0.5,
    8000000 + RAIZ(RAND() * (10000000-8000000)^2),
    13000000 - RAIZ((1-RAND()) * (13000000-10000000)^2))

Coluna B: Margem EBITDA

=NORM.INV(RAND(), 0.22, 0.03)

Coluna C: EBITDA

=A2 * B2

Coluna D: CAPEX

=A2 * NORM.INV(RAND(), 0.08, 0.02)

Coluna E: FCF (simplificado)

=C2 * (1-0.34) - D2

Passo 3: Copiar para 1000 Linhas

Copie as fórmulas para 1000 linhas. Cada vez que pressionar F9, novas simulações serão geradas.

Passo 4: Análise dos Resultados

Crie uma tabela de resumo:

Média:      =MÉDIA(E2:E1001)
Mediana:    =MED(E2:E1001)
Desvio:     =DESVPAD(E2:E1001)
P5:         =PERCENTIL(E2:E1001, 0.05)
P95:        =PERCENTIL(E2:E1001, 0.95)

Passo 5: Criar Gráfico Histograma

  1. Selecione os dados da coluna FCF (E2:E1001)
  2. Inserir → Gráfico → Histograma
  3. Ajuste os bins para ~30 intervalos

🎯 Caso 2: Análise de Risco de Portfólio

Vamos simular o retorno de um portfólio de investimentos considerando correlações entre ativos.

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

# ========================================
# PARÂMETROS DO PORTFÓLIO
# ========================================

# Definir ativos e seus pesos
ativos = ['Ações BR', 'Renda Fixa', 'FIIs', 'Internacional']
pesos = np.array([0.40, 0.30, 0.20, 0.10])  # Soma = 100%

# Retornos anuais esperados (%)
retornos_esperados = np.array([12.5, 8.0, 10.5, 15.0])

# Volatilidades anuais (desvio padrão) (%)
volatilidades = np.array([22.0, 4.0, 15.0, 28.0])

# Matriz de correlação entre ativos
correlacao = np.array([
    [1.00, 0.15, 0.45, 0.65],  # Ações BR
    [0.15, 1.00, 0.10, 0.05],  # Renda Fixa
    [0.45, 0.10, 1.00, 0.30],  # FIIs
    [0.65, 0.05, 0.30, 1.00]   # Internacional
])

# Investimento inicial
investimento_inicial = 100_000  # R$ 100 mil

# Horizonte de tempo
anos = 5

# Número de simulações
n_simulacoes = 10000

# ========================================
# CÁLCULO DA MATRIZ DE COVARIÂNCIA
# ========================================

# Converter volatilidades para matriz diagonal
D = np.diag(volatilidades)

# Calcular matriz de covariância: Σ = D * ρ * D
covariancia = D @ correlacao @ D

# ========================================
# SIMULAÇÃO DE MONTE CARLO
# ========================================

np.random.seed(42)

resultados_finais = []

for _ in range(n_simulacoes):
    # Gerar retornos correlacionados (distribuição normal multivariada)
    retornos_anuais = np.random.multivariate_normal(
        retornos_esperados, 
        covariancia
    )
    
    # Calcular retorno do portfólio (média ponderada)
    retorno_portfolio = np.dot(pesos, retornos_anuais)
    
    # Valor final após "anos" anos (capitalização composta)
    valor_final = investimento_inicial * (1 + retorno_portfolio/100) ** anos
    
    resultados_finais.append(valor_final)

resultados_finais = np.array(resultados_finais)

# ========================================
# ANÁLISE DE RISCO E RETORNO
# ========================================

print("=" * 70)
print("SIMULAÇÃO DE MONTE CARLO - ANÁLISE DE PORTFÓLIO")
print("=" * 70)
print(f"\nInvestimento Inicial: R$ {investimento_inicial:,.2f}")
print(f"Horizonte: {anos} anos")
print(f"Número de simulações: {n_simulacoes:,}")

print(f"\n{'COMPOSIÇÃO DO PORTFÓLIO':^70}")
print("-" * 70)
for ativo, peso, ret, vol in zip(ativos, pesos, retornos_esperados, volatilidades):
    print(f"{ativo:20} {peso*100:6.1f}%  |  Retorno: {ret:5.1f}%  |  Risco: {vol:5.1f}%")

print(f"\n{'PROJEÇÃO DE VALOR FINAL (após {anos} anos)':^70}")
print("-" * 70)
print(f"Valor Médio:       R$ {np.mean(resultados_finais):,.2f}")
print(f"Valor Mediano:     R$ {np.median(resultados_finais):,.2f}")
print(f"Desvio Padrão:     R$ {np.std(resultados_finais):,.2f}")

retorno_medio_anual = ((np.mean(resultados_finais) / investimento_inicial) ** (1/anos) - 1) * 100
print(f"\nRetorno Médio Anual Composto: {retorno_medio_anual:.2f}% a.a.")

# Cenários
p10 = np.percentile(resultados_finais, 10)
p50 = np.percentile(resultados_finais, 50)
p90 = np.percentile(resultados_finais, 90)

print(f"\n{'CENÁRIOS':^70}")
print("-" * 70)
print(f"Pessimista (P10):  R$ {p10:,.2f}  → Retorno: {((p10/investimento_inicial)**(1/anos)-1)*100:.2f}% a.a.")
print(f"Base (P50):        R$ {p50:,.2f}  → Retorno: {((p50/investimento_inicial)**(1/anos)-1)*100:.2f}% a.a.")
print(f"Otimista (P90):    R$ {p90:,.2f}  → Retorno: {((p90/investimento_inicial)**(1/anos)-1)*100:.2f}% a.a.")

# Value at Risk (VaR)
var_95 = investimento_inicial - np.percentile(resultados_finais, 5)
print(f"\n{'MÉTRICAS DE RISCO':^70}")
print("-" * 70)
print(f"Value at Risk (VaR 95%):       R$ {var_95:,.2f}")
print(f"  (Perda máxima esperada em 95% dos casos)")

prob_perda = np.sum(resultados_finais < investimento_inicial) / n_simulacoes * 100
prob_dobrar = np.sum(resultados_finais > investimento_inicial * 2) / n_simulacoes * 100

print(f"\nProbabilidade de perda:        {prob_perda:.2f}%")
print(f"Probabilidade de dobrar:       {prob_dobrar:.2f}%")

print("\n" + "=" * 70)

# ========================================
# VISUALIZAÇÃO
# ========================================

fig, axes = plt.subplots(2, 2, figsize=(14, 10))
fig.suptitle(f'Análise de Portfólio - Monte Carlo ({anos} anos)', 
             fontsize=16, fontweight='bold')

# 1. Histograma
axes[0, 0].hist(resultados_finais / 1000, bins=50, 
                edgecolor='black', alpha=0.7, color='forestgreen')
axes[0, 0].axvline(investimento_inicial / 1000, 
                   color='red', linestyle='--', linewidth=2, 
                   label=f'Investimento Inicial (R$ {investimento_inicial/1000:.0f}k)')
axes[0, 0].axvline(np.median(resultados_finais) / 1000, 
                   color='blue', linestyle='--', linewidth=2, label='Mediana')
axes[0, 0].set_xlabel('Valor Final (R$ mil)')
axes[0, 0].set_ylabel('Frequência')
axes[0, 0].set_title('Distribuição dos Resultados')
axes[0, 0].legend()
axes[0, 0].grid(True, alpha=0.3)

# 2. Distribuição de Retornos Anualizados
retornos_anualizados = ((resultados_finais / investimento_inicial) ** (1/anos) - 1) * 100
axes[0, 1].hist(retornos_anualizados, bins=50, 
                edgecolor='black', alpha=0.7, color='steelblue')
axes[0, 1].axvline(0, color='red', linestyle='--', linewidth=2, label='Break-even')
axes[0, 1].set_xlabel('Retorno Anualizado (%)')
axes[0, 1].set_ylabel('Frequência')
axes[0, 1].set_title('Distribuição de Retornos Anualizados')
axes[0, 1].legend()
axes[0, 1].grid(True, alpha=0.3)

# 3. Alocação do Portfólio
axes[1, 0].pie(pesos, labels=ativos, autopct='%1.1f%%', 
               startangle=90, colors=['#1f77b4', '#ff7f0e', '#2ca02c', '#d62728'])
axes[1, 0].set_title('Alocação de Ativos')

# 4. Cenários
cenarios_labels = ['Pessimista\n(P10)', 'Conservador\n(P25)', 
                   'Base\n(P50)', 'Otimista\n(P75)', 'Excelente\n(P90)']
cenarios_valores = [
    np.percentile(resultados_finais, 10) / 1000,
    np.percentile(resultados_finais, 25) / 1000,
    np.percentile(resultados_finais, 50) / 1000,
    np.percentile(resultados_finais, 75) / 1000,
    np.percentile(resultados_finais, 90) / 1000
]
cores_cenarios = ['#d32f2f', '#ff9800', '#2196f3', '#4caf50', '#8bc34a']

bars = axes[1, 1].bar(cenarios_labels, cenarios_valores, 
                      color=cores_cenarios, edgecolor='black', alpha=0.7)
axes[1, 1].axhline(investimento_inicial / 1000, 
                   color='red', linestyle='--', linewidth=2, alpha=0.5,
                   label='Investimento Inicial')
axes[1, 1].set_ylabel('Valor Final (R$ mil)')
axes[1, 1].set_title('Cenários de Valor Final')
axes[1, 1].legend()
axes[1, 1].grid(True, alpha=0.3, axis='y')

for bar, valor in zip(bars, cenarios_valores):
    height = bar.get_height()
    axes[1, 1].text(bar.get_x() + bar.get_width()/2., height,
                    f'R$ {valor:.1f}k',
                    ha='center', va='bottom', fontweight='bold', fontsize=9)

plt.tight_layout()
plt.savefig('monte_carlo_portfolio.png', dpi=300, bbox_inches='tight')
print("\n✅ Gráficos salvos como 'monte_carlo_portfolio.png'")

📋 Caso 3: Orçamento Empresarial com Incertezas

Um exemplo prático para controllers: simular o resultado operacional considerando múltiplas variáveis incertas.

import numpy as np
import pandas as pd

# ========================================
# CENÁRIO: Empresa de Varejo
# ========================================

n_sim = 5000
np.random.seed(42)

resultados = {
    'Receita': [],
    'CMV': [],
    'Despesas_Operacionais': [],
    'EBITDA': [],
    'Margem_EBITDA': []
}

for _ in range(n_sim):
    # Número de clientes (distribuição normal)
    clientes = max(0, np.random.normal(50000, 8000))
    
    # Ticket médio (distribuição lognormal)
    ticket_medio = np.random.lognormal(np.log(150), 0.3)
    
    # Receita
    receita = clientes * ticket_medio
    
    # CMV (% da receita - triangular)
    cmv_percent = np.random.triangular(0.55, 0.60, 0.68)
    cmv = receita * cmv_percent
    
    # Despesas Operacionais (fixas + variáveis)
    desp_fixas = np.random.normal(1_200_000, 150_000)
    desp_variaveis = receita * np.random.uniform(0.15, 0.22)
    despesas_op = max(0, desp_fixas + desp_variaveis)
    
    # EBITDA
    ebitda = receita - cmv - despesas_op
    margem = (ebitda / receita * 100) if receita > 0 else 0
    
    resultados['Receita'].append(receita)
    resultados['CMV'].append(cmv)
    resultados['Despesas_Operacionais'].append(despesas_op)
    resultados['EBITDA'].append(ebitda)
    resultados['Margem_EBITDA'].append(margem)

# Criar DataFrame
df_resultados = pd.DataFrame(resultados)

# ========================================
# RELATÓRIO PARA DIRETORIA
# ========================================

print("=" * 80)
print("SIMULAÇÃO ORÇAMENTÁRIA - MONTE CARLO")
print("Análise de Sensibilidade para Planejamento Anual")
print("=" * 80)

print(f"\n{'RECEITA BRUTA':^80}")
print("-" * 80)
print(f"Expectativa (Média):     R$ {df_resultados['Receita'].mean():,.2f}")
print(f"Cenário Conservador (P25): R$ {df_resultados['Receita'].quantile(0.25):,.2f}")
print(f"Cenário Base (Mediana):    R$ {df_resultados['Receita'].median():,.2f}")
print(f"Cenário Otimista (P75):    R$ {df_resultados['Receita'].quantile(0.75):,.2f}")

print(f"\n{'EBITDA':^80}")
print("-" * 80)
print(f"Expectativa (Média):     R$ {df_resultados['EBITDA'].mean():,.2f}")
print(f"Cenário Conservador (P25): R$ {df_resultados['EBITDA'].quantile(0.25):,.2f}")
print(f"Cenário Base (Mediana):    R$ {df_resultados['EBITDA'].median():,.2f}")
print(f"Cenário Otimista (P75):    R$ {df_resultados['EBITDA'].quantile(0.75):,.2f}")

print(f"\n{'MARGEM EBITDA':^80}")
print("-" * 80)
print(f"Expectativa (Média):     {df_resultados['Margem_EBITDA'].mean():.2f}%")
print(f"Cenário Conservador (P25): {df_resultados['Margem_EBITDA'].quantile(0.25):.2f}%")
print(f"Cenário Base (Mediana):    {df_resultados['Margem_EBITDA'].median():.2f}%")
print(f"Cenário Otimista (P75):    {df_resultados['Margem_EBITDA'].quantile(0.75):.2f}%")

# Probabilidades de atingir metas
meta_receita = 8_000_000
meta_ebitda = 1_000_000

prob_receita = (df_resultados['Receita'] >= meta_receita).sum() / n_sim * 100
prob_ebitda = (df_resultados['EBITDA'] >= meta_ebitda).sum() / n_sim * 100

print(f"\n{'PROBABILIDADE DE ATINGIR METAS':^80}")
print("-" * 80)
print(f"Meta de Receita (R$ {meta_receita:,.2f}):  {prob_receita:.1f}%")
print(f"Meta de EBITDA (R$ {meta_ebitda:,.2f}):   {prob_ebitda:.1f}%")

print("\n" + "=" * 80)

# Exportar para Excel
df_resultados.to_excel('simulacao_orcamento.xlsx', index=False)
print("\n✅ Resultados exportados para 'simulacao_orcamento.xlsx'")

🎓 Quando Usar Monte Carlo vs. Análise de Sensibilidade?

CritérioAnálise de SensibilidadeMonte Carlo
ComplexidadeUma variável por vezMúltiplas variáveis simultâneas
CorrelaçõesNão consideraConsidera correlações entre variáveis
ResultadosImpacto linearDistribuição probabilística completa
Interpretação“Se X aumentar 10%, Y muda Z%”“Há 75% de chance de Y ficar entre A e B”
UsoAnálises rápidas, apresentaçõesDecisões estratégicas, gestão de risco

Regra prática: Use Monte Carlo quando:

  • ✅ Há múltiplas fontes de incerteza
  • ✅ Precisa quantificar probabilidades
  • ✅ Decisão envolve risco significativo (capex, M&A, novo produto)
  • ✅ Precisa demonstrar confiança estatística para stakeholders

💡 Boas Práticas e Armadilhas

✅ Faça:

  1. Valide as distribuições – Use dados históricos sempre que possível
  2. Documente premissas – Deixe claro de onde vieram os parâmetros
  3. Rode simulações suficientes – Mínimo 1.000, ideal 10.000+
  4. Teste sensibilidade – Varie os parâmetros e veja impacto
  5. Comunique em probabilidades – “70% de chance” é mais útil que “cenário base”

❌ Evite:

  1. Garbage in, garbage out – Distribuições mal escolhidas geram resultados inúteis
  2. Ignorar correlações – Vendas e custos geralmente se movem juntos
  3. Precisão falsa – Monte Carlo não elimina incerteza, apenas a quantifica
  4. Excesso de variáveis – Foque nas 3-5 variáveis de maior impacto
  5. Confundir média com mediana – Em distribuições assimétricas, são diferentes

🚀 Próximos Passos

Agora que você domina Monte Carlo, experimente:

  1. Integrar com modelos de valuation (Fluxo de Caixa Descontado probabilístico)
  2. Análise de opções reais (valor da flexibilidade gerencial)
  3. Otimização de portfólio (combinado com algoritmos genéticos)
  4. Simulação de processos estocásticos (Movimento Browniano Geométrico para preços de ações)

📚 Conclusão

A Simulação de Monte Carlo transforma a forma como profissionais de controladoria e finanças lidam com a incerteza. Em vez de um único número no orçamento (“vamos fazer R$ 10 milhões”), você agora pode afirmar com confiança:

“Há 68% de probabilidade de nossa receita ficar entre R$ 9,2M e R$ 10,8M, e apenas 5% de chance de cair abaixo de R$ 8,5M. Dado esse perfil de risco, recomendamos reservar R$ 500k de capital de contingência.”

Essa é a diferença entre achismo e gestão baseada em dados.


Sobre o Autor:

Prof. Ronald Fonseca é professor da Universidade Federal do Ceará (UFC) e profissional de Controladoria, especialista em análise quantitativa aplicada a finanças. Ministra disciplinas de Estatística, Matemática Financeira e Análise de Dados para cursos de Administração, Contabilidade e Ciências Atuariais.

🔗 Conecte-se: LinkedIn | Instagram | YouTube


Gostou do artigo? Compartilhe com sua rede e deixe nos comentários: que tipo de simulação você gostaria de implementar na sua empresa?

Baixe o código completo: GitHub – Monte Carlo Finanças

#MonteCarloSimulation #Controladoria #AnáliseDeDados #FinançasQuantitativas #GestãoDeRisco #Python #Excel

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *